概述#

上一章使用 port-forward 把本機端口轉發到指定 Pod,但這種作法的最大問題是:Pod 是非永久性的,一旦被重新建立,舊的 port-forward 設定就跟著失效。

Service 正是 Kubernetes(K8s)為了解決「一群 Pod 要如何被連線與存取」而設計的物件。它把暴露端口的職責從 Pod 抽離出來,並透過 Labels 與 Selector 動態關聯背後的 Pod 集合。當 Pod 被重新建立時,只要新的 Pod 帶有相同的 Label,就會自動被納入同一個 Service 之下,無需重新設定連線。

用 Service 實現負載均衡#

下面把上一章的 foo 加上一個夥伴 bar,並透過 Service 統一管理兩者的流量。

Pod 設定#

兩個 Pod 共用同一個 Label type: demo,方便之後讓 Service 一次選中:

apiVersion: v1
kind: Pod
metadata:
  name: foo
  labels:
    app: foo
    type: demo
spec:
  containers:
    - name: foo
      image: mikehsu0618/foo
      ports:
        - containerPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
  name: bar
  labels:
    app: bar
    type: demo
spec:
  containers:
    - name: bar
      image: mikehsu0618/bar
      ports:
        - containerPort: 8080

Service 設定#

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    type: demo
  type: LoadBalancer
  ports:
    - protocol: TCP
      port: 8000
      targetPort: 8080
      nodePort: 30390

各欄位說明:

  • apiVersion:Service 使用 Kubernetes 的 v1 核心 API。
  • metadata.name:Service 名稱。
  • spec.type:Service 型別,常見為 ClusterIPNodePortLoadBalancer
  • spec.ports.port:Service 在叢集內被存取時對外的端口,會對應到 targetPort
  • spec.ports.nodePort:節點上對外開放的端口;如果沒指定,Kubernetes 會自動隨機分配。
  • spec.ports.targetPort:實際 Pod 中容器監聽的端口,本例對應到 Gin 的 8080。
  • spec.ports.protocol:支援 TCPUDPSCTP,預設為 TCP
  • spec.selector:透過 Label 過濾要納入的 Pod。本例會選中所有帶有 type: demo 的 Pod。

套用設定並驗證#

可以一次套用兩份檔案:

kubectl apply -f pod.yaml,service.yaml

查看 Service 與整體狀態:

kubectl get services
# 或一次列出所有資源
kubectl get all

當 Service 型別為 LoadBalancer,若叢集架在 AWS 或 GCP,雲端供應商會配給一個對應的雲端 LoadBalancer,把流量分散到節點上的 NodePort。在 docker-desktop 環境下,External IP 會直接指向本機 localhost,因此可以直接從本機驗證:

curl localhost:8000

每次呼叫,Service 會把流量隨機分派到 foobar 兩個 Pod 之一,這就是 Kubernetes 內建的負載均衡能力。

Service 對 Pod 的選擇純粹依賴 Label。當你重新建立、擴展或刪除 Pod,只要 Label 對得上,Service 就會自動更新背後的 Endpoint,不需要修改 Service 設定。

小結#

Service 把「對外暴露」與「Pod 生命週期」解耦:使用者請求的對象從具體的 Pod 變成抽象的 Service,平台則在背後維護 Pod 集合與流量分派。這樣的設計讓水平擴展、滾動更新、藍綠部署等進階操作都能更平滑地實現。

下一章會引入 Deployment,把 Pod 的建立與生命週期管理也一併納入宣告式設定中。

原文出處#

  • GitHub:https://github.com/MikeHsu0618/2022-ithelp/tree/main/Day7
  • iThome:https://ithelp.ithome.com.tw/articles/10288389