本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
使用 Kubernetes 集群联邦构建全球分布式服务
在 Kubernetes 1.3 中,我们宣布了 Kubernetes 集群联邦并引入了跨集群服务发现的概念,使开发人员能够部署一个跨越不同区域、地区或云提供商的联邦集群的服务。这使开发人员能够为他们的应用程序实现更高的可用性,而不会牺牲服务质量,正如我们之前的博客文章所详述的那样。
在最新版本 Kubernetes 1.4 中,我们扩展了集群联邦以支持 Replica Sets、Secrets、Namespaces 和 Ingress 对象。这意味着您不再需要单独在每个联邦集群中部署和管理这些对象。只需在联邦中创建一次,其内置控制器将自动为您处理。
联邦副本集利用与非联邦 Kubernetes 副本集相同的配置,并自动将 Pod 分布到一个或多个联邦集群中。默认情况下,副本均匀分布在所有集群中,但在不希望如此的情况下,我们引入了副本集偏好设置,允许副本仅分布在某些集群中,或以非相等比例分布(定义注解)。
从 Google Cloud Platform (GCP) 开始,我们引入了 联邦 Ingress 作为 Kubernetes 1.4 的 Alpha 功能,它允许外部客户端指向单个 IP 地址,并将请求发送到联邦中任何区域、区域中具有可用容量的最近集群。
联邦 Secret 自动在联邦的所有集群中创建和管理 Secret,自动确保这些 Secret 在全局范围内保持一致和最新,即使在应用原始更新时某些集群处于离线状态。
联邦 Namespace 与传统的 Kubernetes Namespace 类似,提供相同的功能。在联邦控制平面中创建它们可确保它们在联邦的所有集群中同步。
联邦事件 与传统的 Kubernetes 事件类似,提供相同的功能。联邦事件仅存储在联邦控制平面中,不会传递给底层 Kubernetes 集群。
让我们来看看这一切是如何运作的。我们将为每个区域配置 3 个集群,跨越 3 个大陆(欧洲、北美和亚洲)。
下一步是联邦这些集群。Kelsey Hightower 开发了一个教程,用于设置 Kubernetes 集群联邦。按照教程配置一个集群联邦,其中包含 us-central1、europe-west1 和 asia-east1 这 3 个 GCP 区域中每个区域的 3 个区域中的集群。为了这篇博客文章的目的,我们将在 us-central1-b 区域中配置联邦控制平面。请注意,也有更高可用性的多集群部署可用,但为了简单起见,这里未使用。
本博客文章的其余部分假设您已配置好一个正在运行的 Kubernetes 集群联邦。
让我们验证一下我们是否有 9 个集群在 3 个区域中运行。
$ kubectl --context=federation-cluster get clusters
NAME STATUS AGE
gce-asia-east1-a Ready 17m
gce-asia-east1-b Ready 15m
gce-asia-east1-c Ready 10m
gce-europe-west1-b Ready 7m
gce-europe-west1-c Ready 7m
gce-europe-west1-d Ready 4m
gce-us-central1-a Ready 1m
gce-us-central1-b Ready 53s
gce-us-central1-c Ready 39s
您可以在此处下载此博客文章中使用的源代码。源代码包含以下文件 | |
---|---|
configmaps/zonefetch.yaml | 从实例元数据服务器检索区域并将其连接到卷挂载路径中 |
replicasets/nginx-rs.yaml | 部署一个由 nginx 和 busybox 容器组成的 Pod |
ingress/ingress.yaml | 创建一个具有全局 VIP 的负载均衡器,将请求分发到最近的 nginx 后端 |
services/nginx.yaml | 将 nginx 后端作为外部服务暴露 |
在我们的示例中,我们将使用联邦控制平面部署服务和 ingress 对象。ConfigMap 对象目前不受联邦支持,因此我们将在每个底层联邦集群中手动部署它。我们的集群部署将如下所示
我们将部署一个跨 9 个集群分片的服务。后端部署将由一个带有 2 个容器的 Pod 组成
- busybox 容器,用于获取区域并将带有区域的 HTML 输出到 Pod 卷挂载路径中
- nginx 容器,用于从 Pod 卷挂载路径读取并提供包含其运行区域的 HTML
让我们首先在 federation-cluster 上下文中创建一个联邦服务对象。
$ kubectl --context=federation-cluster create -f services/nginx.yaml
服务传播到 9 个集群需要几分钟。
$ kubectl --context=federation-cluster describe services nginx
Name: nginx
Namespace: default
Labels: app=nginx
Selector: app=nginx
Type: LoadBalancer
IP:
LoadBalancer Ingress: 108.59.xx.xxx, 104.199.xxx.xxx, ...
Port: http 80/TCP
NodePort: http 30061/TCP
Endpoints: <none>
Session Affinity: None
现在让我们创建一个联邦 Ingress。联邦 Ingress 的创建方式与传统 Kubernetes Ingress 大致相同:通过进行 API 调用来指定您逻辑入口点的所需属性。对于联邦 Ingress,此 API 调用指向联邦 API 端点,而不是 Kubernetes 集群 API 端点。联邦 Ingress 的 API 与传统 Kubernetes 服务的 API 100% 兼容。
$ cat ingress/ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx
spec:
backend:
serviceName: nginx
servicePort: 80
$ kubectl --context=federation-cluster create -f ingress/ingress.yaml
ingress "nginx" created
创建后,联邦 Ingress 控制器会自动
- 1.在您的集群联邦下的每个集群中创建匹配的 Kubernetes Ingress 对象
- 2.确保所有这些集群内 Ingress 对象共享相同的逻辑全局 L7(即 HTTP(S))负载均衡器和 IP 地址
- 3.监控此 Ingress 后面的每个集群中服务“分片”(即您的 Pod)的健康状况和容量
- 4.确保在任何时候,即使发生 Pod、集群、可用区或区域中断,所有客户端连接都路由到适当的健康后端服务终结点。我们可以验证底层集群中的 Ingress 对象是否匹配。请注意,所有 9 个集群的 Ingress IP 地址都是相同的。
$ for c in $(kubectl config view -o jsonpath='{.contexts[*].name}'); do kubectl --context=$c get ingress; done
NAME HOSTS ADDRESS PORTS AGE
nginx \* 80 1h
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 40m
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 1h
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 26m
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 1h
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 25m
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 38m
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 3m
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 57m
NAME HOSTS ADDRESS PORTS AGE
nginx \* 130.211.40.xxx 80 56m
请注意,在 Google Cloud Platform 的情况下,逻辑 L7 负载均衡器不是单个物理设备(这将导致单点故障和单个全球网络路由瓶颈),而是一个真正的全球、高可用负载均衡托管服务,可通过单个静态 IP 地址全局访问。
您的联邦 Kubernetes 集群内部的客户端(即 Pod)将自动路由到其集群中支持 Ingress 的联邦服务的集群本地分片(如果存在且健康),或者在不存在的情况下路由到不同集群中最近的健康分片。请注意,这涉及到对 HTTP(S) 负载均衡器的网络往返,该负载均衡器位于您的本地 Kubernetes 集群之外,但位于相同的 GCP 区域内。
下一步是调度服务后端。让我们首先在联邦中的每个集群中创建 ConfigMap。
我们通过将 ConfigMap 提交到联邦中的每个集群来完成此操作。
$ for c in $(kubectl config view -o jsonpath='{.contexts[\*].name}'); do kubectl --context=$c create -f configmaps/zonefetch.yaml; done
让我们快速查看一下我们的 Replica Set
$ cat replicasets/nginx-rs.yaml
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: nginx
labels:
app: nginx
type: demo
spec:
replicas: 9
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: frontend
ports:
- containerPort: 80
volumeMounts:
- name: html-dir
mountPath: /usr/share/nginx/html
- image: busybox
name: zone-fetcher
command:
- "/bin/sh"
- "-c"
- "/zonefetch/zonefetch.sh"
volumeMounts:
- name: zone-fetch
mountPath: /zonefetch
- name: html-dir
mountPath: /usr/share/nginx/html
volumes:
- name: zone-fetch
configMap:
defaultMode: 0777
name: zone-fetch
- name: html-dir
emptyDir:
medium: ""
Replica Set 由 9 个副本组成,均匀分布在集群联邦中的 9 个集群中。注释也可以用于控制 Pod 调度到哪些集群。这可以通过在 Replica Set 规范中添加注释来完成,如下所示
apiVersion: extensions/v1beta1
kind: ReplicaSet
metadata:
name: nginx-us
annotations:
federation.kubernetes.io/replica-set-preferences: ```
{
"rebalance": true,
"clusters": {
"gce-us-central1-a": {
"minReplicas": 2,
"maxReplicas": 4,
"weight": 1
},
"gce-us-central10b": {
"minReplicas": 2,
"maxReplicas": 4,
"weight": 1
}
}
}
为了演示目的,我们将保持简单,将 Pod 均匀分布在集群联邦中。
让我们创建联邦 Replica Set
$ kubectl --context=federation-cluster create -f replicasets/nginx-rs.yaml
验证每个集群中是否创建了 Replica Set 和 Pod
$ for c in $(kubectl config view -o jsonpath='{.contexts[\*].name}'); do kubectl --context=$c get rs; done
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 42s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 14m
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 45s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 46s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 47s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 48s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 49s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 49s
NAME DESIRED CURRENT READY AGE
nginx 1 1 1 49s
$ for c in $(kubectl config view -o jsonpath='{.contexts[\*].name}'); do kubectl --context=$c get po; done
NAME READY STATUS RESTARTS AGE
nginx-ph8zx 2/2 Running 0 25s
NAME READY STATUS RESTARTS AGE
nginx-sbi5b 2/2 Running 0 27s
NAME READY STATUS RESTARTS AGE
nginx-pf2dr 2/2 Running 0 28s
NAME READY STATUS RESTARTS AGE
nginx-imymt 2/2 Running 0 30s
NAME READY STATUS RESTARTS AGE
nginx-9cd5m 2/2 Running 0 31s
NAME READY STATUS RESTARTS AGE
nginx-vxlx4 2/2 Running 0 33s
NAME READY STATUS RESTARTS AGE
nginx-itagl 2/2 Running 0 33s
NAME READY STATUS RESTARTS AGE
nginx-u7uyn 2/2 Running 0 33s
NAME READY STATUS RESTARTS AGE
nginx-i0jh6 2/2 Running 0 34s
下图是 nginx 服务和相关 Ingress 的部署示意图。总结一下,我们使用全局 L7 负载均衡器暴露了一个全局 VIP(130.211.23.176),该负载均衡器将请求转发到具有可用容量的最近集群。
为了测试这一点,我们将在 us-west1-b 和 asia-east1-a 各启动一个 Google Compute Engine (GCE) 实例。所有客户端请求都会通过最短的网络路径自动路由到距离请求源最近的集群中健康的 Pod。因此,例如,来自亚洲的 HTTP(S) 请求将直接路由到亚洲最近的具有可用容量的集群。如果亚洲没有这样的集群,请求将路由到下一个最近的集群(本例中是美国)。这无论请求是来自 GCE 实例还是互联网上的任何其他地方都适用。我们在演示中仅使用 GCE 实例是为了简化操作。
我们可以使用 Cloud Console 或发出 gcloud SSH 命令直接 SSH 到虚拟机中。
$ gcloud compute ssh test-instance-asia --zone asia-east1-a
-----
user@test-instance-asia:~$ curl 130.211.40.186
<!DOCTYPE html>
<html>
<head>
<title>Welcome to the global site!</title>
</head>
<body>
<h1>Welcome to the global site! You are being served from asia-east1-b</h1>
<p>Congratulations!</p>
user@test-instance-asia:~$ exit
----
$ gcloud compute ssh test-instance-us --zone us-west1-b
----
user@test-instance-us:~$ curl 130.211.40.186
<!DOCTYPE html>
<html>
<head>
<title>Welcome to the global site!</title>
</head>
<body>
<h1>Welcome to the global site! You are being served from us-central1-b</h1>
<p>Congratulations!</p>
----
Kubernetes 集群联邦可以包含运行在不同云提供商(例如 GCP、AWS)和本地(例如 OpenStack)的集群。然而,在 Kubernetes 1.4 中,联邦 Ingress 仅支持跨 Google Cloud Platform 集群。在未来版本中,我们打算支持基于混合云 Ingress 的部署。
总而言之,我们通过利用 Kubernetes 1.4 联邦 Ingress Alpha 功能,部署了一个位于全局负载均衡器后的多宿主服务。外部客户端指向一个 IP 地址,并被发送到联邦中任何区域、地区中具有可用容量的最近集群,从而在不牺牲延迟或操作简便性的情况下提供更高级别的可用性。
我们很乐意听取关于 Kubernetes 跨集群服务的反馈。要加入社区
- 在 GitHub 上发布问题或功能请求
- 加入 Slack 上的 #federation 频道
- 参与 集群联邦 SIG
- 下载 Kubernetes
- 在 Twitter 上关注 Kubernetes @Kubernetesio 获取最新更新