跳至主要內容

Kubernetes Service 網路概念完整解析

Kubernetes Service 網路概念完整解析

在 Kubernetes 中,Pod 是短暫的——它們會因為節點故障、滾動更新或自動擴縮而被刪除並重建,每次重建後 IP 位址都會改變。這讓服務發現(Service Discovery)成為一個必須解決的問題:其他服務怎麼知道要連到哪個 IP?

這就是 Kubernetes Service 存在的原因。本文深入解析 Service 的各種類型、DNS 解析機制,以及 kube-proxy 的運作原理。

Service 的本質

Kubernetes Service 是一個抽象層,定義了一組 Pod 的邏輯集合,以及存取這些 Pod 的策略。Service 透過 Label Selector 選取目標 Pod,並提供一個穩定的虛擬 IP(ClusterIP)。

# 基本 Service 定義
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
  namespace: production
spec:
  selector:
    app: my-app           # 選取帶有此標籤的 Pod
    version: stable
  ports:
    - protocol: TCP
      port: 80            # Service 暴露的端口
      targetPort: 3000    # Pod 實際監聽的端口
  type: ClusterIP         # Service 類型

Service 的四種類型

1. ClusterIP(預設)

ClusterIP 只在叢集內部可存取,分配一個虛擬 IP:

spec:
  type: ClusterIP
  clusterIP: 10.96.100.50  # 可指定,或讓系統自動分配
  ports:
    - port: 80
      targetPort: 8080

同一叢集中的任何 Pod 都可以透過 my-app-service.production.svc.cluster.localmy-app-service.production 存取此 Service。

2. NodePort

在每個節點上開放一個端口(30000-32767),讓叢集外部可存取:

spec:
  type: NodePort
  selector:
    app: my-app
  ports:
    - port: 80          # ClusterIP 端口
      targetPort: 8080  # Pod 端口
      nodePort: 30080   # 節點端口(可選,不指定則自動分配)

存取方式:http://<任意節點IP>:30080

3. LoadBalancer

在雲端環境中自動建立外部負載均衡器:

spec:
  type: LoadBalancer
  selector:
    app: web-frontend
  ports:
    - port: 443
      targetPort: 8443
      protocol: TCP

雲端供應商(AWS、GCP、Azure)會自動配置 ELB/GLB 等負載均衡器,並分配一個外部 IP。

4. ExternalName

將 Service 映射到外部 DNS 名稱,不涉及實際的 Pod 選取:

apiVersion: v1
kind: Service
metadata:
  name: external-database
  namespace: production
spec:
  type: ExternalName
  externalName: db.example.com

這讓叢集內的應用程式可以用統一的方式存取外部服務,需要切換外部端點時只需更改 Service,不需更改應用程式設定。

Headless Service

有時候你需要直接存取各個 Pod,而不是透過負載均衡。設定 clusterIP: None 可以建立 Headless Service:

apiVersion: v1
kind: Service
metadata:
  name: my-statefulset-service
spec:
  clusterIP: None
  selector:
    app: my-statefulset
  ports:
    - port: 5432
      targetPort: 5432

DNS 查詢 Headless Service 時,會直接回傳所有 Pod 的 IP 清單,而不是 ClusterIP。這對 StatefulSet(如資料庫叢集)特別有用。

Kubernetes DNS

CoreDNS 是 Kubernetes 的預設 DNS 伺服器,負責解析 Service 和 Pod 的名稱。

DNS 命名規則

# 完整格式
<service-name>.<namespace>.svc.<cluster-domain>

# 範例
my-app-service.production.svc.cluster.local

# 同 namespace 內可以省略
my-app-service
my-app-service.production

驗證 DNS 解析

# 在 Pod 內執行 DNS 查詢
kubectl exec -it debug-pod -- nslookup my-app-service.production

# 使用 dig
kubectl exec -it debug-pod -- dig my-app-service.production.svc.cluster.local

# 查看 DNS 設定
kubectl exec -it debug-pod -- cat /etc/resolv.conf
# 輸出:
# nameserver 10.96.0.10
# search production.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

Endpoints 與 EndpointSlices

Service 的後端實際上是由 Endpoints 物件管理的:

# 查看 Service 對應的 Endpoints
kubectl get endpoints my-app-service -n production

# 輸出
NAME             ENDPOINTS                          AGE
my-app-service   10.244.1.5:8080,10.244.2.3:8080   5d

當 Pod 的 Ready 狀態改變時,Endpoints 會自動更新。這就是為什麼健康檢查(Readiness Probe)如此重要——只有 Ready 的 Pod 才會出現在 Endpoints 中,才能接收流量。

kube-proxy 的運作原理

kube-proxy 在每個節點上運行,負責實現 Service 的網路規則。它有三種模式:

iptables 模式(預設)

用戶端請求 → ClusterIP:Port
     ↓
iptables DNAT 規則(隨機選擇後端 Pod)
     ↓
目標 Pod IP:Port

kube-proxy 監聽 Kubernetes API,當 Service 或 Endpoints 變更時,更新每個節點上的 iptables 規則。

IPVS 模式(高效能)

對於大型叢集,IPVS 模式效能更好:

# 啟用 IPVS 模式
kubectl edit configmap kube-proxy -n kube-system
# 修改 mode: "ipvs"

IPVS 使用雜湊表而非線性掃描,在大量 Service 和 Endpoints 的情況下效能大幅優於 iptables。

Ingress:七層負載均衡

Ingress 是管理外部 HTTP/HTTPS 流量的資源,建立在 Service 之上:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: app-tls
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 80
          - path: /
            pathType: Prefix
            backend:
              service:
                name: frontend-service
                port:
                  number: 80

常見問題排查

# 1. 確認 Service 存在且設定正確
kubectl describe service my-app-service -n production

# 2. 確認 Endpoints 不為空
kubectl get endpoints my-app-service -n production

# 3. 確認 Pod 標籤符合 Selector
kubectl get pods -n production --show-labels
kubectl get pods -n production -l app=my-app

# 4. 確認 Pod 的 Readiness Probe 通過
kubectl describe pod <pod-name> -n production

# 5. 在 Pod 內測試連線
kubectl exec -it debug-pod -n production -- curl http://my-app-service/health

總結

Kubernetes Service 是叢集內部網路的核心抽象。理解 ClusterIP、NodePort、LoadBalancer 和 Headless Service 的差異,掌握 DNS 解析機制和 kube-proxy 的工作原理,是部署和維護 Kubernetes 應用的必備知識。配合 Ingress 處理外部流量,你就擁有了完整的 Kubernetes 網路工具箱。

分享這篇文章