iT邦幫忙

2025 iThome 鐵人賽

DAY 12
1
DevOps

賢者大叔的容器修煉手札系列 第 12

DNS 服務發現 - 微服務的電話簿 📞

  • 分享至 

  • xImage
  •  

賢者大叔的容器修煉手札系列 第 12 篇

DNS 服務發現 - 微服務的電話簿 📞

昨天我們學會了 Service 這個「總服務台」,讓 Pod 之間能夠穩定通訊。但各位想想,如果每次要找服務都得記住 IP 地址,那不是很麻煩嗎?就像打電話要背電話號碼一樣!今天我們要學習 Kubernetes 的 DNS 服務發現,它就像是微服務世界的「電話簿」!
想像一下,您在一家大型購物中心工作,每次要聯絡其他部門都要記住分機號碼:財務部 1001、人事部 1002、IT部 1003...這樣很容易搞混對吧?如果有個「內部電話簿」,只要說「幫我轉財務部」就能自動接通,那該多方便!這就是 DNS 服務發現要解決的問題!

今日學習目標 🎯

✅ 理解 Kubernetes DNS 自動服務發現機制

✅ 掌握服務自動註冊與下線流程

✅ 學會服務間 DNS 通訊設定與查詢

✅ 實作跨命名空間的服務發現

DNS 服務發現的核心概念 🧠

什麼是服務發現?

服務發現 (Service Discovery) 就是讓應用程式能夠自動找到並連接到其他服務的機制。

傳統方式 😰:需要明確知道 IP
curl http://10.96.111.53:80/api/payment

DNS 方式 😍:
curl http://payment-service/api/payment

Kubernetes DNS 架構 🏗️

https://ithelp.ithome.com.tw/upload/images/20250826/20104930vyDogX8Qyy.png

服務自動註冊機制 📝

搭配 Day 6 的健康探針

服務註冊的完整流程
https://ithelp.ithome.com.tw/upload/images/20250827/20104930Jf3nJuqVlF.png

實際演示:觀察自動註冊過程

# 1. 準備監控 Endpoints 變化
kubectl get endpoints -n backend --watch &

# 2. 創建新的服務部署
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-service
  namespace: backend
spec:
  replicas: 0  # 先設為 0,觀察註冊過程
  selector:
    matchLabels:
      app: demo-service
  template:
    metadata:
      labels:
        app: demo-service
    spec:
      containers:
      - name: demo
        image: nginx:alpine
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3
---
apiVersion: v1
kind: Service
metadata:
  name: demo-service
  namespace: backend
spec:
  selector:
    app: demo-service
  ports:
  - port: 80
    targetPort: 80
EOF

# 3. 觀察初始狀態(無 Endpoints)
kubectl get endpoints demo-service -n backend
# 輸出: NAME           ENDPOINTS   AGE
#       demo-service   <none>      10s

# 4. 擴展到 2 個實例,觀察自動註冊
kubectl scale deployment demo-service -n backend --replicas=2

# 5. 即時觀察註冊過程
kubectl get endpoints demo-service -n backend --watch
# 你會看到:
# demo-service   <none>                    30s
# demo-service   10.244.1.50:80           45s  # 第一個 Pod 註冊
# demo-service   10.244.1.50:80,10.244.2.51:80   60s  # 第二個 Pod 註冊

服務下線的自動發現機制 🔻

搭配 Day 6 的健康探針
健康檢查和自動移除

https://ithelp.ithome.com.tw/upload/images/20250827/20104930wDJdUUd0Zh.png

實際測試:觀察服務自動下線

# 1. 部署測試服務
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: health-test
  namespace: backend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: health-test
  template:
    metadata:
      labels:
        app: health-test
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 5
          failureThreshold: 2  # 🎯 失敗 2 次就下線
        livenessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 10
          failureThreshold: 3
---
apiVersion: v1
kind: Service
metadata:
  name: health-test-service
  namespace: backend
spec:
  selector:
    app: health-test
  ports:
  - port: 80
    targetPort: 80
EOF

# 2. 觀察初始狀態
kubectl get pods -n backend -l app=health-test
kubectl get endpoints health-test-service -n backend

# 輸出示例:
# NAME                          READY   STATUS    RESTARTS   AGE
# health-test-7d4b8f9c8-abc12   1/1     Running   0          30s
# health-test-7d4b8f9c8-def34   1/1     Running   0          30s
# health-test-7d4b8f9c8-ghi56   1/1     Running   0          30s
#
# NAME                  ENDPOINTS                                    AGE
# health-test-service   10.244.1.20:80,10.244.2.21:80,10.244.3.22:80   30s

