federation机制的最新发布_基于Federation实现Kubernetes跨集群应用调度实践

27b3a1e4c09783bbff114f0e17e289db.png

1 Kubernetes Federation介绍

1.1 Kubenetes Federation概述

Kubernetes Federation实现在混合云模式下统一管理多个跨region或者跨公有云供应商的Kubernetes集群,使Kubernetes应用支持在多个跨区域集群之间部署、调度以及同步,从而实现应用的高可用以及灾备的效果。

b90cfc9e1538cddada47586580f38551.png

Kubernetes Federation主要包含如下两大核心功能:

  • 跨集群资源同步。Federation实现了跨多个集群的资源同步,比如可以实现同时在多个集群部署相同的Deployment。

  • 跨集群服务发现。Federation基于跨集群的服务发现自动配置与发布DNS,从而使应用实现跨多个集群的负载均衡。

通过Federation可以解决如下单一Kubernetes集群的问题:

  1. Kubernetes应用容灾。虽然Kubernetes通过多副本机制实现了应用的高可用,但单个集群难以避免由于Kubernetes集群本身故障导致应用崩溃的问题。通过Federation可以实现当单个Kubernetes故障时,自动把应用流量切换到另一个Kubernetes集群上,从而保持应用的连续性。

  2. 应用在不同地理位置的低延时访问。通过DNS负载策略或者CDN可以实现应用就近访问,从而减少应用访问的网络延迟。

  3. 避免应用对某个集群的强耦合。通过Federation可以实现应用在多个集群之间进行方便快速迁移,如果集群升级,也完全不会影响应用的连续性。

  4. 集群可扩展性。虽然Kubernetes实现了很好的节点级别的水平扩展能力,但当集群节点达到一定的规模后,Pod和Service数量巨大导致iptables规则过多,从而使网络性能大幅度下降。通过Federation可实现集群级别的水平扩展能力。

  5. 实现应用在混合云架构下部署。通过Federation实现应用能够在私有云、多云上同时部署,能够充分利用混合云模式的优势,比如公有云成本优化、避免公有云厂商绑定等等。

1.2 Kubernetes Federation架构

早期的Federation v1由于无法兼容Kubernetes最新API以及不支持RBAC等原因已经被完全废弃,目前官方推荐使用Kubernetes Federation V2版本,因此本文将以v2为例。

其架构图如下:

6b049b7b34816d1e7b7644952f95a113.png

KubeFed要配置两类内容:

  • Type configuration:定义哪些Kubernetes资源需要被KubeFed管理,比如要实现ConfigMap资源通过联邦机制管理就必须先通过CRD建立新资源FederatedConfigMap,然后创建名称为configmaps的Type configuration(FederatedTypeConfig)资源,并描述ConfigMap要被FederatedConfigMap所管理,这样KubeFed Controllers才能知道如何建立Federated资源。

  • Cluster configuration声明了KubeFed纳管的集群信息。

对于Cluster configuration又包含了三种类型:

  • Templates定义了跨集群资源的描述信息;

  • Placement定义了跨集群资源的放置信息;

  • Overrides定义了模板字段级的变化信息。

通过上面的资源类型实现跨Kubernetes集群的资源统一调度部署及服务DNS配置。本文后续章节将从Federation安装配置、跨集群应用部署、跨集群的服务发现三个方面进行实践。

2 Kubernetes Federation配置

2.1 Federation安装配置

Federation本身也是可运行在Kubernetes平台之上的,实际生产中应该规划把Federation控制平面部署在哪个Kubernetes集群中,建议放到一个单独的Kubernetes集群中,避免和应用混合运行。

本文由于仅作为测试,因此选择在cluster1集群中进行Federation控制平面的部署。

首先安装kubefedctl,kubefedctl提供命令行工具与Federation API进行交互:

VERSION=0.1.0-rc6

OS=linux

ARCH=amd64

curl -LO https://github.com/kubernetes-sigs/kubefed/releases/download/v${VERSION}/kubefedctl-${VERSION}-${OS}-${ARCH}.tgz

tar -zxvf kubefedctl-*.tgz

chmod u+x kubefedctl

sudo mv kubefedctl /usr/local/bin/

在Kubernetes集群上准备好helm并配置RBAC相关内容。

$ cat << EOF | kubectl apply -f -

apiVersion: v1

kind: ServiceAccount

metadata:

name: tiller

namespace: kube-system

---

apiVersion: rbac.authorization.k8s.io/v1

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

$ helm init --service-account tiller

$ helm repo add kubefed-charts https://raw.githubusercontent.com/kubernetes-sigs/kubefed/master/charts

$ helm search kubefed

