这篇文章已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已失效。
跨集群服务 - 为 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 的教程,其中详细介绍了相关步骤。
联邦服务 (Federated Services)
联邦服务 (Federated Services) 指向联邦 API 端点,并指定您服务的期望属性。
创建后,联邦服务 (Federated Service) 会自动
- 在构成集群联邦的每个集群中创建匹配的 Kubernetes Service,
- 监控这些服务“分片”(以及它们所在的集群)的健康状态,并且
- 在公共 DNS 提供商(如 Google Cloud DNS 或 AWS Route 53)中管理一组 DNS 记录,从而确保联邦服务的客户端在任何时候都能无缝地找到合适的健康服务终结点,即使发生集群、可用区或地域中断。
您的联邦 Kubernetes 集群内部的客户端(即 Pod)如果联邦服务的本地分片存在且健康,将自动找到该分片;如果不存在,则将找到不同集群中最接近的健康分片。
Kubernetes 集群联邦可以包含在不同云提供商(例如 GCP、AWS)以及本地(例如在 OpenStack 上)运行的集群。您只需在相应的云提供商和/或位置创建集群,并将每个集群的 API 端点和凭据注册到您的 Federation API Server。
在我们的示例中,我们在 4 个地域创建了集群,并在其中一个集群中部署了联邦控制平面 API,我们将使用它来供应我们的服务。请参阅下图以获得直观表示。
创建联邦服务 (Federated Service)
让我们列出联邦中的所有集群
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' 的上下文。基础服务的名称和命名空间将自动与您上面创建的联邦服务的名称和命名空间匹配。
您的联邦服务 (Federated Service) 的状态将自动反映基础 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 入口”地址与所有基础 Kubernetes 服务的“LoadBalancer 入口”地址相对应。为了使服务分片之间的跨集群和跨云提供商网络正常工作,您的服务需要具有外部可见的 IP 地址。此处通常使用服务类型:LoadBalancer。
另请注意,我们尚未供应任何后端 Pod 来接收指向这些地址的网络流量(即“服务终结点”),因此联邦服务尚未将这些视为健康的服务分片,也因此尚未将其地址添加到此联邦服务的 DNS 记录中。
添加后端 Pod
为了使基础服务分片变为健康,我们需要在它们后面添加后端 Pod。目前这直接通过基础集群的 API 端点完成(尽管将来 Federation server 将能够通过单个命令为您完成所有这些操作,从而省去麻烦)。例如,要在我们的基础集群中创建后端 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 发现联邦服务 (Federated Service)
默认情况下,Kubernetes 集群预配置了集群本地 DNS 服务器 ('KubeDNS'),以及一个智能构建的 DNS 搜索路径,它们共同确保您的软件在 Pod 内部发出的 DNS 查询(如 "myservice", "myservice.mynamespace", "bobsservice.othernamespace" 等)能够自动正确地扩展并解析到本地集群中运行的服务的相应服务 IP。
随着联邦服务 (Federated Services) 和跨集群服务发现的引入,此概念得到扩展,涵盖了在您的集群联邦中任何其他集群(全球范围内)运行的 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 服务在世界任何地方最接近的健康分片。如果本地集群中存在健康的 sharg,则会返回该服务的集群本地(通常为 10.x.y.z)IP 地址(由集群本地 KubeDNS 返回)。这与非联邦服务解析完全等效。
如果本地集群中不存在该服务(或者存在但没有健康的后端 Pod),DNS 查询会自动扩展为 "nginx.mynamespace.myfederation.svc.us-central1-a.example.com"。在幕后,这会找到最接近我的可用区的一个分片的外部 IP。此扩展由 KubeDNS 自动执行,它返回相关的 CNAME 记录。这会导致在上述示例中遍历 DNS 记录的层次结构,最终指向本地 us-central1 地域中联邦服务 (Federated Service) 的一个外部 IP。
还可以通过明确指定适当的 DNS 名称,而不是依赖自动 DNS 扩展,来定位 Pod 本地可用区和地域之外的服务分片。例如,"nginx.mynamespace.myfederation.svc.europe-west1.example.com" 将解析到欧洲所有当前健康的服务分片,即使发出查找的 Pod 位于美国,无论美国是否存在该服务的健康分片。这对于远程监控及其他类似应用非常有用。
从联邦集群外部的其他客户端发现联邦服务 (Federated Service)
对于外部客户端,上述自动 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 Cluster Federation 自动为您处理。
处理后端 Pod 和整个集群的故障
标准 Kubernetes 服务集群 IP 已确保无响应的单个 Pod 终结点能够以低延迟自动下线。Kubernetes 集群联邦系统自动监控集群的健康状况以及联邦服务所有分片背后的终结点,根据需要将分片投入或撤出服务。由于 DNS 缓存固有的延迟(联邦服务 DNS 记录的缓存超时或 TTL 默认为 3 分钟,但可调整),在发生灾难性故障时,所有客户端完全故障转移到备用集群可能需要长达这段时间。然而,考虑到每个地域服务终结点可以返回的离散 IP 地址数量(例如参见上面的 us-central1,它有三个备选地址),在适当配置的情况下,许多客户端将在比这更短的时间内自动故障转移到其中一个备选 IP。
社区
我们很乐意听取关于 Kubernetes Cross Cluster Services 的反馈。要加入社区
请尝试使用 Cross Cluster Services,并告诉我们进展如何!