# 3. 開始監控 Endpoints 變化
kubectl get endpoints health-test-service -n backend --watch &

# 4. 模擬服務故障 - 停止其中一個 Pod 的 nginx
POD_NAME=$(kubectl get pods -n backend -l app=health-test -o jsonpath='{.items[0].metadata.name}')
echo "模擬 Pod $POD_NAME 故障..."

kubectl exec -n backend $POD_NAME -- sh -c "nginx -s stop"

# 5. 觀察自動下線過程
# 你會看到類似輸出:
# health-test-service   10.244.1.20:80,10.244.2.21:80,10.244.3.22:80   1m
# health-test-service   10.244.2.21:80,10.244.3.22:80                   1m  # 故障 Pod 自動移除

# 6. 驗證 Pod 狀態
kubectl get pods -n backend -l app=health-test
# 你會看到其中一個 Pod 的 READY 狀態變為 0/1

# 7. 測試 DNS 解析(故障 Pod 不再出現)
kubectl run test-client --rm -i --tty --image=curlimages/curl -n backend -- sh
/ # nslookup health-test-service
# 只會返回健康的 Pod IP

服務間 DNS 通訊設定 🌐

https://ithelp.ithome.com.tw/upload/images/20250827/20104930XTOHdovwkb.png

DNS 命名規範與解析層級

DNS 解析規則詳解 📋

  1. DNS 命名規範
    Kubernetes 中的 DNS 名稱遵循以下格式:
<service-name>.<namespace>.<service-type>.<cluster-domain>

例如︰

payment-service.ecommerce.svc.cluster.local
    ↓           ↓         ↓        ↓
 服務名稱    命名空間   服務類型  cluster 域名

🎯 DNS 格式記憶法:
「服務.空間.類型.域名」
就像地址:「姓名.社區.建築類型.城市」

  1. DNS 解析層級
# 同命名空間內 - 最簡短,直接服務名稱
curl http://payment-service/api/v1/pay

# 跨命名空間 - 指定命名空間
curl http://payment-service.ecommerce/api/v1/pay

# 完整服務類型 - 明確指定
curl http://payment-service.ecommerce.svc/api/v1/pay

# 完整 FQDN - 最完整
curl http://payment-service.ecommerce.svc.cluster.local/api/v1/pay
  1. DNS 查詢順序

當 Pod 查詢 payment-service 時,DNS 會按以下順序嘗試:

1. payment-service.current-namespace.svc.cluster.local
2. payment-service.svc.cluster.local
3. payment-service.cluster.local
4. payment-service (如果配置了搜尋域)

實際配置:跨命名空間服務通訊

演示跨命名空間通訊。
API Gateway 在 frontend 命名空間,要訪問 backend 和 data 命名空間的服務。
必須使用完整的 DNS 名稱才能跨命名空間解析。

# microservices-communication.yaml
---
# 前端命名空間
apiVersion: v1
kind: Namespace
metadata:
  name: frontend
---
# API Gateway部署
# 前端的 nginx 需要將請求轉發到後端的不同微服務
# 使用 DNS 名稱而非 IP,讓配置更穩定可靠
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api-gateway
  namespace: frontend
spec:
  replicas: 2
  selector:
    matchLabels:
      app: api-gateway
  template:
    metadata:
      labels:
        app: api-gateway
    spec:
      containers:
      - name: gateway
        image: nginx:alpine
        ports:
        - containerPort: 80
        env:
        # 🎯 跨命名空間 DNS 配置
        - name: USER_SERVICE_URL
          value: "http://user-service.backend.svc.cluster.local"
        - name: PRODUCT_SERVICE_URL
          value: "http://product-service.backend.svc.cluster.local"
        - name: ORDER_SERVICE_URL
          value: "http://order-service.backend.svc.cluster.local"
        # 🎯 資料庫服務 DNS 配置
        - name: POSTGRES_HOST
          value: "postgres-service.data.svc.cluster.local"
        - name: REDIS_HOST
          value: "redis-service.data.svc.cluster.local"
        volumeMounts:
        - name: nginx-config
          mountPath: /etc/nginx/conf.d
      volumes:
      - name: nginx-config
        configMap:
          name: gateway-config
---
# API Gateway 配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: gateway-config
  namespace: frontend
