瞭解 Kubernetes 服務


本頁說明不同類型的 Kubernetes 服務,以及 Google Kubernetes Engine (GKE) 如何使用服務將 Pod 端點分組。

您將瞭解如何使用 YAML 範例建立服務。每種服務類型都會使用服務的穩定 IP 位址,以降低特定網路和通訊工作的複雜度。舉例來說,您會瞭解如何使用多個通訊埠和端點,以及如何設定支援 IPv4 和 IPv6 的單一或雙堆疊選項。

如要瞭解如何建立服務,請參閱使用服務公開應用程式

本頁適用於佈建及設定雲端資源,並部署應用程式和服務的營運人員和開發人員。如要進一步瞭解內容中提及的常見角色和範例工作,請參閱「常見的 GKE Enterprise 使用者角色和工作」。 Google Cloud

什麼是 Kubernetes 服務?

Service 的概念,就是將一組 Pod 端點聚集成單一資源。而您可以設定利用多種方式來存取這組 Pod 端點。根據預設,您會有個穩定的叢集 IP 位址,能讓叢集中的用戶端拿來聯絡 Service 中的 Pod。用戶端會將要求傳送至穩定的 IP 位址,而要求會轉送至服務中的一個 Pod。

Service 會利用選取器辨識自己的成員 Pod。如要讓 Pod 成為 Service 的成員,該 Pod 必須要有在選取器中指定的所有標籤。標籤是附加在物件上的任意鍵/值組合。

以下的 Service 資訊清單擁有會指定兩個標籤的選取器。selector 欄位表示,只要是同時擁有 app: metrics 標籤和 department:engineering 標籤的 Pod,就是這個 Service 的成員。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: metrics
    department: engineering
  ports:
  ...

為什麼要使用 Kubernetes 服務?

在 Kubernetes 叢集中,每個 Pod 都有內部 IP 位址。但部署中的 Pod 會變動,其 IP 位址也會變更。因此,直接使用 Pod IP 位址並不合理。透過服務,您可獲得一個在服務生命週期內持續存在的穩定 IP 位址,甚至在成員 Pod 的 IP 位址變更時仍不會改變。

服務也能提供負載平衡。用戶端呼叫單一穩定的 IP 位址,而用戶端的要求會平均分配到屬於服務成員的 Pod 之間。

Kubernetes 服務類型

服務有五種類型:

  • ClusterIP (預設):內部用戶端會將要求傳送至穩定的內部 IP 位址。

  • NodePort:用戶端會根據 Service 所指定的一或多個 nodePort 值,將要求傳送至某個節點的 IP 位址。

  • LoadBalancer:用戶端會將要求傳送至某個網路負載平衡器的 IP 位址。

  • ExternalName:內部用戶端會把 Service 的 DNS 名稱當做外部 DNS 名稱的別名。

  • 無介面:如果您想要使用一組 Pod,但不需要穩定的 IP 位址,即可使用無介面 Service

NodePort 類型是 ClusterIP 類型的延伸,因此 NodePort 類型的 Service 擁有 1 個叢集 IP 位址。

LoadBalancer 類型是 NodePort 類型的延伸,因此 LoadBalancer 類型的 Service 擁有 1 個叢集 IP 位址,以及一或多個nodePort 值。

ClusterIP 類型的 Service

當您建立 ClusterIP 類型的 Service 時,Kubernetes 會建立可從叢集中的節點存取的穩定 IP 位址。

以下是 ClusterIP 類型 Service 的資訊清單:

apiVersion: v1
kind: Service
metadata:
  name: my-cip-service
spec:
  selector:
    app: metrics
    department: sales
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

您可以使用 kubectl apply -f [MANIFEST_FILE]建立 Service。當您建立 Service 之後,即可使用 kubectl get service 查看穩定的 IP 位址:

NAME             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)
my-cip-service   ClusterIP   10.11.247.213   none          80/TCP

叢集中的用戶端會利用叢集 IP 位址,以及在 Service 資訊清單的 port 欄位中指定的 TCP 通訊埠來呼叫 Service。系統會把要求轉送至在 targetPort 欄位中指定的 TCP 通訊埠上的某個成員 Pod。在上述範例中,用戶端會呼叫位於 10.11.247.213 的 TCP 通訊埠 80 上的 Service。要求會轉送至 TCP 通訊埠 8080 上的其中一個成員 Pod。成員 Pod 必須有監聽 TCP 通訊埠 8080 的容器。如果沒有任何監聽通訊埠 8080 的容器,用戶端會看到類似「無法連接」或「無法連上這個網站」的訊息。

