本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
跨叢集服務 - 為您的 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.
您的聯邦服務的“LoadBalancer Ingress”地址與所有底層 Kubernetes 服務的“LoadBalancer Ingress”地址相對應。為了使服務分片之間的叢集間和雲提供商間網路正常工作,您的服務需要具有外部可見的 IP 地址。此處通常使用服務型別:Loadbalancer。
另請注意,我們尚未為接收定向到這些地址的網路流量(即“服務終結點”)配置任何後端 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 中執行所發出的“myservice”、“myservice.mynamespace”、“bobsservice.othernamespace”等 DNS 查詢會自動擴充套件並正確解析為本地叢集中執行的服務的適當服務 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 自動執行,它返回相關的 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 跨叢集服務的反饋。加入社群:
請嘗試使用跨叢集服務,並告訴我們您的體驗如何!