通过helm进行kubeFed的安装部署。(TIPS:在此使用helm search时由于helm不识别rc版本,因此列出版本不是最新的)

$ helm install kubefed-charts/kubefed --name kubefed --version=0.1.0-rc6 --namespace kube-federation-system

检查发现kubeFed已经正常运行。

$ kubectl get pod -n kube-federation-system

NAME READY STATUS RESTARTS AGE

kubefed-admission-webhook-554b6bc659-l6xq6 1/1Running04h8m

kubefed-controller-manager-64b4d7ddb5-7hvb41/1Running04h8m

kubefed-controller-manager-64b4d7ddb5-jtb4t 1/1Running04h8m

2.2 添加Kubernetes集群到Federation

可通过kubefedctl添加两个集群到Federation:

$ kubefedctl join cluster1 --cluster-context cluster1 --host-cluster-context cluster1 --v=2

$ kubefedctl join cluster2 --cluster-context cluster2 --host-cluster-context cluster1 --v=2

查看集群的状态:

$ kubectl get kubefedclusters --all-namespaces

NAMESPACE NAME READY AGE

kube-federation-system cluster1 True5m3s

kube-federation-system cluster2 True4m31s

如上READY如果输出为 True,说明配置就绪。

3 Kubernetes Federation应用部署

3.1 准备样例资源

官方提供了很好的样例,为了验证我们直接下载官方的资源:

git clone https://github.com/kubernetes-sigs/kubefed.git

并创建我们要使用的namespaces。

kubectl apply -f example/sample1/namespace.yaml \

-f example/sample1/federatednamespace.yaml

3.2 创建configmap资源

部署跨集群的configmap,所使用的yaml为:

apiVersion: types.kubefed.io/v1beta1

kind: FederatedConfigMap

metadata:

name: test-configmap

namespace: test-namespace

spec:

template:

data:

A: ala ma kota

placement:

clusters:

- name: cluster2

- name: cluster1

overrides:

- clusterName: cluster2

clusterOverrides:

- path: /data

value:

foo: bar

创建完成后,在cluster1集群上看到已经正常创建:

$ kubectl get configmap -n test-namespace

NAME DATA AGE

test-configmap 129m

在cluster2集群上也已经正常创建,验证了configmap在多个集群上同时创建:

$ kubectl get configmap -n test-namespace

NAME DATA AGE

test-configmap 129m

但注意,在yaml文件里写了 override, override可实现不同集群的配置不同,如果没有 override所有集群的资源配置完全一样。

这里我们在cluster2上配置的具体内容和cluster1的并不相同。对于cluster1,configmap的data内容为:

$ kubectl describe configmap/test-configmap -n test-namespace

Name: test-configmap

Namespace: test-namespace

Labels: kubefed.io/managed=true

Annotations:

Data

====

A:

----

ala ma kota

Events:

对于cluster2,configmap的data内容为:

$ kubectl describe configmap/test-configmap -n test-namespace

Name: test-configmap

Namespace: test-namespace

Labels: kubefed.io/managed=true

Annotations:

Data

====

foo:

----

bar

Events:

3.3 创建deployment资源

3.3.1 创建单个集群deployment

首先在cluster1上进行创建单个集群的deployment,所使用yaml为:

apiVersion: apps/v1

kind: Deployment

metadata:

name: nginx

labels:

app: nginx

spec:

replicas: 1

selector:

matchLabels:

app: nginx

template:

metadata:

labels:

app: nginx

spec:

containers:

- image: nginx

name: nginx

volumeMounts:

- name: web-file

mountPath: /usr/share/nginx/html/

volumes:

- name: web-file

configMap:

name: web-file

创建完成后,在cluster1集群上,可以看到已经正常创建。

$ kubectl get deployment

NAME READY UP-TO-DATE AVAILABLE AGE

nginx 1/11150m

在cluster2集群上,满足预期,并没有创建这个deployment。

$ kubectl get deployment

No resources found indefaultnamespace.

3.3.2 创建跨集群的deployment

部署跨集群的deployment,所使用的yaml为:

apiVersion: types.kubefed.io/v1beta1

kind: FederatedDeployment

metadata:

name: test-deployment

namespace: test-namespace

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: cluster2

- name: cluster1

overrides:

- clusterName: cluster2

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

- path: "/metadata/annotations/foo"

op: "remove"

创建完成后,在cluster1集群上看到已经正常创建:

$ kubectl get deployment -n test-namespace

NAME READY UP-TO-DATE AVAILABLE AGE

test-deployment 3/333167m

在cluster2集群上也已经正常创建,说明Deployment资源在多个集群上同时创建了:

$ kubectl get deployment -n test-namespace

NAME READY UP-TO-DATE AVAILABLE AGE

test-deployment 5/555167m

这里我们也配置了 override,因此cluster1的副本数是3,而cluster2的副本数是5,且cluster2的容器镜像版本为nginx:1.17.0-alpine

$ kubectl describe pod/test-deployment-7bdd764dcd-8m4rk-n test-namespace

...

Containers:

nginx:

Container ID: docker://3881259dd285ae0e05dfc374e6a8c707ee74978b870e74b9eb3936c2d94e6263

Image: nginx:1.17.0-alpine

可见通过联邦集群实现了deployment资源在不同集群中的部署并能实现不同集群的配置不一样。

3.4 创建其它类型的资源

同样的模式,可以跨集群创建不同类型的资源,包括service、serviceaccount、job、secrets等资源的跨集群创建,如果不指定overrides,则在两个集群下部署的内容相同;如果指定overrides,则可以实现不同集群下资源差异化配置。

3.5 更新资源配置

可以针对已经部署在cluster1和cluster2集群上的资源进行配置更新。

3.5.1 从cluster2集群中把部署资源删除

从placement中删除cluster2:

$ kubectl -n test-namespace patch federatednamespace test-namespace \

--type=merge -p '{"spec": {"placement": {"clusters": [{"name": "cluster1"}]}}}'

可以看到,部署在cluster2上的资源已经在进行删除。

$ kubectl get pod --all-namespaces

NAMESPACE NAME READY STATUS RESTARTS AGE

test-namespace test-deployment-7bdd764dcd-vsvt8 0/1Terminating03h26m

test-namespace test-deployment-7bdd764dcd-zrwc8 0/1Terminating03h26m

test-namespace test-job-r8gkd 1/1Terminating03h26m

test-namespace test-job-z5ngq 1/1Terminating03h26m

3.5.2 把cluster2集群的资源添加回来

在placement中添加cluster2:

$ kubectl -n test-namespace patch federatednamespace test-namespace \

--type=merge -p '{"spec": {"placement": {"clusters": [{"name": "cluster1"}, {"name": "cluster2"}]}}}'

可以看到在cluster2的资源重新部署上。

$ kubectl get pod -n test-namespace

NAME READY STATUS RESTARTS AGE

test-deployment-7bdd764dcd-2z47c1/1Running049s

test-deployment-7bdd764dcd-458v81/1Running049s

test-deployment-7bdd764dcd-82gw91/1Running049s

test-deployment-7bdd764dcd-rvlnh 1/1Running049s

test-deployment-7bdd764dcd-w7qpt 1/1Running049s

test-job-8hbjg1/1Running049s

test-job-t69xz 1/1Running049s

3.5.3 修改federateddeployments的副本数

修改federateddeployments的副本数:

$ kubectl edit federateddeployments -n test-namespace

template:

metadata:

labels:

app: nginx

spec:

replicas: 6

selector:

matchLabels:

app: nginx

template:

metadata:

labels:

app: nginx

可以看到在cluster1中副本数已经调整为6。

$ kubectl get pod -n test-namespace

NAME READY STATUS RESTARTS AGE

test-deployment-86c57db685-9tfmr1/1Running045s

test-deployment-86c57db685-g895p 1/1Running045s

test-deployment-86c57db685-hkxsc 1/1Running045s

test-deployment-86c57db685-j284m 1/1Running03h53m

test-deployment-86c57db685-stl9l 1/1Running03h53m

test-deployment-86c57db685-xxfm9 1/1Running045s

但由于overrides的存在,而在cluster2上还只有5个副本,符合预期。

$ kubectl get pod -n test-namespace

NAME READY STATUS RESTARTS AGE

test-deployment-7bdd764dcd-2z47c1/1Running022m

test-deployment-7bdd764dcd-458v81/1Running022m

test-deployment-7bdd764dcd-82gw91/1Running022m

test-deployment-7bdd764dcd-rvlnh 1/1Running022m

test-deployment-7bdd764dcd-w7qpt 1/1Running022m

4 跨集群服务发现

4.1 架构分析

对于Federation集群,需要考虑多个集群下的服务如何暴露给互联网的问题。而此时会通过DNS进行服务地址的解析。

在下图中,DNS Provider即提供了DNS的解析服务,而DNS有能力根据权重、位置、路由策略等分类,实现把同一个域名解析到不同的集群的服务上,因此后面需要解决Federation k8s集群和DNS联动的问题。

