使用服務公開你的應用程式
目標
- 瞭解 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"
注意
如果您正在使用 Docker Desktop 作為容器驅動程式執行 minikube,則需要 minikube tunnel。這是因為 Docker Desktop 內部的容器與您的主機計算機是隔離的。
在單獨的終端視窗中,執行
minikube service kubernetes-bootcamp --url
輸出如下:
http://127.0.0.1:51082
! Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
然後使用給定的 URL 訪問應用程式。
curl 127.0.0.1:51082
我們收到了來自伺服器的響應。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。
下一步
- 教程執行應用程式的多個例項。
- 瞭解有關Service的更多資訊。