本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

使用 Kubernetes 叢集聯邦構建全球分散式服務

在 Kubernetes 1.3 中,我們宣佈了 Kubernetes 叢集聯邦並引入了跨叢集服務發現的概念,使開發人員能夠部署一個跨越不同區域、地區或雲提供商的聯邦叢集的服務。這使開發人員能夠為他們的應用程式實現更高的可用性,而不會犧牲服務質量,正如我們之前的部落格文章所詳述的那樣。

在最新版本 Kubernetes 1.4 中,我們擴充套件了叢集聯邦以支援 Replica Sets、Secrets、Namespaces 和 Ingress 物件。這意味著您不再需要單獨在每個聯邦叢集中部署和管理這些物件。只需在聯邦中建立一次,其內建控制器將自動為您處理。

聯邦副本集利用與非聯邦 Kubernetes 副本集相同的配置,並自動將 Pod 分佈到一個或多個聯邦叢集中。預設情況下,副本均勻分佈在所有叢集中,但在不希望如此的情況下,我們引入了副本集偏好設定,允許副本僅分佈在某些叢集中,或以非相等比例分佈(定義註解)。

從 Google Cloud Platform (GCP) 開始,我們引入了 聯邦 Ingress 作為 Kubernetes 1.4 的 Alpha 功能,它允許外部客戶端指向單個 IP 地址,並將請求傳送到聯邦中任何區域、區域中具有可用容量的最近叢集。

聯邦 Secret 自動在聯邦的所有叢集中建立和管理 Secret,自動確保這些 Secret 在全域性範圍內保持一致和最新,即使在應用原始更新時某些叢集處於離線狀態。

聯邦 Namespace 與傳統的 Kubernetes Namespace 類似,提供相同的功能。在聯邦控制平面中建立它們可確保它們在聯邦的所有叢集中同步。

聯邦事件 與傳統的 Kubernetes 事件類似,提供相同的功能。聯邦事件僅儲存在聯邦控制平面中,不會傳遞給底層 Kubernetes 叢集。

讓我們來看看這一切是如何運作的。我們將為每個區域配置 3 個叢集,跨越 3 個大陸(歐洲、北美和亞洲)。

下一步是聯邦這些叢集。Kelsey Hightower 開發了一個教程,用於設定 Kubernetes 叢集聯邦。按照教程配置一個叢集聯邦,其中包含 us-central1、europe-west1 和 asia-east1 這 3 個 GCP 區域中每個區域的 3 個區域中的叢集。為了這篇部落格文章的目的,我們將在 us-central1-b 區域中配置聯邦控制平面。請注意,也有更高可用性的多叢集部署可用,但為了簡單起見,這裡未使用。

本部落格文章的其餘部分假設您已配置好一個正在執行的 Kubernetes 叢集聯邦。

讓我們驗證一下我們是否有 9 個叢集在 3 個區域中執行。

$ kubectl --context=federation-cluster get clusters


NAME              STATUS    AGE  
gce-asia-east1-a     Ready     17m  
gce-asia-east1-b     Ready     15m  
gce-asia-east1-c     Ready     10m  
gce-europe-west1-b   Ready     7m  
gce-europe-west1-c   Ready     7m  
gce-europe-west1-d   Ready     4m  
gce-us-central1-a    Ready     1m  
gce-us-central1-b    Ready     53s  
gce-us-central1-c    Ready     39s
您可以在此處下載此部落格文章中使用的原始碼。原始碼包含以下檔案
configmaps/zonefetch.yaml從例項元資料伺服器檢索區域並將其連線到卷掛載路徑中
replicasets/nginx-rs.yaml部署一個由 nginx 和 busybox 容器組成的 Pod
ingress/ingress.yaml建立一個具有全域性 VIP 的負載均衡器,將請求分發到最近的 nginx 後端
services/nginx.yaml將 nginx 後端作為外部服務暴露

在我們的示例中,我們將使用聯邦控制平面部署服務和 ingress 物件。ConfigMap 物件目前不受聯邦支援,因此我們將在每個底層聯邦叢集中手動部署它。我們的叢集部署將如下所示

我們將部署一個跨 9 個叢集分片的服務。後端部署將由一個帶有 2 個容器的 Pod 組成

  • busybox 容器,用於獲取區域並將帶有區域的 HTML 輸出到 Pod 卷掛載路徑中
  • nginx 容器,用於從 Pod 卷掛載路徑讀取並提供包含其執行區域的 HTML

讓我們首先在 federation-cluster 上下文中建立一個聯邦服務物件。

$ kubectl --context=federation-cluster create -f services/nginx.yaml

服務傳播到 9 個叢集需要幾分鐘。