NodePort 類型的 Service

當您建立 NodePort 類型的 Service 時,Kubernetes 會提供您 nodePort 值。然後,您就可以利用任何節點的 IP 位址與該 nodePort 值來存取 Service。

以下是 NodePort 類型 Service 的資訊清單:

apiVersion: v1
kind: Service
metadata:
  name: my-np-service
spec:
  selector:
    app: products
    department: sales
  type: NodePort
  ports:
  - protocol: TCP
    port: 80
    targetPort: 8080

當您建立 Service 之後,即可使用 kubectl get service -o yaml 檢視該 Service 的規格,以及查看 nodePort 值。

spec:
  clusterIP: 10.11.254.114
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 32675
    port: 80
    protocol: TCP
    targetPort: 8080

外部用戶端會利用某個節點的外部 IP 位址,以及 nodePort 所指定的 TCP 通訊埠來呼叫 Service。系統會把要求轉送至在 targetPort 欄位中指定的 TCP 通訊埠上的某個成員 Pod。

舉例來說,假設某個叢集節點的外部 IP 位址為 203.0.113.2,則在上述範例中,外部用戶端會呼叫位於 203.0.113.2 的 TCP 通訊埠 32675 上的 Service。系統會把要求轉送到 TCP 通訊埠 8080 上的某個成員 Pod,而該成員 Pod 必須擁有會監聽 TCP 通訊埠 8080 的容器。

NodePort Service 類型是 ClusterIP Service 類型的延伸,因此內部用戶端呼叫 Service 的方式有兩種:

  • 使用 clusterIPport
  • 使用節點的 IP 位址和 nodePort

在某些叢集配置中,外部應用程式負載平衡器會使用 NodePort 類型的 Service。

外部應用程式負載平衡器是 Proxy 伺服器,與本主題「LoadBalancer 類型的 Service」一節所述的外部直通式網路負載平衡器完全不同。

LoadBalancer 類型的 Service

如要進一步瞭解 LoadBalancer 類型的服務,請參閱LoadBalancer 服務概念

ExternalName 類型的 Service

ExternalName 類型的 Service 會提供外部 DNS 名稱的內部別名。內部用戶端會使用內部 DNS 名稱來發出要求,而系統會把該要求重新導向至外部名稱。

以下是 ExternalName 類型 Service 的資訊清單:

apiVersion: v1
kind: Service
metadata:
  name: my-xn-service
spec:
  type: ExternalName
  externalName: example.com

當您建立 Service 時,Kubernetes 會建立可讓內部用戶端拿來呼叫 Service 的 DNS 名稱。在上述範例中,DNS 名稱為 my-xn-service.default.svc.cluster.local。當內部用戶端向 my-xn-service.default.svc.cluster.local 發出要求時,系統會把該要求重新導向至 example.com。

ExternalName Service 類型與其他的 Service 類型完全不同。事實上,ExternalName 類型的 Service 並不符合本文一開始為 Service 所下的定義。ExternalName 類型的 Service 並沒有與一組 Pod 相關聯,且它沒有穩定的 IP 位址。相反地,ExternalName 類型的 Service 是內部 DNS 名稱與外部 DNS 名稱的對應關係。

無頭服務

無介面服務是一種 Kubernetes 服務,不會配置叢集 IP 位址。無介面服務會改用 DNS 公開與服務相關聯的 Pod IP 位址。這樣一來,您就能直接連線至 Pod,不必透過 Proxy。

無頭服務適用於各種情境,包括:

  • 服務探索:您可以使用無頭服務實作服務探索。如要實作這項功能,請建立具有名稱和選取器的 Service。無介面服務的 DNS 記錄包含符合選取器的 Service 後方所有 Pod 的 IP。用戶端可以使用這些 DNS 記錄,找出與服務相關聯的 Pod IP 位址。

  • 直接存取 Pod:用戶端可直接連線至與無頭服務相關聯的 Pod,這對於需要直接存取基礎 Pod 的服務 (例如負載平衡器和 DNS 伺服器) 很有幫助。

  • 彈性:無標題服務可用於建立各種不同的拓撲,例如負載平衡器、DNS 伺服器和分散式資料庫。

