这篇文章已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已过时。
使用 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 仅被放置到与该卷相同的区域,因为卷无法跨区域连接。
演练
现在我们将演练如何使用 Kubernetes 附带的默认 kube-up 脚本,在 Google Compute Engine (GCE) 和 Amazon EC2 上设置和使用多区域集群。虽然我们重点介绍 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 主节点),所有这些都位于 KUBE_{GCE,AWS}_ZONE
指定的区域中。在 Ubernetes Lite 的未来迭代中,我们将支持 HA 控制平面,主节点组件将在区域间复制。在此之前,如果主节点所在的区域发生故障,主节点将变得不可用。然而,在所有区域中运行的容器将继续运行,如果它们发生故障,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 不会创建新的主节点,而是重用之前创建的一个。
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,以及主节点的内部 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 的未来!有许多参与方式。如果你对可扩展性特别感兴趣,你会对以下内容感兴趣:
- 我们的 federation Slack 频道
- Federation“特别兴趣小组”,每周四太平洋时间上午 9:30 在SIG-Federation 环聊 会面。
当然,有关项目的一般更多信息,请访问www.kubernetes.io。