為什麼要學 DNS?
Service 篇我們說「程式裡寫 mysql-svc:3306 就能連到 MySQL」,但到底是誰在做這件事? mysql-svc 又不是 IP,K8s 怎麼解析的?
答案是 CoreDNS — K8s 內建的 DNS 服務。
這篇要回答兩個問題:
為什麼不直接用 ClusterIP 的 IP?
技術上沒人擋你。kubectl get svc 看到 IP 是 10.43.0.150,你寫死在程式裡也能跑。
但:
- ClusterIP 雖然比 Pod IP 穩,Service 重建後會變(你刪一次
mysql-svc重建,新 IP 就變了) - 一個叢集裡 30 個微服務 = 30 個 ClusterIP,沒人記得起來
- 換 namespace、換叢集、跨環境部署,IP 全變
K8s 的「通訊錄」就是 CoreDNS。
CoreDNS 是什麼?
K8s 叢集裡內建的 DNS 服務,跑在 kube-system namespace。
$ kubectl get pods -n kube-system | grep coredns
coredns-77ccd57875-abc12 1/1 Running
它做的事很單純:
每建一個 Service,CoreDNS 自動註冊一筆 DNS 記錄。
你建一個叫 nginx-svc 的 Service → CoreDNS 記住「nginx-svc 對應 10.43.0.150」。任何 Pod 查 nginx-svc,CoreDNS 就回那個 IP。
Pod 怎麼知道要找 CoreDNS? K8s 在每個 Pod 啟動時自動寫好 /etc/resolv.conf:
$ kubectl exec -it <pod> -- cat /etc/resolv.conf
search default.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.43.0.10 # ← CoreDNS 的 ClusterIP
你完全不用設定,curl / wget / nslookup 都會自動走 CoreDNS。
DNS 名字的三種寫法
| 寫法 | 什麼時候用 |
|---|---|
nginx-svc | 同一個 namespace 內(最常用) |
nginx-svc.dev | 跨 namespace |
nginx-svc.dev.svc.cluster.local | 完整 FQDN |
nginx-svc . dev . svc . cluster.local
↑ ↑ ↑ ↑
Service ns 固定 叢集網域
/etc/resolv.conf 裡的 search 設定會幫你補後綴。所以同 namespace 用短名,K8s 自動補上 .default.svc.cluster.local;跨 namespace 至少要寫到 namespace。
Namespace 是什麼?
Namespace = 叢集裡的「資料夾」,用來分類 / 隔離資源。
最常見用途:隔離環境。
┌──── default ────┐ ┌──── dev ────┐ ┌──── prod ────┐
│ nginx-svc │ │ nginx-svc │ │ nginx-svc │
│ (你的測試) │ │ (1.26) │ │ (1.27) │
└────────────────┘ └─────────────┘ └──────────────┘
三個 namespace 都有 nginx-svc,互不衝突。如果都擠在 default,K8s 會擋你 — 同 namespace 不允許同名 Service。
K8s 預設四個 namespace:
| Namespace | 用途 |
|---|---|
default | 你沒指定就在這 |
kube-system | K8s 系統元件(CoreDNS、kube-proxy) |
kube-public | 公開資源(很少用) |
kube-node-lease | 節點心跳(不用管) |
nginx-svc.dev.svc.cluster.local 連到 dev 的服務。要做網路隔離得用 NetworkPolicy。
用 nslookup 看穿 CoreDNS
開一個臨時 busybox Pod 來查:
$ kubectl run dns-test --image=busybox:1.36 --rm -it --restart=Never -- sh
/ # nslookup nginx-svc
Server: 10.43.0.10
Address: 10.43.0.10:53
Name: nginx-svc.default.svc.cluster.local
Address: 10.43.0.150
兩個重點:
Server: 10.43.0.10→ 那是 CoreDNS 的 ClusterIP- 你問
nginx-svc,CoreDNS 回的是完整 FQDNnginx-svc.default.svc.cluster.local對應10.43.0.150
/ # wget -qO- http://nginx-svc
<h1>Welcome to nginx!</h1>
# 完整 FQDN 也行
/ # wget -qO- http://nginx-svc.default.svc.cluster.local
<h1>Welcome to nginx!</h1>
兩個寫法指向同一個 Service。
跨 Namespace 實作
# 1. 建 dev namespace
$ kubectl create namespace dev
# 2. 在 dev 部署 nginx
$ kubectl create deployment nginx-dev --image=nginx:1.27 -n dev
$ kubectl expose deployment nginx-dev --port=80 -n dev
# 3. 從 default 跨 namespace 連線
$ kubectl run cross-test --image=busybox:1.36 --rm -it --restart=Never \
-- wget -qO- http://nginx-dev.dev.svc.cluster.local
<h1>Welcome to nginx!</h1>
關鍵:busybox 在 default,要連 dev 的服務,必須帶上 namespace:nginx-dev.dev(或完整 FQDN)。
kubectl 操作 Namespace
# 看所有 namespace
$ kubectl get namespaces
# 看特定 namespace 的所有資源
$ kubectl get all -n dev
# 看所有 namespace 的 Pod
$ kubectl get pods -A
常見坑:跑 kubectl 忘記加 -n dev,資源全跑到 default 去。
排錯:kubectl get pods -A | grep ,看資源到底跑去哪了。
對照 Docker
| Docker | Kubernetes |
|---|---|
Compose 服務名(mysql) | Service name(mysql-svc) |
| 不同 Compose project = 不同 network | 不同 namespace |
| 內建 DNS(compose 版) | CoreDNS(叢集版) |
docker network 內。K8s 的 CoreDNS 是叢集級的,所有 namespace 共用同一套 DNS 解析機制。
重點整理
- 用名字不用 IP — Service 重建 IP 會變、人腦記不住
- CoreDNS 跑在
kube-system,每建一個 Service 自動註冊 DNS - 三種寫法:
name/name.ns/name.ns.svc.cluster.local - 同 ns 用短名,跨 ns 至少帶上 namespace
- Namespace 是邏輯隔離,不是網路隔離
下一步
到目前為止學的都是「我要 N 個 Pod」。但有些情境是「每台 Node 都要一個」(日誌收集 agent、監控 agent),有些是「每天凌晨備份一次」(定時任務)。
這就要用 DaemonSet 與 CronJob。