本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 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.在您的叢集聯邦下的每個叢集中建立匹配的 Kubernetes Ingress 物件
- 2.確保所有這些叢集內 Ingress 物件共享相同的邏輯全域性 L7(即 HTTP(S))負載均衡器和 IP 地址
- 3.監控此 Ingress 後面的每個叢集中服務“分片”(即您的 Pod)的健康狀況和容量
- 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 跨叢集服務的反饋。要加入社群
- 在 GitHub 上釋出問題或功能請求
- 加入 Slack 上的 #federation 頻道
- 參與 叢集聯邦 SIG
- 下載 Kubernetes
- 在 Twitter 上關注 Kubernetes @Kubernetesio 獲取最新更新