如果工作負載有特殊網路需求,無法透過含選取器的無標頭服務解決,也可以使用不含選取器的無標頭服務。無標頭服務是存取 Kubernetes 叢集外部服務的實用工具,因為控制層不會建立 EndpointSlice 物件,詳情請參閱「沒有選取器的服務」一文。

以下是無頭服務的資訊清單範例:

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
  - name: http
    port: 80
    targetPort: 80

建立無介面 Service 後,您可以查詢 DNS,找出與該 Service 相關聯的 Pod IP 位址。舉例來說,下列指令會列出與 nginx 服務相關聯的 Pod IP 位址:

dig +short nginx.default.svc.cluster.local

另一個使用 Kubernetes 查詢擴展的範例:

dig +short +search nginx

您可以使用單一指令建立無頭服務,且無頭服務易於更新及擴充。

kubectl create service clusterip my-svc --clusterip="None" --dry-run=client -o yaml > [file.yaml]

Service 抽象層

Service 是種抽象概念,因為它並不是監聽某個網路介面的程序。而這抽象概念有部分會在叢集節點的 iptables 規則中實現。視服務類型而定,抽象層的其他部分會透過外部直通式網路負載平衡器外部應用程式負載平衡器實作。

可任意選擇的 Service 通訊埠

Service 資訊清單中 port 欄位的值可讓您任意選擇,但您無法任意選擇 targetPort 的值。每個成員 Pod 成員都必須要有一個監聽 targetPort 的容器。

以下是 LoadBalancer 類型的 Service,它的 port 值為 50000:

apiVersion: v1
kind: Service
metadata:
  name: my-ap-service
spec:
  clusterIP: 10.11.241.93
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30641
    port: 50000
    protocol: TCP
    targetPort: 8080
  selector:
    app: parts
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.200

用戶端會呼叫位於 203.0.113.200 的 TCP 通訊埠 50000 上的 Service。要求會轉送至 TCP 通訊埠 8080 上的其中一個成員 Pod。

多個通訊埠

Service 的 ports 欄位包含一系列的 ServicePort 物件,而 ServicePort 物件有以下欄位:

  • name
  • protocol
  • port
  • targetPort
  • nodePort

如果您有數個 ServicePort,每個 ServicePort 都必須要有獨特的名稱。

以下是 LoadBalancer 類型的 Service,它擁有兩個 ServicePort 物件:

apiVersion: v1
kind: Service
metadata:
  name: my-tp-service
spec:
  clusterIP: 10.11.242.196
  externalTrafficPolicy: Cluster
  ports:
  - name: my-first-service-port
    nodePort: 31233
    port: 60000
    protocol: TCP
    targetPort: 50000
  - name: my-second-service-port
    nodePort: 31081
    port: 60001
    protocol: TCP
    targetPort: 8080
  selector:
    app: tests
    department: engineering
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 203.0.113.201

在上述範例中,如果用戶端呼叫位於 203.0.113.201 的 TCP 通訊埠 60000 上的 Service,系統會把要求轉送至 TCP 通訊埠 50000 上的成員 Pod。不過,如果用戶端在 TCP 通訊埠 60001 上從 203.0.113.201 呼叫服務,要求則會轉送至 TCP 通訊埠 8080 上的成員 Pod。

每個成員 Pod 都必須有一個監聽 TCP 通訊埠 50000 的容器,以及一個監聽 TCP 通訊埠 8080 的容器。這可以是具有兩個執行緒的單一容器,或在同一個 Pod 中執行的兩個容器。

Service 端點

建立 Service 時,Kubernetes 會建立 Endpoints 物件,而該物件的名稱會與您的 Service 名稱相同。Kubernetes 會使用該 Endpoints 物件來記錄哪些 Pod 是 Service 的成員。

單一堆疊和雙重堆疊服務

您可以建立類型為 ClusterIPNodePort 的 IPv6 服務。

針對每種服務類型,您可以將 ipFamiliesipFamilyPolicy 欄位定義為 IPv4、IPv6 或雙堆疊服務。

後續步驟