返回文章列表

Kubernetes服務探索與網路策略詳解

本文探討 Kubernetes 服務探索與網路策略的運作機制,包含 kube-proxy 如何管理 Service 虛擬 IP 與操作 iptables 規則、DNS 與環境變數在服務探索中的應用、NetworkPolicy 的設定方式及服務網格的應用場景。透過實際案例與圖表解析,幫助讀者理解 Kubernetes

容器技術 網路管理

Kubernetes 服務提供穩定的網路介面,讓後端 Pod 可被統一存取,並非與 Deployment 一對一繫結,而是透過標籤選擇器動態連線 Pod,支援藍綠佈署等策略。kube-proxy 透過操作 iptables 規則管理 Service 虛擬 IP 連線,將流量導向後端 Pod。服務探索方面,Kubernetes 主要透過 DNS 解析 Service 名稱,並利用 kube-proxy 設定的 iptables 規則將請求轉發至後端 Pod。此外,環境變數也提供另一種服務探索方式,Kubernetes 會自動注入 Service 相關的環境變數供 Pod 使用。NetworkPolicy 則可控制 Pod 間的網路流量,透過 Ingress 和 Egress 規則限制 Pod 的網路存取許可權,實作微隔離。服務網格則進一步增強了網路管理能力,提供流量管理、可觀察性和安全性等功能,簡化微服務環境中的網路複雜性。

Kubernetes 服務探索與 kube-proxy 的運作原理

在 Kubernetes 叢集中,服務(Service)資源的實作提供了穩定的網路介面,讓後端的多個 Pod 可以被統一管理與存取。許多使用者剛開始接觸 Kubernetes 時,通常會以為 Deployment 與 Service 之間是一對一的關係,但事實上,由於 Service 是透過標籤選擇器(label selector)與 Pod 相連線,因此任何具備相應標籤的 Pod 都會被視為該 Service 的端點。這種設計使得多個 Pod 可以動態地成為某個 Service 的後端,甚至支援像是藍綠佈署(blue/green deployment)或金絲雀發布(canary rollout)等進階佈署策略。

kube-proxy 的運作機制

在 Kubernetes 中,讓 Service 能夠正常運作的核心元件是 kube-proxy。它通常以特權容器(privileged container)的形式執行,負責管理 Service 虛擬 IP 的連線。kube-proxy 最初是以使用者空間代理(userspace proxy)的形式實作,但目前最常見的實作方式是直接操作每台節點上的 iptables 規則。這些 iptables 規則會將目標為 Service IP 的流量重新導向到後端的端點 IP。

檢視 kube-proxy 如何操作 iptables 規則

假設我們已經在叢集中定義了一個名為 kubernetes-dashboard 的 Service,我們可以透過以下指令檢視其相關設定:

$ kubectl get svc -n kube-system kubernetes-dashboard
NAME                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes-dashboard   ClusterIP   10.104.154.139   <none>        443/TCP   40d

$ kubectl get ep -n kube-system kubernetes-dashboard
NAME                  ENDPOINTS                            AGE
kubernetes-dashboard   192.168.63.200:8443,192.168.63.201:8443   40d

接著,我們可以檢視 kube-proxy 在節點上設定的 iptables 規則:

$ sudo iptables-save | grep KUBE | grep "kubernetes-dashboard"
-A KUBE-SEP-3HWS5OGCGRHMJ23K -s 192.168.63.201/32 -m comment --comment "kube-system/kubernetes-dashboard:" -j KUBE-MARK-MASQ
-A KUBE-SEP-3HWS5OGCGRHMJ23K -p tcp -m comment --comment "kube-system/kubernetes-dashboard:" -m tcp -j DNAT --to-destination 192.168.63.201:8443
-A KUBE-SEP-XWHZMKM53W55IFOX -s 192.168.63.200/32 -m comment --comment "kube-system/kubernetes-dashboard:" -j KUBE-MARK-MASQ
-A KUBE-SEP-XWHZMKM53W55IFOX -p tcp -m comment --comment "kube-system/kubernetes-dashboard:" -m tcp -j DNAT --to-destination 192.168.63.200:8443
-A KUBE-SERVICES ! -s 192.168.0.0/16 -d 10.104.154.139/32 -p tcp -m comment --comment "kube-system/kubernetes-dashboard: cluster IP" -m tcp --dport 443 -j KUBE-MARK-MASQ
-A KUBE-SERVICES -d 10.104.154.139/32 -p tcp -m comment --comment "kube-system/kubernetes-dashboard: cluster IP" -m tcp --dport 443 -j KUBE-SVC-XGLOHA7QRQ3V22RZ
-A KUBE-SVC-XGLOHA7QRQ3V22RZ -m comment --comment "kube-system/kubernetes-dashboard:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-XWHZMKM53W55IFOX
-A KUBE-SVC-XGLOHA7QRQ3V22RZ -m comment --comment "kube-system/kubernetes-dashboard:" -j KUBE-SEP-3HWS5OGCGRHMJ23K

