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

使用 Kubernetes 全新多區域叢集(又名「Ubernetes Lite」)建構高可用性應用程式

編輯註記: 這是 Kubernetes 1.2 新功能 系列深入文章的第三篇

簡介

Kubernetes 最常被要求的功能之一,就是在多個區域中執行應用程式的能力。這是有充分理由的 — 開發人員需要跨多個網域部署應用程式,以在單一區域中斷時提高可用性。

Kubernetes 1.2 在兩週前發布,新增了在多個故障區域(GCP 簡稱為「區域」,Amazon 稱為「可用區域」,在此我們將其稱為「區域」)中執行單一叢集的功能。這是更廣泛努力的第一步,目的是將多個 Kubernetes 叢集聯合在一起(有時以暱稱「Ubernetes」稱之)。這個初始版本(稱為「Ubernetes Lite」)透過將應用程式分散到單一雲端供應商內的多個區域,來提高應用程式的可用性。

多區域叢集經過刻意簡化,而且在設計上非常容易使用 — 不需要 Kubernetes API 變更,也不需要應用程式變更。您只需將現有的 Kubernetes 應用程式部署到新型多區域叢集中,您的應用程式就會自動具備區域故障的復原能力。

現在進入一些細節...

Ubernetes Lite 的運作方式是透過標籤來利用 Kubernetes 平台的可擴展性。如今,當節點啟動時,標籤會新增到系統中的每個節點。透過 Ubernetes Lite,系統已擴展為也新增關於節點執行所在區域的資訊。有了這些資訊,排程器就可以針對應用程式實例的放置做出明智的決策。

具體來說,排程器已分散 Pod,以盡量減少任何單一節點故障的影響。透過 Ubernetes Lite,藉由 SelectorSpreadPriority,排程器將盡最大努力跨區域分散放置。我們應注意,如果叢集中的區域是異質的(例如,不同數量的節點或不同類型的節點),您可能無法實現跨區域平均分散 Pod。如果需要,您可以使用同質區域(相同數量和類型的節點)來降低不均勻分散的可能性。

這種改良的標籤也適用於儲存。當建立持久性磁碟區時,PersistentVolumeLabel 許可控制器會自動將區域標籤新增到其中。然後排程器(透過 VolumeZonePredicate 述詞)將確保聲明給定磁碟區的 Pod 僅放置在與該磁碟區相同的區域中,因為磁碟區無法跨區域附加。

逐步解說

我們現在將逐步解說如何在 Google Compute Engine (GCE) 和 Amazon EC2 上,使用 Kubernetes 隨附的預設 kube-up 指令碼來設定和使用多區域叢集。雖然我們重點介紹 GCE 和 EC2,但此功能適用於任何 Kubernetes 1.2 部署,您可以在叢集設定期間進行變更。此功能也將在 Google Container Engine (GKE) 中很快推出。

啟動您的叢集

