本文发布时间已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
跨集群服务 - 为您的 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.
您联合服务的“负载均衡器入口”地址与所有底层 Kubernetes 服务的“负载均衡器入口”地址相对应。为了使服务分片之间的集群间和云提供商间网络正常工作,您的服务需要具有外部可见的 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 内运行的软件发出的诸如 "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 跨集群服务的反馈。要加入社区,请:
请尝试使用跨集群服务,并告诉我们您的使用体验!