此时通过ExternalDNS组件来实现容器平台上的服务与DNS自动化配置的过程。对于非联邦的k8s集群,ExternalDNS可以直接发现service/ingress类型的资源,并直接把域名在DNS Provider上进行配置,而对于联邦的集群,需要引入了一个中间层,这个中间层有两种类型:一种是监控ingress,一种是监控service。这两种类型实现原理都相同,只是监控的资源不相同而已。

(1)Service类型。

首先集群会建立一个FederatedDeployment类型资源,然后建立了FederatedService,这与上面章节的演示内容相同。然后,为了让ExternalDNS能自动感知,建立Domain类型资源和ServiceDNSRecord类型资源,此时KubeFed的通过Service DNS Controller来收集Service的信息,并更新至ServiceDNSRecord中,接着DNS Endpoint Controller会依据该ServiceDNSRecord的状态内容,建立一个DNSEndpoint文件,并产生DNS records资源,最后再由ExternalDNS来同步更新DNS records至DNS供应商。

ebf2b81c75981d1c34558f96aa7d8da1.png

(2)Ingress类型

若是Ingress 的话,会由IngressDNSRecord 文件取代,并由Ingress DNS Controller 收集信息。其余与上图架构相同。

4.2 环境准备

为了实现面向互联网暴露的服务可以调度到Federation集群中的不同集群,需要配置DNS来进行解析。方案采用了ExternalDNS组件,与DNS provider进行联动,从而实现DNS服务器上的自动配置。

本演示环境使用了AWS的route53服务。

4.3 ExternalDNS配置

首先,配置ExternalDNS所需要的IAM policy。

{

"Version": "2012-10-17",

"Statement": [

{

"Effect": "Allow",

"Action": [

"route53:ChangeResourceRecordSets"

],

"Resource": [

"arn:aws:route53:::hostedzone/*"

]

},

{

"Effect": "Allow",

"Action": [

"route53:ListHostedZones",

"route53:ListResourceRecordSets"

],

"Resource": [

"*"

]

}

]

}

新建立IAM role,把上面的policy添加到role中,并把role赋予给虚拟机。

然后,使用命令行对AWS route53创建zone。

$ aws route53 create-hosted-zone --name "external-dns-test.cuizsh.com."--caller-reference "external-dns-test-$(date +%s)"

此时可以从route53的页面上看到已经创建出来对应的zone。

170534da070b8ffc87e5d57d7cb17d73.png

部署ExternalDNS,具体yaml文件如下。

apiVersion: v1

kind: ServiceAccount

metadata:

name: external-dns

namespace: kube-federation-system

---

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRole

metadata:

name: external-dns

rules:

- apiGroups: [""]

resources: ["services"]

verbs: ["get","watch","list"]

- apiGroups: [""]

resources: ["pods"]

verbs: ["get","watch","list"]

- apiGroups: ["extensions"]

resources: ["ingresses"]

verbs: ["get","watch","list"]

- apiGroups: [""]

resources: ["nodes"]

verbs: ["list", "get", "watch"]

- apiGroups: ["multiclusterdns.kubefed.io"]

resources: ["*"]

verbs: ["*"]

---

apiVersion: rbac.authorization.k8s.io/v1beta1

kind: ClusterRoleBinding

metadata:

name: external-dns-viewer

roleRef:

apiGroup: rbac.authorization.k8s.io

kind: ClusterRole

name: external-dns

subjects:

- kind: ServiceAccount

name: external-dns

namespace: kube-federation-system

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: external-dns

namespace: kube-federation-system

labels:

k8s-app: external-dns

spec:

replicas: 1

selector:

matchLabels:

k8s-app: external-dns

template:

metadata:

labels:

k8s-app: external-dns

spec:

serviceAccountName: external-dns

tolerations:

- key: CriticalAddonsOnly

operator: Exists

- effect: NoSchedule

key: node-role.kubernetes.io/master

containers:

- name: external-dns

image: registry.opensource.zalan.do/teapot/external-dns:latest

args:

- --source=service

- --source=ingress

- --domain-filter=external-dns-test.cuizsh.com ###change your own domain

- --provider=aws

- --policy=upsert-only

- --aws-zone-type=public

- --registry=txt

- --txt-owner-id=/hostedzone/Z1MJK86562DOQP ###change your hostzoneid

- --log-level=debug

- --txt-prefix=cname

- --source=crd

- --crd-source-apiversion=multiclusterdns.kubefed.io/v1alpha1

- --crd-source-kind=DNSEndpoint

检查可知,ExternalDNS已经部署完成。

$ kubectl get pod

NAME READY STATUS RESTARTS AGE

external-dns-56d5d4bc68-dz99d 1/1Running048s

对ExternalDNS进行验证,创建一个Service,验证是否可以自动在route53上创建对应记录。

