本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
跨集群服务 - 为您的 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 跨集群服务的反馈。加入社区:
请尝试使用跨集群服务,并告诉我们您的体验如何!