data:
  default.conf: |
    upstream user_backend {
        # 🎯 使用 DNS 名稱,自動 load balancing
        server user-service.backend.svc.cluster.local:80;
    }
    
    upstream product_backend {
        server product-service.backend.svc.cluster.local:80;
    }
    
    upstream order_backend {
        server order-service.backend.svc.cluster.local:80;
    }
    
    server {
        listen 80;
        
        # 用戶服務路由
        location /api/users/ {
            proxy_pass http://user_backend/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
        
        # 商品服務路由
        location /api/products/ {
            proxy_pass http://product_backend/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
        
        # 訂單服務路由
        location /api/orders/ {
            proxy_pass http://order_backend/;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
        
        # 健康檢查
        location /health {
            return 200 "OK";
            add_header Content-Type text/plain;
        }
    }
---
apiVersion: v1
kind: Service
metadata:
  name: api-gateway-service
  namespace: frontend
spec:
  type: LoadBalancer  # 對外暴露
  selector:
    app: api-gateway
  ports:
  - port: 80
    targetPort: 80

DNS 查詢與測試工具

# 1. 部署 DNS 測試工具
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
 name: dns-test-tool
 namespace: frontend
spec:
 replicas: 1
 selector:
   matchLabels:
     app: dns-test-tool
 template:
   metadata:
     labels:
       app: dns-test-tool
   spec:
     containers:
     - name: dns-tool
       image: tutum/dnsutils
       command: ["sleep", "3600"]
EOF

# 2. 進入測試 Pod
kubectl exec -it -n frontend deployment/dns-test-tool -- bash

# 3. 測試各種 DNS 解析層級
root@dns-test-tool:/# nslookup api-gateway-service
# 同命名空間解析
Server:		10.96.0.10
Address:	10.96.0.10#53
Name:	api-gateway-service.frontend.svc.cluster.local
Address: 10.96.50.10

root@dns-test-tool:/# nslookup user-service.backend
# 跨命名空間解析
Server:		10.96.0.10
Address:	10.96.0.10#53
Name:	user-service.backend.svc.cluster.local
Address: 10.96.100.10

root@dns-test-tool:/# nslookup postgres-service.data.svc.cluster.local
# 完整 FQDN 解析
Server:		10.96.0.10
Address:	10.96.0.10#53
Name:	postgres-service.data.svc.cluster.local
Address: 10.96.20.10

# 4. 測試實際 HTTP 連接
root@dns-test-tool:/# curl -I http://user-service.backend/
HTTP/1.1 200 OK
Server: nginx/1.21.5

root@dns-test-tool:/# curl -I http://product-service.backend.svc.cluster.local/
HTTP/1.1 200 OK
Server: nginx/1.21.5

# 5. 測試 DNS 解析時間
root@dns-test-tool:/# time nslookup user-service.backend
# 觀察解析時間

# 6. 查看 DNS 配置
root@dns-test-tool:/# cat /etc/resolv.conf
nameserver 10.96.0.10
search frontend.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

總結 服務發現完整生命週期 🔄

關鍵流程回顧
1. 自動註冊 ⬆️

  • Pod 啟動 → 健康檢查通過 → 自動加入 Endpoints
  • 時間:通常 10-30 秒完成註冊

2. 負載分散 ⚖️

  • Service 在所有健康 Pod 間自動分散流量
  • DNS 返回多個 IP,客戶端自動選擇

3. 健康監控 💓

  • 持續健康檢查,即時發現故障
  • readinessProbe 決定是否接收流量

4. 自動下線 ⬇️

  • 健康檢查失敗 → 自動從 Endpoints 移除
  • 時間:通常 15-30 秒完成下線

5. DNS 更新 🔄

  • CoreDNS 即時反映 Endpoints 變化
  • 新流量不再路由到故障 Pod

✅ 使用明確的 DNS 名稱:跨命名空間時使用完整格式

✅ 配置適當的健康檢查:快速發現和處理故障

✅ 監控服務發現狀態:建立監控和告警機制

✅ 優化 DNS 配置:減少查詢延遲

✅ 測試故障場景:驗證自動下線機制

這就是 Kubernetes DNS 服務發現的完整機制!它讓微服務之間的通訊變得簡單可靠,就像有了一本永遠更新的「電話簿」📞

https://ithelp.ithome.com.tw/upload/images/20250827/20104930RSujw8MmnP.png


上一篇
Service 基礎 - Pod 間溝通的穩定橋樑 🌉
下一篇
StatefulSet - 有狀態應用的專屬管家 👑
系列文
賢者大叔的容器修煉手札17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言