创建Service的yaml如下。

apiVersion: v1

kind: Service

metadata:

name: nginx

annotations:

external-dns.alpha.kubernetes.io/hostname: nginx.external-dns-test.cuizsh.com

spec:

type: LoadBalancer

ports:

- port: 80

name: http

targetPort: 80

selector:

app: nginx

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: nginx

spec:

selector:

matchLabels:

app: nginx

template:

metadata:

labels:

app: nginx

spec:

containers:

- image: nginx

name: nginx

ports:

- containerPort: 80

name: http

创建完的Service如下:

$ kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP

nginx LoadBalancer10.100.143.66 ade41da1e50ad11ea84090e3f9ad3b4d-64143112.ap-northeast-1.elb.amazonaws.com 80:30314/TCP 95s

此时登录route53的console,发现已经自动添加A记录和TXT记录,证明ExternalDNS已经正常工作,可以自动实现服务与DNS的联动。

5b9c5cef63acbeb3f215b5bf5eee399e.png

3.5 Federation实现服务DNS发现

在上面章节已经创建了federatedservices类型的资源,这种类型的资源会在两个集群上都部署service。

$ kubectl get federatedservices --all-namespaces

NAMESPACE NAME AGE

test-namespace test-service 95m

此时可以看到两个集群上的service已经部署成功。

$ kubectl get svc -n test-namespace--context=cluster1

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

test-service LoadBalancer10.100.115.247 aa866f6b350c011ea84090e3f9ad3b4d-59219283.ap-northeast-1.elb.amazonaws.com 80:31618/TCP 97m

$ kubectl get svc -n test-namespace--context=cluster2

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

test-service LoadBalancer10.100.196.47 aa818f27550c011ea8c80064ff2fdab2-1423980564.ap-northeast-1.elb.amazonaws.com 80:31537/TCP 98m

然后创建Domain及ServiceDNSRecord类型资源。

$ cat <

apiVersion: multiclusterdns.kubefed.io/v1alpha1

kind: Domain

metadata:

# Corresponds to in the resource records.

name: test-domain

# The namespace running kubefed-controller-manager.

namespace: kube-federation-system

# The domain/subdomain that is setup in your externl-dns provider.

domain: external-dns-test.cuizsh.com

---

apiVersion: multiclusterdns.kubefed.io/v1alpha1

kind: ServiceDNSRecord

metadata:

# The name of the sample service.

name: test-service

# The namespace of the sample deployment/service.

namespace: test-namespace

spec:

# The name of the corresponding Domain.

domainRef: test-domain

recordTTL: 300

EOF

此时检查route53的页面,发现已经给test-service自动进行了DNS的配置,同时可以发现添加的记录类型为4条A记录。由于一个federatedservices对应了两个service,而每一个service又对应一个LoadBalancer,每一个 LoadBalancer默认分配了2个公网IP,因此共4个公网IP。

5cbb2db47206bb848559895e4f71299f.png

可见ExternalDNS已经实现自动化的把集群的服务调度到了两个集群的服务上去。

$ dig +short@ns-1513.awsdns-61.org test-service.test-namespace.test-domain.svc.external-dns-test.cuizsh.com

52.194.7.232

54.64.122.197

13.112.162.25

52.196.202.239

并且可以配置不同的权重及策略,实现不同方式的轮询。

86a49a1c4a5300c289231707e388d99f.png

5 小结

本文章验证了Kubernetes Federation的基本功能,包括环境的搭建、资源在多集群上的部署、DNS解析分发到多集群等内容。从技术成熟度上来看,该技术正在发展过程中;从目前公有云提供商提供的服务来看,目前也在采用类似的架构进行多容器集群的管理。但该方案在具体落地时还需要结合实际情况,例如,该方案目前实现的同一个资源在A集群部署m副本、在B集群部署n副本,但针对当A集群故障时,把m+n个副本都调度到B集群还需要再进行相关的配置。但整体来说,对于多个K8S集群的统一调度可以提供相关的参考 。

参考文档

  • https://github.com/kairen/aws-k8s-federation

  • https://www.kubernetes.org.cn/5702.html

  • https://github.com/kubernetes-sigs/kubefed

  • https://github.com/kubernetes-sigs/external-dns

作者介绍

  • 崔增顺:任职民生银行云技术管理中心,目前从事云平台相关探索及研究,熟悉私有云、公有云相关服务及架构。微信humanthinker,邮箱cuizengshun@cmbc.com.cn。

eba728ee5a409ebcba52281b0368a655.png  4f6ab95c671a637466b50d6563c741ce.png

作者:崔增顺

编辑:民生文化建设小组

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值