使用服務公開你的應用程式

目標

  • 瞭解 Kubernetes 中的 Service。
  • 瞭解標籤和選擇器如何與 Service 相關。
  • 將應用程式暴露到 Kubernetes 叢集之外。

Kubernetes Service 概述

Kubernetes Pod 是有生命週期的。Pod 具有 生命週期。當一個工作節點死亡時,在該節點上執行的 Pod 也會丟失。然後,Replicaset 可能會透過建立新的 Pod 將叢集動態地恢復到所需的狀態,以保持應用程式的執行。再舉一個例子,考慮一個有 3 個副本的影像處理後端。這些副本是可互換的;前端系統不應該關心後端副本,甚至不應該關心 Pod 是否丟失並重新建立。也就是說,Kubernetes 叢集中的每個 Pod 都有一個唯一的 IP 地址,即使是同一節點上的 Pod 也是如此,因此需要有一種方法來自動協調 Pod 之間的更改,以使您的應用程式能夠繼續執行。

Kubernetes 中的 Service 是一個抽象,它定義了一組邏輯 Pod 和訪問它們的方式。Service 實現了依賴 Pod 之間的鬆散耦合。Service 與所有 Kubernetes 物件清單一樣,使用 YAML 或 JSON 定義。Service 所指向的 Pod 集合通常由_標籤選擇器_決定(有關為何需要在不包含 selector 的情況下建立 Service,請參閱下文)。

儘管每個 Pod 都有唯一的 IP 地址,但如果沒有 Service,這些 IP 地址就不會暴露在叢集外部。Service 允許您的應用程式接收流量。透過在 Service 的 spec 中指定 type,Service 可以以不同的方式暴露。

  • ClusterIP(預設) - 在叢集中的內部 IP 上暴露 Service。此型別使 Service 只能在叢集內部訪問。

  • NodePort - 使用 NAT 在叢集中每個選定節點的同一埠上暴露 Service。使用 NodeIP:NodePort 使 Service 可以從叢集外部訪問。它是 ClusterIP 的超集。

  • LoadBalancer - 在當前雲中(如果支援)建立外部負載均衡器,併為 Service 分配一個固定的外部 IP。它是 NodePort 的超集。

  • ExternalName - 透過返回包含其值的 CNAME 記錄,將 Service 對映到 externalName 欄位的內容(例如 foo.bar.example.com)。不設定任何型別的代理。此型別需要 kube-dns v1.7 或更高版本,或者 CoreDNS 0.0.8 或更高版本。

有關不同型別的 Service 的更多資訊,請參閱使用源 IP 教程。另請參閱使用 Service 連線應用程式

此外,請注意,Service 有些用例不涉及在 spec 中定義 selector。在沒有 selector 的情況下建立的 Service 也不會建立相應的 Endpoints 物件。這允許使用者手動將 Service 對映到特定的端點。可能沒有選擇器的另一個原因是你嚴格使用 type: ExternalName

Service 和標籤

Service 將流量路由到一組 Pod。Service 是一種抽象,允許 Pod 在 Kubernetes 中消亡和複製而不影響您的應用程式。依賴 Pod 之間(例如應用程式中的前端和後端元件)的發現和路由由 Kubernetes Service 處理。

Service 使用標籤和選擇器匹配一組 Pod,這是一種分組原語,允許對 Kubernetes 中的物件進行邏輯操作。標籤是附加到物件的鍵/值對,可以以多種方式使用。

  • 指定用於開發、測試和生產的物件
  • 嵌入版本標籤
  • 使用標籤對物件進行分類

標籤可以在建立時或之後附加到物件。它們可以隨時修改。現在讓我們使用 Service 暴露我們的應用程式並應用一些標籤。

步驟 1:建立新的 Service

讓我們驗證一下我們的應用程式是否正在執行。我們將使用 kubectl get 命令並查詢現有的 Pod。

kubectl get pods

如果沒有 Pod 正在執行,則意味著之前教程中的物件已被清理。在這種情況下,請返回並從使用 kubectl 建立 Deployment 教程中重新建立 Deployment。請稍等幾秒鐘,然後再次列出 Pod。看到一個 Pod 執行後,即可繼續。

接下來,讓我們列出叢集中當前的 Service。

kubectl get services

為了將 Deployment 暴露給外部流量,我們將使用帶有 --type=NodePort 選項的 kubectl expose 命令。

kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080

我們現在有一個名為 kubernetes-bootcamp 的執行中的 Service。在這裡我們看到 Service 收到了一個唯一的叢集 IP、一個內部埠和一個外部 IP(節點的 IP)。

要找出外部開啟的埠(對於 type: NodePort Service),我們將執行 describe service 子命令。

kubectl describe services/kubernetes-bootcamp

建立一個名為 NODE_PORT 的環境變數,其值為分配的節點埠。

export NODE_PORT="$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')"
echo "NODE_PORT=$NODE_PORT"

現在我們可以使用 curl、節點的 IP 地址和外部暴露的埠來測試應用程式是否暴露在叢集外部。

curl http://"$(minikube ip):$NODE_PORT"

我們收到了來自伺服器的響應。Service 已暴露。

步驟 2:使用標籤

Deployment 自動為我們的 Pod 建立了一個標籤。透過 describe deployment 子命令,您可以看到該標籤的名稱(鍵)。

kubectl describe deployment

讓我們使用此標籤查詢我們的 Pod 列表。我們將使用 kubectl get pods 命令,其中 -l 作為引數,後跟標籤值。

kubectl get pods -l app=kubernetes-bootcamp

您可以使用相同的方法列出現有 Service。

kubectl get services -l app=kubernetes-bootcamp

獲取 Pod 的名稱並將其儲存在 POD_NAME 環境變數中。

export POD_NAME="$(kubectl get pods -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}')"
echo "Name of the Pod: $POD_NAME"

要應用新標籤,我們使用 label 子命令,後跟物件型別、物件名稱和新標籤。

kubectl label pods "$POD_NAME" version=v1

這將為我們的 Pod 應用一個新標籤(我們將應用程式版本固定到 Pod),我們可以使用 describe pod 命令進行檢查。

kubectl describe pods "$POD_NAME"

我們在這裡看到標籤現在已附加到我們的 Pod。現在我們可以使用新標籤查詢 Pod 列表。

kubectl get pods -l version=v1

我們看到了 Pod。

步驟 3:刪除 Service

要刪除 Service,您可以使用 delete service 子命令。標籤也可以在這裡使用。

kubectl delete service -l app=kubernetes-bootcamp

確認 Service 已消失。

kubectl get services

這確認了我們的 Service 已被刪除。要確認路由不再暴露,您可以 curl 之前暴露的 IP 和埠。

curl http://"$(minikube ip):$NODE_PORT"

這證明應用程式無法再從叢集外部訪問。您可以從 Pod 內部使用 curl 確認應用程式仍在執行。

kubectl exec -ti $POD_NAME -- curl https://:8080

我們在這裡看到應用程式正在執行。這是因為 Deployment 正在管理應用程式。要關閉應用程式,您還需要刪除 Deployment。

下一步

上次修改於 2025 年 5 月 8 日上午 9:59 PST:更新 expose-intro.md 中的 expose 命令 (#50570) (894a84131b)