本文已超過一年。較舊的文章可能包含過時的內容。請確認頁面中的資訊自發布以來是否已變得不正確。
使用 Kubernetes 叢集聯邦建構全球分散式服務
在 Kubernetes 1.3 中,我們宣布了 Kubernetes 叢集聯邦,並介紹了跨叢集服務探索的概念,使開發人員能夠部署跨越不同區域、地區或雲端供應商的叢集聯邦分片的服務。正如我們先前的博客文章中所詳述,這使開發人員能夠在不犧牲服務品質的情況下,實現應用程式的更高可用性。
在最新版本 Kubernetes 1.4 中,我們擴展了叢集聯邦以支援副本集、密鑰、命名空間和 Ingress 物件。這表示您不再需要在每個聯邦叢集中個別部署和管理這些物件。只需在聯邦中建立一次,並讓其內建控制器自動為您處理即可。
聯邦副本集 利用與非聯邦 Kubernetes 副本集相同的配置,並自動在一個或多個聯邦叢集之間分配 Pod。預設情況下,副本平均分配在所有叢集之間,但對於不希望如此行為的情況,我們推出了副本集偏好設定,允許將副本僅分配在某些叢集之間,或以不相等的比例分配 ( 定義註釋 )。
從 Google Cloud Platform (GCP) 開始,我們推出了 聯邦 Ingress 作為 Kubernetes 1.4 Alpha 功能,使外部用戶端能夠指向單一 IP 位址,並將請求發送到聯邦中任何區域、區域內最近的可用容量叢集。
聯邦密鑰 自動在聯邦中的所有叢集之間建立和管理密鑰,即使在應用原始更新時某些叢集處於離線狀態,也能自動確保這些密鑰在全球範圍內保持一致且最新。
聯邦命名空間 類似於傳統的 Kubernetes 命名空間,提供相同的功能。在聯邦控制平面中建立它們可確保它們在聯邦中的所有叢集之間同步。
聯邦事件 類似於傳統的 Kubernetes 事件,提供相同的功能。聯邦事件僅儲存在聯邦控制平面中,不會傳遞到底層的 Kubernetes 叢集。
讓我們逐步了解所有這些東西是如何運作的。我們將在每個區域佈建 3 個叢集,跨越 3 大洲(歐洲、北美洲和亞洲)。
下一步是聯邦這些叢集。Kelsey Hightower 開發了一個 教學課程,用於設定 Kubernetes 叢集聯邦。按照本教學課程配置叢集聯邦,其中包含 us-central1、europe-west1 和 asia-east1 這 3 個 GCP 區域中每個區域的 3 個區域中的叢集。就本博客文章而言,我們將在 us-central1-b 區域中佈建聯邦控制平面。請注意,也提供更高可用性的多叢集部署,但為了簡潔起見,此處未使用。
本博客文章的其餘部分假設您已佈建正在運行的 Kubernetes 叢集聯邦。
讓我們驗證我們在 3 個區域中運行 9 個叢集。
$ 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
讓我們從在聯邦叢集上下文中建立聯邦服務物件開始。
$ 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 點的期望屬性。對於聯邦 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
讓我們快速查看一下我們的副本集
$ 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: ""
副本集由 9 個副本組成,平均分佈在叢集聯邦內的 9 個叢集中。註釋也可用於控制將 Pod 排程到哪些叢集。這是透過將註釋新增至副本集規格來完成的,如下所示
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 平均分佈在叢集聯邦中。
讓我們建立聯邦副本集
$ kubectl --context=federation-cluster create -f replicasets/nginx-rs.yaml
驗證副本集和 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 的部署方式。總而言之,我們有一個全域 VIP (130.211.23.176),使用全域 L7 負載平衡器公開,該負載平衡器將請求轉發到最近的可用容量叢集。
為了測試這一點,我們將啟動 2 個 Google Cloud Engine (GCE) 實例,一個在 us-west1-b 中,另一個在 asia-east1-a 中。所有用戶端請求都會透過最短的網路路徑自動路由到最接近請求來源的叢集中健康的 Pod。例如,來自亞洲的 HTTP(S) 請求將直接路由到亞洲最近的可用容量叢集。如果亞洲沒有此類叢集,則請求將路由到下一個最近的叢集(在本例中為美國)。無論請求是來自 GCE 實例還是網路上任何其他位置,這都有效。我們僅使用 GCE 實例來簡化演示。
我們可以透過 Cloud Console 或發出 gcloud SSH 命令直接 SSH 連線到 VM。
$ 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 上關注 @Kubernetesio 以獲取最新更新