為 Kubernetes 建立多區域部署與單區域叢集相同,但您需要傳遞環境變數("MULTIZONE”)來告知叢集管理多個區域。我們先從在 GCE 和/或 EC2 上建立多區域感知叢集開始。

GCE

curl -sS https://get.k8s.io | MULTIZONE=true KUBERNETES_PROVIDER=gce
KUBE_GCE_ZONE=us-central1-a NUM_NODES=3 bash

EC2

curl -sS https://get.k8s.io | MULTIZONE=true KUBERNETES_PROVIDER=aws
KUBE_AWS_ZONE=us-west-2a NUM_NODES=3 bash

在此指令的結尾,您將啟動一個叢集,該叢集已準備好管理在多個區域中執行的節點。您也將啟動 NUM_NODES 個節點和叢集的控制平面(即 Kubernetes master),全部都在 KUBE_{GCE,AWS}_ZONE 指定的區域中。在 Ubernetes Lite 的未來迭代中,我們將支援 HA 控制平面,其中 master 元件會在多個區域中複寫。在那之前,如果執行 master 的區域發生故障,master 將變得不可用。但是,在所有區域中執行的容器將繼續執行,並在故障時由 Kubelet 重新啟動,因此應用程式本身將能容忍此類區域故障。

節點已加上標籤

若要查看新增到節點的其他 metadata,只需檢視叢集的所有標籤(此處的範例是在 GCE 上)

$ kubectl get nodes --show-labels

NAME STATUS AGE LABELS
kubernetes-master Ready,SchedulingDisabled 6m        
beta.kubernetes.io/instance-type=n1-standard-1,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-master
kubernetes-minion-87j9 Ready 6m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-87j9
kubernetes-minion-9vlv Ready 6m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-9vlv
kubernetes-minion-a12q Ready 6m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-a12q

排程器將在其排程決策中使用附加到每個節點的標籤(區域使用 failure-domain.beta.kubernetes.io/region,區域使用 failure-domain.beta.kubernetes.io/zone)。

在第二個區域中新增更多節點

讓我們將另一組節點新增到現有的叢集,但在不同的區域(GCE 為 us-central1-b,EC2 為 us-west-2b)中執行。我們再次執行 kube-up,但透過指定 KUBE_USE_EXISTING_MASTER=1,kube-up 將不會建立新的 master,而是會重複使用先前建立的 master。

GCE

KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=gce
KUBE_GCE_ZONE=us-central1-b NUM_NODES=3 kubernetes/cluster/kube-up.sh

在 EC2 上,我們也需要指定額外子網路的網路 CIDR,以及 master 內部 IP 位址

KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=aws
KUBE_AWS_ZONE=us-west-2b NUM_NODES=3 KUBE_SUBNET_CIDR=172.20.1.0/24
MASTER_INTERNAL_IP=172.20.0.9 kubernetes/cluster/kube-up.sh

再次檢視節點;將會啟動並標記另外 3 個節點(此處的範例是在 GCE 上)

$ kubectl get nodes --show-labels

NAME STATUS AGE LABELS
kubernetes-master Ready,SchedulingDisabled 16m       
beta.kubernetes.io/instance-type=n1-standard-1,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-master
kubernetes-minion-281d Ready 2m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kub
ernetes.io/hostname=kubernetes-minion-281d
kubernetes-minion-87j9 Ready 16m       
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-87j9
kubernetes-minion-9vlv Ready 16m       
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-9vlv
kubernetes-minion-a12q Ready 17m       
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-a12q
kubernetes-minion-pp2f Ready 2m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kub
ernetes.io/hostname=kubernetes-minion-pp2f
kubernetes-minion-wf8i Ready 2m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kub
ernetes.io/hostname=kubernetes-minion-wf8i

讓我們再新增一個區域

GCE

KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=gce
KUBE_GCE_ZONE=us-central1-f NUM_NODES=3 kubernetes/cluster/kube-up.sh

EC2

KUBE_USE_EXISTING_MASTER=true MULTIZONE=true KUBERNETES_PROVIDER=aws
KUBE_AWS_ZONE=us-west-2c NUM_NODES=3 KUBE_SUBNET_CIDR=172.20.2.0/24
MASTER_INTERNAL_IP=172.20.0.9 kubernetes/cluster/kube-up.sh

驗證您現在在 3 個區域中都有節點

kubectl get nodes --show-labels

高可用性應用程式,指日可待。

部署多區域應用程式

建立 guestbook-go 範例,其中包含大小為 3 的 ReplicationController,執行簡單的 Web 應用程式。從此處下載所有檔案,並執行以下指令(指令假設您將它們下載到名為「guestbook-go」的目錄)

kubectl create -f guestbook-go/

您完成了!您的應用程式現在已分散到所有 3 個區域。使用以下指令向自己證明

$ kubectl describe pod -l app=guestbook | grep Node
Node: kubernetes-minion-9vlv/10.240.0.5
Node: kubernetes-minion-281d/10.240.0.8
Node: kubernetes-minion-olsh/10.240.0.11

$ kubectl get node kubernetes-minion-9vlv kubernetes-minion-281d 
kubernetes-minion-olsh --show-labels
NAME STATUS AGE LABELS
kubernetes-minion-9vlv Ready 34m       
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-a,kub
ernetes.io/hostname=kubernetes-minion-9vlv
kubernetes-minion-281d Ready 20m       
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-b,kub
ernetes.io/hostname=kubernetes-minion-281d
kubernetes-minion-olsh Ready 3m        
beta.kubernetes.io/instance-type=n1-standard-2,failure-domain.beta.kubernetes.
io/region=us-central1,failure-domain.beta.kubernetes.io/zone=us-central1-f,kub
ernetes.io/hostname=kubernetes-minion-olsh

此外,負載平衡器會自動跨叢集中的所有區域;guestbook-go 範例包含負載平衡服務範例

$ kubectl describe service guestbook | grep LoadBalancer.Ingress
LoadBalancer Ingress: 130.211.126.21

ip=130.211.126.21

$ curl -s http://${ip}:3000/env | grep HOSTNAME
  "HOSTNAME": "guestbook-44sep",

$ (for i in `seq 20`; do curl -s http://${ip}:3000/env | grep HOSTNAME; done)  
| sort | uniq
  "HOSTNAME": "guestbook-44sep",
  "HOSTNAME": "guestbook-hum5n",
  "HOSTNAME": "guestbook-ppm40",

負載平衡器正確地鎖定所有 Pod,即使它們位於多個區域中。

關閉叢集

完成後,清除

GCE

KUBERNETES_PROVIDER=gce KUBE_USE_EXISTING_MASTER=true 
KUBE_GCE_ZONE=us-central1-f kubernetes/cluster/kube-down.sh
KUBERNETES_PROVIDER=gce KUBE_USE_EXISTING_MASTER=true 
KUBE_GCE_ZONE=us-central1-b kubernetes/cluster/kube-down.sh
KUBERNETES_PROVIDER=gce KUBE_GCE_ZONE=us-central1-a 
kubernetes/cluster/kube-down.sh

EC2

KUBERNETES_PROVIDER=aws KUBE_USE_EXISTING_MASTER=true KUBE_AWS_ZONE=us-west-2c 
kubernetes/cluster/kube-down.sh
KUBERNETES_PROVIDER=aws KUBE_USE_EXISTING_MASTER=true KUBE_AWS_ZONE=us-west-2b 
kubernetes/cluster/kube-down.sh
KUBERNETES_PROVIDER=aws KUBE_AWS_ZONE=us-west-2a 
kubernetes/cluster/kube-down.sh

結論

Kubernetes 的核心理念是抽象化執行高可用性分散式應用程式的複雜性。正如您在此處所見,除了在叢集啟動時進行少量工作外,跨多個故障網域啟動應用程式實例的所有複雜性,都不需要應用程式開發人員進行額外的工作,這才是應有的狀態。而我們才剛開始!

請加入我們的社群,協助我們建構 Kubernetes 的未來!有很多種參與方式。如果您對擴充性特別感興趣,您會對以下內容感興趣

當然,如需有關專案的更多資訊,請前往 www.kubernetes.io