iptables 規則解析

這些 iptables 規則的作用是將目標為 kubernetes-dashboard Service 的 ClusterIP(10.104.154.139)的流量,隨機導向到後端兩個 Pod 端點(192.168.63.200:8443 和 192.168.63.201:8443)。這樣一來,每個節點上的 Pod 都可以透過 kube-proxy 組態的 iptables 規則來存取定義好的 Service。

#### 內容解密:

  1. iptables規則的作用:這些規則是由kube-proxy動態生成的,用於實作Service的負載平衡。
  2. DNAT的作用:DNAT(Destination Network Address Translation)用於修改封包的目的IP地址和埠,將流量導向後端Pod。
  3. 隨機分配流量:透過statistic模組的random模式,將流量隨機分配到不同的後端Pod,實作負載平衡。
  4. KUBE-MARK-MASQ的作用:該規則用於標記需要進行SNAT(Source Network Address Translation)的封包,以確保回包能夠正確傳回。

Kubernetes 中的服務探索

在動態排程的環境中,服務探索(Service Discovery)是至關重要的。Kubernetes 中最常見的服務探索方式是透過 DNS。Kubernetes 本身並不包含 DNS 控制器,但社群維護了像是 kube-dns 和 CoreDNS 等附加元件,用於為 Service 資源提供 DNS 解析。

DNS 在 Kubernetes 中的應用

在 Kubernetes 中,DNS 是預設的服務探索機制。當我們建立一個 Service 時,相關的 DNS 紀錄會被自動建立,讓其他 Pod 可以透過 DNS 名稱來存取該 Service。

Kubernetes Service 與 kube-proxy 的運作流程

此圖示說明瞭 Kubernetes 中 Client Pod 如何透過 DNS 解析 Service 名稱,並經由 kube-proxy 組態的 iptables 規則,將請求轉發到後端的 Pod,最終傳回回應給客戶端。

Kubernetes 網路策略與服務探索

Kubernetes 提供多種網路管理與服務探索機制,包括 DNS、環境變數及網路策略(NetworkPolicy)。這些功能使叢集內的服務能夠互相通訊,並確保網路安全。

服務探索機制

DNS 服務發現

Kubernetes 使用 DNS 作為主要的服務探索機制。叢集內的每個 Service 在建立時都會被分配一個 DNS A 記錄,格式為 <service-name>.<namespace>.svc.cluster.local>。例如:

# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   35d

# kubectl run --image=alpine dns-test -it -- /bin/sh
/ # nslookup kubernetes
Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   kubernetes.default.svc.cluster.local
Address: 10.96.0.1

對於無頭服務(Headless Services),DNS 解析會傳回後端 Pod 的 IP 地址:

/ # nslookup kube-headless
Name:      kube-headless
Address 1: 192.168.136.154 ip-192-168-136-154.ec2.internal
Address 2: 192.168.241.42 ip-192-168-241-42.ec2.internal

環境變數服務發現

除了 DNS,Kubernetes 還支援透過環境變數進行服務探索。當 Pod 啟動時,Kubernetes 會自動注入與該名稱空間內 Service 相關的環境變數:

# kubectl get svc test
NAME   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
test   ClusterIP   10.102.163.244   <none>        8080/TCP   9m

# 環境變數範例
TEST_SERVICE_HOST=10.102.163.244
TEST_SERVICE_PORT=8080
TEST_PORT=tcp://10.102.163.244:8080

程式碼解析:環境變數注入機制

import os

def get_service_address():
    host = os.getenv('TEST_SERVICE_HOST')
    port = os.getenv('TEST_SERVICE_PORT')
    return f"http://{host}:{port}"

print(get_service_address())

內容解密:

  1. os.getenv() 用於取得環境變數的值。
  2. TEST_SERVICE_HOSTTEST_SERVICE_PORT 是 Kubernetes 自動注入的環境變數,分別代表 Service 的 IP 和埠。
  3. 該程式碼片段展示瞭如何在應用程式中動態取得 Service 的連線資訊。

網路策略(NetworkPolicy)

網路策略用於控制 Pod 之間的網路流量,提供微隔離功能。透過定義 Ingress 和 Egress 規則,可以限制特定 Pod 的網路存取許可權。

網路策略範例

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: api-backend
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          project: api-midtier
    - podSelector:
        matchLabels:
          role: api-management
    ports:
    - protocol: TCP
      port: 3306
  egress:
  - to:
    - ipBlock:
        cidr: 10.3.4.5/32
    ports:
    - protocol: TCP
      port: 22