$ kubectl --context=federation-cluster describe services nginx


Name:                   nginx  
Namespace:              default  
Labels:                 app=nginx  
Selector:               app=nginx  
Type:                   LoadBalancer  
IP:  
LoadBalancer Ingress:   108.59.xx.xxx, 104.199.xxx.xxx, ...  
Port:                   http    80/TCP

NodePort:               http    30061/TCP  
Endpoints:              <none>  
Session Affinity:       None

現在讓我們建立一個聯邦 Ingress。聯邦 Ingress 的建立方式與傳統 Kubernetes Ingress 大致相同:透過進行 API 呼叫來指定您邏輯入口點的所需屬性。對於聯邦 Ingress,此 API 呼叫指向聯邦 API 端點,而不是 Kubernetes 叢集 API 端點。聯邦 Ingress 的 API 與傳統 Kubernetes 服務的 API 100% 相容。

$ cat ingress/ingress.yaml   

apiVersion: extensions/v1beta1  
kind: Ingress  
metadata:  
  name: nginx  
spec:  
  backend:  
    serviceName: nginx  
    servicePort: 80
$ kubectl --context=federation-cluster create -f ingress/ingress.yaml   
ingress "nginx" created

建立後,聯邦 Ingress 控制器會自動

  1. 1.在您的叢集聯邦下的每個叢集中建立匹配的 Kubernetes Ingress 物件
  2. 2.確保所有這些叢集內 Ingress 物件共享相同的邏輯全域性 L7(即 HTTP(S))負載均衡器和 IP 地址
  3. 3.監控此 Ingress 後面的每個叢集中服務“分片”(即您的 Pod)的健康狀況和容量
  4. 4.確保在任何時候,即使發生 Pod、叢集、可用區或區域中斷,所有客戶端連線都路由到適當的健康後端服務終結點。我們可以驗證底層叢集中的 Ingress 物件是否匹配。請注意,所有 9 個叢集的 Ingress IP 地址都是相同的。
$ for c in $(kubectl config view -o jsonpath='{.contexts[*].name}'); do kubectl --context=$c get ingress; done  

NAME      HOSTS     ADDRESS   PORTS     AGE  
nginx     \*                   80        1h  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        40m  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        1h  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        26m  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        1h  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        25m  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        38m  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        3m  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        57m  
NAME      HOSTS     ADDRESS          PORTS     AGE  
nginx     \*         130.211.40.xxx   80        56m

請注意,在 Google Cloud Platform 的情況下,邏輯 L7 負載均衡器不是單個物理裝置(這將導致單點故障和單個全球網路路由瓶頸),而是一個真正的全球、高可用負載均衡託管服務,可透過單個靜態 IP 地址全域性訪問。

您的聯邦 Kubernetes 叢集內部的客戶端(即 Pod)將自動路由到其叢集中支援 Ingress 的聯邦服務的叢集本地分片(如果存在且健康),或者在不存在的情況下路由到不同叢集中最近的健康分片。請注意,這涉及到對 HTTP(S) 負載均衡器的網路往返,該負載均衡器位於您的本地 Kubernetes 叢集之外,但位於相同的 GCP 區域內。

下一步是排程服務後端。讓我們首先在聯邦中的每個叢集中建立 ConfigMap。

我們透過將 ConfigMap 提交到聯邦中的每個叢集來完成此操作。

$ for c in $(kubectl config view -o jsonpath='{.contexts[\*].name}'); do kubectl --context=$c create -f configmaps/zonefetch.yaml; done

讓我們快速檢視一下我們的 Replica Set

$ cat replicasets/nginx-rs.yaml


apiVersion: extensions/v1beta1  
kind: ReplicaSet  
metadata:  
  name: nginx  
  labels:  
    app: nginx  
    type: demo  
spec:  
  replicas: 9  
  template:  
    metadata:  
      labels:  
        app: nginx  
    spec:  
      containers:  
      - image: nginx  
        name: frontend  
        ports:  
          - containerPort: 80  
        volumeMounts:  
        - name: html-dir  
          mountPath: /usr/share/nginx/html  
      - image: busybox  
        name: zone-fetcher  
        command:  
          - "/bin/sh"  
          - "-c"  
          - "/zonefetch/zonefetch.sh"  
        volumeMounts:  
        - name: zone-fetch  
          mountPath: /zonefetch  
        - name: html-dir  
          mountPath: /usr/share/nginx/html  
      volumes:  
        - name: zone-fetch  
          configMap:  
            defaultMode: 0777  
            name: zone-fetch  
        - name: html-dir  
          emptyDir:  
            medium: ""

