这篇文章发布于一年多以前。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
使用 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 将变得不可用。但是,在所有区域中运行的容器将继续运行,如果它们失败,则由 Kubelet 重新启动,因此应用程序本身将容忍这种区域故障。
节点已标记
要查看添加到节点的其他元数据,只需查看集群的所有标签(此处的示例在 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 的未来!有很多参与的方式。如果你对可伸缩性特别感兴趣,你将对以下内容感兴趣
- 我们的联合 slack 频道
- 联合“特别兴趣小组”,该小组每周四太平洋时间上午 9:30 在 SIG-Federation hangout 开会
当然,有关该项目的一般信息,请访问 www.kubernetes.io