1. 背景
Amazon Elastic Kubernetes Service (Amazon EKS)是一项完全托管的Kubernetes服务,由于其安全性、可靠性和可扩展性,许多企业在 EKS上 运行任务关键型应用程序。而Amazon EKS默认的模式是以同region下单cluster形式对外提供服务,而随着环境的复杂多样和集群数量增长,企业不可避免地需要同时部署和运营多个集群,比如:
- 高可用性:通过跨集群分配负载并自动配置DNS服务器和负载平衡器,集群联邦可以最小化集群失败的影响,即使遇到某个区域连接中断或某个数据中心故障,也会保持最关键的服务运行。
- 低延迟:将集群放在不同Region中,为用户提供最近的集群应用服务来最小化延迟。
- 故障隔离:使用多个小集群而不是单个大集群进行故障隔离(例如:在aws的不同region中使用多个集群)。
- 可伸缩性:避免单个Kubernetes集群可伸缩性的限制。
- 混合云:在不同的云提供商或内部数据中心上拥有多个集群。
那么在这样的多集群环境下,企业如何通过一个统一的控制面板来实现Amazon EKS在多集群环境下服务的跨集群服务部署、服务发布、服务发现和全局调度,以及如何高效地管理和运维这些跨区域的集群成为企业面临的新问题。通过Kubernetes Federation,可以轻松实现Amazon EKS服务的多区域部署,以及对EKS不同区域的集群,甚至可以位于不同的云提供商或企业内部的Kubernetes集群进行集中管理。
2.Federation v2 简介
Federation(集群联邦)是k8s社区中重要的多云管理项目,实现了跨Region跨服务商管理多个k8s集群的功能。Federation允许从集中式主群集或主机群集控制多个K8S 群集目前社区有Federation v1和v2两个版本,v1已被官方强烈不推荐使用。Federation v2 利用 CRD 实现了整体功能,通过定义多种自定义资源(CR),从而省掉了 v1 的 API Server,但也因此引入了Host Cluster 的概念。
基本概念
- Federate:联邦(Federate)是指联结一组Kubernetes集群,并为其提供公共的跨集群部署和访问接口
- KubeFed:Kubernetes Cluster Federation,为用户提供跨集群的资源分发、服务发现和高可用
- Host Cluster:Host Cluster运行KubeFed控制平面,其中包含每个成员集群的KubeFedConfig和KubeFedCluster资源
- Cluster Registration:通过Kubefed join使得成员集群加入到主集群(Host Cluster)
- Member Cluster:通过KubeFed API注册为成员并受KubeFed管理的集群,主集群(Host Cluster)也可以作为成员集群(Member Cluster)
- ServiceDNSRecord: 记录Kubernetes Service信息,并通过DNS使其可以跨集群访问
- IngressDNSRecord:记录Kubernetes Ingress信息,并通过DNS使其可以跨集群访问
- DNSEndpoint:一个记录(ServiceDNSRecord/IngressDNSRecord 的Endpoint信息的自定义资源
工作原理
Federation v2 在架构上采用了流行的CRD+Controller模型运行在 Kubernetes 集群中,扩展了 k8s 的资源管理能力。 首先,它向原有k8s集群注册一系列 CRD 资源,这些 CRD 定义了联邦系统所支持的k8s资源;然后通过开启一个 ControllerManager来管理这些CRD资源,实现跨集群资源调度。 CRD资源和ControllerManager共同构成了Federation v2的Control Plane。 目前 Federation v2主要定义了 4 种CRD资源:
Cluster Configuration:主要定义了子集群注册时的配置信息。当用户执行 kubefedctl join命令将安装好的集群加入联邦时,federation-controller-manager 会自动读取新加入集群的 context 信息,生成Cluster Configuration信息;
Type Configuration:主要定义了Federation可以处理哪些资源对象。每个Type Configuration包括三个子配置项:
- Template:定义了Federation要处理的资源对象,含有该对象的全部信息;
- Placement:定义要将资源对象运行在哪些子集群中,如不定义该对象,则资源不会运行在任一集群;
- Override:针对不同集群的特殊需求,会重写覆盖Template中的内容;
Schedule:主要定义应用在集群中的调度分布,该类型主要涉及Deployment与Replicaset两种。用户可以定义对象在每个集群中分布的最多、最少实例数,并且还能在集群中做到应用实例数的均衡分布。值得注意的是,如果调度结果跟用户自定义的 Override冲突时,该调度算法享有优先权。例如用户Override 中定义为 5 个实例,实际调度结果只有 3 个,那么自定义的Override中5个实例将被改为3个。
MultiClusterDNS:该资源主要实现多集群间的服务发现,其下主要包含ServiceDNSRecord、IngressDNSRecord、DNSEndpoint这几个资源对象。
3.安装步骤
下面将介绍如何在Amazon EKS容器服务上搭建和使用Federation v2,完成如下步骤后的架构见下图。
1) 前置条件
开始前,需要先安装下列工具到操作机器上:
kubectl:用来操作部署完成的 EKS集群
sudo curl --silent --location -o /usr/local/bin/kubectl https://amazon-eks.s3-us-west-2.amazonaws.com/1.14.6/2019-08-22/bin/linux/amd64/kubectl
sudo chmod +x /usr/local/bin/kubectl
eksctl: 用来创建EKS集群
curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv -v /tmp/eksctl /usr/local/bin
helm: 用来部署 Federation v2 元件的工具。
curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > get_helm.sh
chmod +x get_helm.sh ./get_helm.sh
kubefedctl:用来新增与加入集群成为联邦的工具。
curl -LO https://github.com/kubernetes-sigs/kubefed/releases/download/v0.1.0-rc6/kubefedctl-0.1.0-rc6-linux-$amd64.tgz
tar -zxvf kubefedctl-*.tgz
chmod u+x kubefedctl sudo mv kubefedctl /usr/local/bin/
2) 创建EKS集群
目前KubeFed控制平面可以在任何v1.13或更高版本的EKS集群上运行。以下步骤仅在主群集上进行,该集群将控制所有其他集群,成员集群上无需进行任何配置,所有设置均由主集群来驱动。本文使用eksctl.io分别在两个region(us-east-2,ap-northeast-1)创建了两个集群,并将它们命名为cluster0,cluster1,其中cluster0充当主集群。
eksctl create cluster --name=cluster0 --nodes=2 --managed --alb-ingress-access --region=us-east-2
eksctl create cluster --name=cluster1 --nodes=2 --managed --alb-ingress-access --region=ap-northeast-1
3) 部署Helm 2
Helm 2依赖于一个名为tiller的服务,该服务需要在kubernetes集群上获得特殊许可,因此我们需要为tiller建立一个服务帐户。然后将其应用于集群。
创建一个新的服务帐户:
cat <<EoF > ~/environment/rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
EoF
应用配置:
kubectl apply -f ~/rbac.yaml
用helm tooling在集群中安装tiller,允许访问EKS集群中的资源
helm init --service-account tiller
安装kubefed Chart:首先,将KubeFed Chart存储库添加到本地存储库,然后安装。
helm repo add kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts
helm install kubefed-charts/kubefed --name kubefed --version=0.1.0-rc6 --namespace kube-federation-system
4) 转换kubectl的配置文件
为了将群集连接在一起,必须下载并安装一个单独的工具kubefedctl,且kubefedctl应该与Helm的版本匹配(当前版本为v0.1.0-rc6)。该工具会使用到kubectl的配置文件,以便正确验证并连接到其他成员集群中。但是当前版本kubefedctl并不能正确解析EKS默认生成YAML格式的config文件。因此,我们还需要手工调整了kubectl配置文件中所有大写和特殊字符,将大写字母转换为小写字母等。具体转换格式对比如下:
EKS生成的原始kubectl文件
clusters:
- cluster:
certificate-authority-data: XXXXXX
server: https://180FC6AD63608B8F7378E497E507458D.yl4.us-east-2.eks.amazonaws.com
name: cluster0.us-east-2.eksctl.io
- cluster:
certificate-authority-data: XXXXXXX
server: https://B8DB290F55BE6B845C3B74C00C6479D6.yl4.ap-northeast-1.eks.amazonaws.com
name: cluster1.ap-northeast-1.eksctl.io
contexts:
- context:
cluster: cluster0.us-east-2.eksctl.io
user: i-0ce31a1921dd19b2f@cluster0.us-east-2.eksctl.io
name: i-0ce31a1921dd19b2f@cluster0.us-east-2.eksctl.io
- context:
cluster: cluster1.ap-northeast-1.eksctl.io
user: i-0ce31a1921dd19b2f@cluster1.ap-northeast-1.eksctl.io
name: i-0ce31a1921dd19b2f@cluster1.ap-northeast-1.eksctl.io
current-context: i-0ce31a1921dd19b2f@cluster0.us-east-2.eksctl.io
kubefedctl工具所需的正确格式
clusters:
- cluster:
certificate-authority-data: XXXXXXXX
server: https://180fc6ad63608b8f7378e497e507458d.yl4.us-east-2.eks.amazonaws.com
name: cluster0
- cluster:
certificate-authority-data: XXXXXXXX
server: https://b8db290f55be6b845c3b74c00c6479d6.yl4.ap-northeast-1.eks.amazonaws.com
name: cluster1
contexts:
- context:
cluster: cluster0
user: i-0ce31a1921dd19b2f@cluster0.us-east-2.eksctl.io
name: cluster0
- context:
cluster: cluster1
user: i-0ce31a1921dd19b2f@cluster1.ap-northeast-1.eksctl.io
name: cluster1
current-context: cluster0
确认已经配置好kubeconfig,配置如下图所示:
kubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* cluster0 cluster0 i-0ce31a1921dd19b2f@cluster0.us-east-2.eksctl.io
cluster1 cluster1 i-0ce31a1921dd19b2f@cluster1.ap-northeast-1.eksctl.io
5)运行kubefedctl将集群加入集群联邦
kubefedctl join cluster0 --cluster-context cluster0 \ --host-cluster-context cluster0 --v=2
kubefedctl join cluster1 --cluster-context cluster1 \ --host-cluster-context cluster0 --v=2
Kubefed 是利用 CR 来存储自己所需要的数据,因此当使用 kubefedctl join 后,可以在 host cluster 查看到集群信息:
kubectl -n kube-federation-system get kubefedclusters
NAME READY AGE
cluster0 True 10d
cluster1 True 10d
检查在主群集上运行kubefed的所有 “CRD”:
kubectl get crd | grep kubefed.io | awk '{ print $1 }'
clusterpropagatedversions.core.kubefed.io
dnsendpoints.multiclusterdns.kubefed.io
domains.multiclusterdns.kubefed.io
federatedclusterroles.types.kubefed.io
federatedconfigmaps.types.kubefed.io
federateddeployments.types.kubefed.io
federatedingresses.types.kubefed.io
federatedjobs.types.kubefed.io
federatednamespaces.types.kubefed.io
federatedreplicasets.types.kubefed.io
federatedsecrets.types.kubefed.io
federatedserviceaccounts.types.kubefed.io
federatedservices.types.kubefed.io
federatedservicestatuses.core.kubefed.io
federatedtypeconfigs.core.kubefed.io
ingressdnsrecords.multiclusterdns.kubefed.io
kubefedclusters.core.kubefed.io
kubefedconfigs.core.kubefed.io
propagatedversions.core.kubefed.io
replicaschedulingpreferences.scheduling.kubefed.io
servicednsrecords.multiclusterdns.kubefed.io
6)在主机群集上创建本地名称空间
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: test
EOF
namespace/test created
7)在test名称空间中创建Federated名称空间
在部署资源之前,需要先创建 Federated 名称空间 ,federation集群的资源只会部署到被 kubefed 管理的 namespace 中
cat <<EOF | kubectl apply -f -
apiVersion: types.kubefed.io/v1beta1
kind: FederatedNamespace
metadata:
name: test
namespace: test
spec:
placement:
clusters:
- name: cluster0
- name: cluster1
EOF
federatednamespace.types.kubefed.io/test created
kubectl -n test get federatednamespaces
NAME AGE
test 43h
8)创建FederatedDeployment
cat <<EOF | kubectl apply -f -
apiVersion: types.kubefed.io/v1beta1
kind: FederatedDeployment
metadata:
name: test
namespace: test
spec:
template:
metadata:
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
name: nginx
placement:
clusters:
- name: cluster0
- name: cluster1
overrides:
- clusterName: cluster1
clusterOverrides:
- path: "/spec/replicas"
value: 5
- path: "/spec/template/spec/containers/0/image"
value: "nginx:1.17.0-alpine"
- path: "/metadata/annotations"
op: "add"
value:
foo: bar
EOF
federateddeployment.types.kubefed.io/test created
9)验证Federation集群
部署Deployment 之后,可以通过查看部署状态。
kubectl -n test describe federateddeployment.types.kubefed.io/test
通过查看cluster0和cluster1 deployment在不同集群间的差异,可以发现每个群集中的副本数不同。这是因为Kubefed 通过 overrides 字段实现不同集群间的差异化部署,deployment 已经按照预期在 cluster0 和 cluster1 正确部署。
kubectl --context cluster0 -n test get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
test 3/3 3 3 5m
kubectl --context cluster1 -n test get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
test 5/5 5 5 5m11s
4.结论
Ferderation v2是kubernetes非常强大的机制,可方便在多个集群上管理应用程序和服务。本文通过介绍如何在Amazon EKS容器服务上搭建Federation v2环境,通过Federration V2可以实现Amazon EKS服务的多区域部署,以及对Amazon EKS不同区域的集群进行管理,体验了使用Federation v2带来的多集群管理的便捷性。
虽然kubernetes集群联邦有很多有吸引力的功能和特点,但也有一些要注意的事项:
- 增加网络带宽和成本:集群联邦控制平面监视所有集群,以确保当前状态符合预期。如果集群运行在不同的云提供商的不同区域,这可能会导致巨大的网络成本。
- 减少跨集群隔离:集群联邦控制平面中的一个缺陷会影响所有集群功能。
- 成熟度:集群联邦项目相对较新,还不是很成熟。并不是所有的资源都是可用的,许多仍处于beta阶段。
5. 资料参考
https://github.com/kairen/aws-k8s-federation
https://github.com/kubernetes-sigs/kubefed/blob/master/charts/kubefed/README.md
https://github.com/kubernetes-sigs/kubefed/blob/master/docs/cluster-registration.md
本篇作者