本文已發布超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
跨叢集服務 - 為您的 Kubernetes 應用程式實現更高的可用性
編者註: 這篇文章是 Kubernetes 1.3 新功能系列深入文章的一部分
隨著 Kubernetes 使用者擴展其生產部署,我們清楚地聽到他們希望跨區域、地區、叢集和雲端邊界部署服務。跨叢集服務提供地理分佈、實現混合雲和多雲情境,並提高超出單一叢集多區域部署的高可用性水平。希望其服務跨越一個或多個(可能是遠端)叢集的客戶,需要確保這些服務可以從叢集內外以一致的方式存取。
在 Kubernetes 1.3 中,我們的目標是盡可能減少摩擦點,並降低與將具有地理分佈的服務部署到多個叢集相關的管理/營運負擔。這篇文章說明如何做到這一點。
注意:雖然此處使用的範例利用 Google Container Engine (GKE) 來佈建 Kubernetes 叢集,但它們適用於您想要部署 Kubernetes 的任何地方。
讓我們開始吧。第一步是使用 GKE 在 4 個 Google Cloud Platform (GCP) 區域中建立 Kubernetes 叢集。
- asia-east1-b
- europe-west1-b
- us-east1-b
- us-central1-b
讓我們執行以下命令來建構叢集
gcloud container clusters create gce-asia-east1 \
--scopes cloud-platform \
--zone asia-east1-b
gcloud container clusters create gce-europe-west1 \
--scopes cloud-platform \
--zone=europe-west1-b
gcloud container clusters create gce-us-east1 \
--scopes cloud-platform \
--zone=us-east1-b
gcloud container clusters create gce-us-central1 \
--scopes cloud-platform \
--zone=us-central1-b
讓我們驗證叢集是否已建立
gcloud container clusters list
NAME ZONE MASTER\_VERSION MASTER\_IP NUM\_NODES STATUS
gce-asia-east1 asia-east1-b 1.2.4 104.XXX.XXX.XXX 3 RUNNING
gce-europe-west1 europe-west1-b 1.2.4 130.XXX.XX.XX 3 RUNNING
gce-us-central1 us-central1-b 1.2.4 104.XXX.XXX.XX 3 RUNNING
gce-us-east1 us-east1-b 1.2.4 104.XXX.XX.XXX 3 RUNNING
下一步是引導啟動叢集,並在已佈建的叢集之一上部署聯邦控制平面。如果您想一起操作,請參考 Kelsey Hightower 的教學,其中逐步說明了相關步驟。
聯邦服務
聯邦服務會定向到聯邦 API 端點,並指定您服務的所需屬性。
建立後,聯邦服務會自動
- 在叢集聯邦的每個底層叢集中建立相符的 Kubernetes 服務,
- 監控這些服務「碎片」(以及它們所在的叢集)的健康狀況,以及
- 在公用 DNS 提供者(如 Google Cloud DNS 或 AWS Route 53)中管理一組 DNS 記錄,從而確保您的聯邦服務的用戶端始終可以順利找到適當的健康服務端點,即使在叢集、可用性區域或區域中斷的情況下也是如此。
聯邦 Kubernetes 叢集內的用戶端(即 Pod)將自動找到其叢集中聯邦服務的本機碎片(如果存在且健康),或者在不同叢集中最接近的健康碎片(如果不存在)。
Kubernetes 叢集聯邦可以包含在不同雲端提供者(例如 GCP、AWS)和內部部署(例如在 OpenStack 上)中執行的叢集。您只需在適當的雲端提供者和/或位置中建立叢集,並向您的聯邦 API 伺服器註冊每個叢集的 API 端點和憑證即可。
在我們的範例中,我們在 4 個區域中建立了叢集,並在我們的其中一個叢集中部署了聯邦控制平面 API,我們將使用它來佈建我們的服務。請參閱下圖以取得視覺化表示。
建立聯邦服務
讓我們列出我們聯邦中的所有叢集
kubectl --context=federation-cluster get clusters
NAME STATUS VERSION AGE
gce-asia-east1 Ready 1m
gce-europe-west1 Ready 57s
gce-us-central1 Ready 47s
gce-us-east1 Ready 34s
讓我們建立一個聯邦服務物件
kubectl --context=federation-cluster create -f services/nginx.yaml
'--context=federation-cluster' 標誌告訴 kubectl 將請求提交到聯邦 API 端點,並附帶適當的憑證。聯邦服務將自動在您的聯邦的所有底層叢集中建立和維護相符的 Kubernetes 服務。
您可以透過檢查每個底層叢集來驗證這一點,例如
kubectl --context=gce-asia-east1a get svc nginx
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx 10.63.250.98 104.199.136.89 80/TCP 9m
以上假設您在用戶端中為該區域中的叢集設定了名為 'gce-asia-east1a' 的內容。底層服務的名稱和命名空間將自動與您在上面建立的聯邦服務的名稱和命名空間相符。
您的聯邦服務的狀態將自動反映底層 Kubernetes 服務的即時狀態,例如
kubectl --context=federation-cluster describe services nginx
Name: nginx
Namespace: default
Labels: run=nginx
Selector: run=nginx
Type: LoadBalancer
IP:
LoadBalancer Ingress: 104.XXX.XX.XXX, 104.XXX.XX.XXX, 104.XXX.XX.XXX, 104.XXX.XXX.XX
Port: http 80/TCP
Endpoints: \<none\>
Session Affinity: None
No events.
您的聯邦服務的「負載平衡器 Ingress」位址與所有底層 Kubernetes 服務的「負載平衡器 Ingress」位址相對應。為了使服務碎片之間的叢集間和跨雲端提供者網路正常運作,您的服務需要具有外部可見的 IP 位址。服務類型:此處通常使用負載平衡器。
另請注意,我們尚未佈建任何後端 Pod 來接收定向到這些位址的網路流量(即「服務端點」),因此聯邦服務尚未將這些視為健康的服務碎片,因此尚未將其位址新增到此聯邦服務的 DNS 記錄中。
新增後端 Pod
為了使底層服務碎片保持健康,我們需要在其後方新增後端 Pod。目前這是直接針對底層叢集的 API 端點完成的(雖然未來聯邦伺服器將能夠透過單一命令為您完成所有這些操作,以節省您的麻煩)。例如,在我們的底層叢集中建立後端 Pod
for CLUSTER in asia-east1-a europe-west1-a us-east1-a us-central1-a
do
kubectl --context=$CLUSTER run nginx --image=nginx:1.11.1-alpine --port=80
done
驗證公用 DNS 記錄
一旦 Pod 成功啟動並開始監聽連線,每個叢集中的 Kubernetes (透過自動健康檢查) 將報告它們是該叢集中服務的健康端點。叢集聯邦將進而將這些服務「碎片」視為健康,並透過自動設定相應的公用 DNS 記錄將它們投入服務。您可以使用您偏好的介面連線到您設定的 DNS 提供者來驗證這一點。例如,如果您的聯邦設定為使用 Google Cloud DNS 和受管理的 DNS 網域 'example.com'
$ gcloud dns managed-zones describe example-dot-com
creationTime: '2016-06-26T18:18:39.229Z'
description: Example domain for Kubernetes Cluster Federation
dnsName: example.com.
id: '3229332181334243121'
kind: dns#managedZone
name: example-dot-com
nameServers:
- ns-cloud-a1.googledomains.com.
- ns-cloud-a2.googledomains.com.
- ns-cloud-a3.googledomains.com.
- ns-cloud-a4.googledomains.com.
$ gcloud dns record-sets list --zone example-dot-com
NAME TYPE TTL DATA
example.com. NS 21600 ns-cloud-e1.googledomains.com., ns-cloud-e2.googledomains.com.
example.com. SOA 21600 ns-cloud-e1.googledomains.com. cloud-dns-hostmaster.google.com. 1 21600 3600 1209600 300
nginx.mynamespace.myfederation.svc.example.com. A 180 104.XXX.XXX.XXX, 130.XXX.XX.XXX, 104.XXX.XX.XXX, 104.XXX.XXX.XX
nginx.mynamespace.myfederation.svc.us-central1-a.example.com. A 180 104.XXX.XXX.XXX
nginx.mynamespace.myfederation.svc.us-central1.example.com.
nginx.mynamespace.myfederation.svc.us-central1.example.com. A 180 104.XXX.XXX.XXX, 104.XXX.XXX.XXX, 104.XXX.XXX.XXX
nginx.mynamespace.myfederation.svc.asia-east1-a.example.com. A 180 130.XXX.XX.XXX
nginx.mynamespace.myfederation.svc.asia-east1.example.com.
nginx.mynamespace.myfederation.svc.asia-east1.example.com. A 180 130.XXX.XX.XXX, 130.XXX.XX.XXX
nginx.mynamespace.myfederation.svc.europe-west1.example.com. CNAME 180 nginx.mynamespace.myfederation.svc.example.com.
... etc.
注意:如果您的聯邦設定為使用 AWS Route53,您可以使用其中一種同等的 AWS 工具,例如
$aws route53 list-hosted-zones
and
$aws route53 list-resource-record-sets --hosted-zone-id Z3ECL0L9QLOVBX
無論您使用哪種 DNS 提供者,任何 DNS 查詢工具(例如 'dig' 或 'nslookup')當然也都會讓您看到聯邦為您建立的記錄。
從聯邦叢集內的 Pod 探索聯邦服務
預設情況下,Kubernetes 叢集預先設定了叢集本機 DNS 伺服器 ('KubeDNS'),以及智慧型建構的 DNS 搜尋路徑,它們共同確保由 Pod 內執行的軟體發出的 DNS 查詢(例如 "myservice"、"myservice.mynamespace"、"bobsservice.othernamespace" 等)會自動展開並正確解析為在本機叢集中執行的服務的適當服務 IP。
隨著聯邦服務和跨叢集服務探索的引入,此概念已擴展到涵蓋在全球叢集聯邦中任何其他叢集中執行的 Kubernetes 服務。若要利用此擴展範圍,您可以使用稍微不同的 DNS 名稱(例如 myservice.mynamespace.myfederation)來解析聯邦服務。使用不同的 DNS 名稱也可以避免您的現有應用程式意外地遍歷跨區域或跨地區網路,並在您未明確選擇此行為的情況下產生可能不需要的網路費用或延遲。
因此,使用我們上面的 NGINX 範例服務,以及剛才描述的聯邦服務 DNS 名稱形式,讓我們考慮一個範例:us-central1-a 可用性區域中叢集中的 Pod 需要聯絡我們的 NGINX 服務。它現在可以使用服務的聯邦 DNS 名稱 "nginx.mynamespace.myfederation",而不是使用服務的傳統叢集本機 DNS 名稱 ("nginx.mynamespace",它會自動展開為 "nginx.mynamespace.svc.cluster.local")。這將自動展開並解析為我的 NGINX 服務最接近的健康碎片,無論它在世界何處。如果本機叢集中存在健康碎片,則將傳回該服務的叢集本機 (通常為 10.x.y.z) IP 位址(由叢集本機 KubeDNS 傳回)。這與非聯邦服務解析完全相同。
如果本機叢集中不存在該服務(或存在但沒有健康的後端 Pod),則 DNS 查詢會自動展開為 "nginx.mynamespace.myfederation.svc.us-central1-a.example.com"。在幕後,這是尋找最接近我的可用性區域的碎片之一的外部 IP。此展開由 KubeDNS 自動執行,KubeDNS 會傳回相關聯的 CNAME 記錄。這會導致遍歷上述範例中 DNS 記錄的階層,並最終到達本機 us-central1 區域中聯邦服務的外部 IP 之一。
也可以透過明確指定適當的 DNS 名稱,而不是依賴自動 DNS 展開,來鎖定可用性區域和區域中服務碎片,而不是 Pod 本機的服務碎片。例如,"nginx.mynamespace.myfederation.svc.europe-west1.example.com" 將解析為歐洲目前所有健康的服務碎片,即使發出查詢的 Pod 位於美國,並且無論美國是否存在服務的健康碎片。這對於遠端監控和其他類似應用程式非常有用。
從聯邦叢集外部的其他用戶端探索聯邦服務
對於外部用戶端,不再可能進行描述的自動 DNS 展開。外部用戶端需要指定聯邦服務的完整限定 DNS 名稱之一,無論是區域、地區或全域名稱。為了方便起見,通常最好在您的服務中手動設定其他靜態 CNAME 記錄,例如
eu.nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.europe-west1.example.com.
us.nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.us-central1.example.com.
nginx.acme.com CNAME nginx.mynamespace.myfederation.svc.example.com.
這樣,您的用戶端始終可以使用左側的簡短形式,並始終自動路由到其所在大陸上最接近的健康碎片。所有需要的容錯移轉都由 Kubernetes 叢集聯邦自動為您處理。
處理後端 Pod 和整個叢集的故障
標準 Kubernetes 服務叢集 IP 已經確保非回應的個別 Pod 端點會以低延遲自動停止服務。Kubernetes 叢集聯邦系統會自動監控叢集和聯邦服務所有碎片後方端點的健康狀況,並根據需要將碎片投入和停止服務。由於 DNS 快取中固有的延遲(聯邦服務 DNS 記錄的快取逾時或 TTL 預設設定為 3 分鐘,但可以調整),在災難性故障的情況下,所有用戶端可能需要長達這麼長的時間才能完全容錯移轉到替代叢集。但是,鑑於每個區域服務端點可以傳回的離散 IP 位址數量(例如,上面的 us-central1,有三個替代方案),許多用戶端將在比給定適當設定的時間更短的時間內自動容錯移轉到其中一個替代 IP。
社群
我們很樂意聽到有關 Kubernetes 跨叢集服務的回饋。若要加入社群
請試用跨叢集服務,並讓我們知道您的使用體驗!