網路策略流程圖

此圖示展示了網路策略的執行流程,包括入口(Ingress)和出口(Egress)規則的比對過程。

網路策略關鍵概念解析

  1. podSelector:定義該網路策略適用的 Pod 範圍。
  2. policyTypes:指定該策略包含的規則型別(Ingress 或 Egress)。
  3. ingress:定義允許進入 Pod 的流量來源。
  4. egress:定義允許從 Pod 發出的流量目標。

Kubernetes 網路策略與服務網格

在 Kubernetes 中,網路策略(NetworkPolicy)用於控制 Pod 之間的流量。預設情況下,Kubernetes 沒有任何網路限制,但透過 NetworkPolicy,可以開始鎖定 Pod 之間的互連性。

網路策略範例

以下是一個簡單的 NetworkPolicy 範例,限制對特定 Pod 的存取:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-allow
spec:
  podSelector:
    matchLabels:
      role: db
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: api-management
    - ports:
      - 3306
  egress:
  - to:
    - ipBlock:
        cidr: 10.3.4.5/32
    - ports:
      - 22

內容解密:

  • podSelector 指定了此 NetworkPolicy 作用的 Pod,範例中選擇了標籤 role: db 的 Pod。
  • policyTypes 定義了此策略適用的流量型別,包括入口(Ingress)和出口(Egress)流量。
  • ingress 部分定義了允許進入 Pod 的流量來源,本例中允許來自標籤 role: api-management 的 Pod 對 3306 連線埠的存取。
  • egress 部分定義了允許從 Pod 出去的流量目的地,本例中允許到達 10.3.4.5 的 SSH 伺服器。

服務網格

在微服務環境中,流量可能會透過 Ingress、Service 和多個 Pod 複本進行流轉。這使得流量追蹤變得複雜,而服務網格(Service Mesh)解決方案可以幫助解決這個問題。

服務網格是一組「智慧」代理,能夠幫助使用者處理東西向(Pod-to-Pod)網路需求。這些代理可以作為 sidecar 容器執行在應用程式 Pod 中,也可以作為 DaemonSets 執行,提供節點本地的基礎設施元件。

服務網格的主要功能:

  1. 流量管理:可以實作高階的流量控制模式,如 canary 和 blue/green 佈署。
  2. 可觀察性:提供分散式追蹤機制,幫助除錯連線問題和識別慢速應用程式。
  3. 安全性:在基礎網路不提供預設加密的情況下,提供相互 TLS(Transport Layer Security)加密所有東西向流量。

常見的服務網格解決方案

常見的服務網格解決方案包括 Istio、Linkerd 和 Conduit。這些專案提供了上述功能,並且可以根據具體需求進行選擇。

Kubernetes 監控

設定或使用來自公共雲供應商的 Kubernetes 叢集固然重要,但若沒有正確的策略來監控指標和日誌,並在出現問題時發出適當的警示,那麼所建立的叢集就如同埋下了災難的定時炸彈。

監控目標

監控的主要目標是確保叢集和應用程式的可靠性。例如,若控制器管理器(二進位制檔案)停止正常運作,服務發現將開始慢慢過時。現有的服務已經正確傳播到叢集中的 DNS 伺服器,但新的服務或因滾動更新或擴充套件操作而更改的服務,將無法更新其 DNS。

主要監控目標:

  1. 可靠性:確保叢集和應用程式的穩定運作。
  2. 效能:監控叢集和應用程式的效能指標。
  3. 日誌管理:收集、儲存和分析日誌,以便於故障排除和安全稽核。
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title Kubernetes服務探索與網路策略詳解

package "Kubernetes Cluster" {
    package "Control Plane" {
        component [API Server] as api
        component [Controller Manager] as cm
        component [Scheduler] as sched
        database [etcd] as etcd
    }

    package "Worker Nodes" {
        component [Kubelet] as kubelet
        component [Kube-proxy] as proxy
        package "Pods" {
            component [Container 1] as c1
            component [Container 2] as c2
        }
    }
}

api --> etcd : 儲存狀態
api --> cm : 控制迴圈
api --> sched : 調度決策
api --> kubelet : 指令下達
kubelet --> c1
kubelet --> c2
proxy --> c1 : 網路代理
proxy --> c2

note right of api
  核心 API 入口
  所有操作經由此處
end note

@enduml

此圖示顯示了流量從 Ingress 經過 Service 到達多個 Pod 的流程,並展示了 Service Mesh 在其中扮演的角色。

圖示說明:

  • Ingress 負責接收外部流量並將其導向 Service。
  • Service 將流量分配給後端的 Pod(如 Pod1 和 Pod2)。
  • Pod1 和 Pod2 可能會透過 Service Mesh 與其他 Pod(如 Pod3)進行通訊。