Replica Set 由 9 個副本組成,均勻分佈在叢集聯邦中的 9 個叢集中。註釋也可以用於控制 Pod 排程到哪些叢集。這可以透過在 Replica Set 規範中添加註釋來完成,如下所示

apiVersion: extensions/v1beta1  
kind: ReplicaSet  
metadata:  
  name: nginx-us  
  annotations:  
    federation.kubernetes.io/replica-set-preferences: ```  
        {  
            "rebalance": true,  
            "clusters": {  
                "gce-us-central1-a": {  
                    "minReplicas": 2,  
                    "maxReplicas": 4,  
                    "weight": 1  
                },  
                "gce-us-central10b": {  
                    "minReplicas": 2,  
                    "maxReplicas": 4,  
                    "weight": 1  
                }  
            }  
        }

為了演示目的,我們將保持簡單,將 Pod 均勻分佈在叢集聯邦中。

讓我們建立聯邦 Replica Set

$ kubectl --context=federation-cluster create -f replicasets/nginx-rs.yaml

驗證每個叢集中是否建立了 Replica Set 和 Pod

$ for c in $(kubectl config view -o jsonpath='{.contexts[\*].name}'); do kubectl --context=$c get rs; done  

NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         42s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         14m  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         45s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         46s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         47s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         48s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         49s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         49s  
NAME      DESIRED   CURRENT   READY     AGE  
nginx     1         1         1         49s


$ for c in $(kubectl config view -o jsonpath='{.contexts[\*].name}'); do kubectl --context=$c get po; done  

NAME          READY     STATUS    RESTARTS   AGE  
nginx-ph8zx   2/2       Running   0          25s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-sbi5b   2/2       Running   0          27s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-pf2dr   2/2       Running   0          28s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-imymt   2/2       Running   0          30s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-9cd5m   2/2       Running   0          31s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-vxlx4   2/2       Running   0          33s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-itagl   2/2       Running   0          33s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-u7uyn   2/2       Running   0          33s  
NAME          READY     STATUS    RESTARTS   AGE  
nginx-i0jh6   2/2       Running   0          34s

下圖是 nginx 服務和相關 Ingress 的部署示意圖。總結一下,我們使用全域性 L7 負載均衡器暴露了一個全域性 VIP(130.211.23.176),該負載均衡器將請求轉發到具有可用容量的最近叢集。

為了測試這一點,我們將在 us-west1-b 和 asia-east1-a 各啟動一個 Google Compute Engine (GCE) 例項。所有客戶端請求都會透過最短的網路路徑自動路由到距離請求源最近的叢集中健康的 Pod。因此,例如,來自亞洲的 HTTP(S) 請求將直接路由到亞洲最近的具有可用容量的叢集。如果亞洲沒有這樣的叢集,請求將路由到下一個最近的叢集(本例中是美國)。這無論請求是來自 GCE 例項還是網際網路上的任何其他地方都適用。我們在演示中僅使用 GCE 例項是為了簡化操作。

我們可以使用 Cloud Console 或發出 gcloud SSH 命令直接 SSH 到虛擬機器中。

$ gcloud compute ssh test-instance-asia --zone asia-east1-a

-----

user@test-instance-asia:~$ curl 130.211.40.186  
<!DOCTYPE html>  
<html>  
<head>  
<title>Welcome to the global site!</title>  
</head>  
<body>  
<h1>Welcome to the global site! You are being served from asia-east1-b</h1>  
<p>Congratulations!</p>


user@test-instance-asia:~$ exit

----


$ gcloud compute ssh test-instance-us --zone us-west1-b

----

user@test-instance-us:~$ curl 130.211.40.186  
<!DOCTYPE html>  
<html>  
<head>  
<title>Welcome to the global site!</title>  
</head>  
<body>  
<h1>Welcome to the global site! You are being served from us-central1-b</h1>  
<p>Congratulations!</p>


----

Kubernetes 叢集聯邦可以包含執行在不同雲提供商(例如 GCP、AWS)和本地(例如 OpenStack)的叢集。然而,在 Kubernetes 1.4 中,聯邦 Ingress 僅支援跨 Google Cloud Platform 叢集。在未來版本中,我們打算支援基於混合雲 Ingress 的部署。

總而言之,我們透過利用 Kubernetes 1.4 聯邦 Ingress Alpha 功能,部署了一個位於全域性負載均衡器後的多宿主服務。外部客戶端指向一個 IP 地址,並被髮送到聯邦中任何區域、地區中具有可用容量的最近叢集,從而在不犧牲延遲或操作簡便性的情況下提供更高級別的可用性。

我們很樂意聽取關於 Kubernetes 跨叢集服務的反饋。要加入社群