1. 多集群构建 Tekton 的优势
借助于 Kubernetes, Tekton 已经具备很好的弹性, 能够支持大规模构建。同时, 开发 Task 主要使用 Yaml 和 Shell, 这扩大了 Tekton 的各种场景适配范围。
上面是一张 Tekton 在多集群下的示意图。为什么 Tekton 需要多集群执行流水线?
随时可变的 Kubernetes 集群。单一的 Kubernetes 集群, 无法满足运维的要求, 不能随时对集群进行变更。多集群下, 可以下架部分集群进行维护。 更大规模的构建。CI 对 CPU、内存、IO 资源的消耗很大, 容易压垮节点甚至集群。多集群能有效分担负载压力,提高可用性。 业务隔离。业务对代码安全等级、构建速度、构建环境要求不一样, 多集群能够提供隔离的环境, 定制化的流水线服务。 2. Kubernetes Cluster Federation
Kubernetes Cluster Federation 简称 KubeFed。KubeFed v2 相较于 v1 最大的改变是将 API Server 移除, 并且通过 CRD 机制完成 Federated Resource 的扩展。KubeFed Controller 管理这些 CRD, 并实现同步 Resources 跨集群编排等功能,实现模块化和定制化。下面是社区的架构图:
KubeFed 配置了两种类型的信息:
Type configuration, 声明 KubeFed 处理的 API 类型 Cluster configuration, 声明 KubeFed 管理哪些集群
Type configuration 有三个基本概念:
Templates, 定义资源在集群中的模板描述 Placement, 定义资源需要分发到哪些集群 Overrides, 定义在集群中,需要覆盖 Templates 的字段内容
此外,通过 Status、Policy 和 Scheduling 可以实现更高级的功能:
Status 收集分发资源在各个集群中的状态 Policy 允许将资源分配给哪些集群的策略控制 Scheduling 允许资源跨集群迁移副本
除此,KubeFed 还提供了 MultiClusterDNS,可以用于多集群之间的服务发现。
3. 联邦化 Kubernetes 集群 3.1 准备集群并配置 Context
这里部署两个集群: dev1 作为主集群,用来作为 Tekton 的控制面,不运行流水线任务; dev2 作为子集群,用来执行 Tekton 流水线任务。
准备两个集群
主集群 dev1
kubectlgetnodeNAMESTATUSROLESAGEVERSIONnode1Readycontrol-plane,master,worker151mv1.20.4 helmversionversion.BuildInfo{Version:\”v3.2.1\”,GitCommit:\”fe51cd1e31e6a202cba7dead9552a6d418ded79a\”,GitTreeState:\”clean\”,GoVersion:\”go1.13.10\”}
子集群 dev2
kubectlgetnodeNAMESTATUSROLESAGEVERSIONnode1Readycontrol-plane,master,worker42dv1.20.4
在主集群上配置全部集群的 Context(要求集群 Apiserver 入口在一个网络,能够直连),用来添加子集群
这里 contexts 中的 name 不能含义 @ 等特殊字符, 否则 join 时会报错。因为 name 会用来创建 Secret, 需要符合 Kubernetes 的命名规范。
将主集群 dev1 的 kubeconfig 放在 ~/.kube/config-1,并修改 name 等信息,格式如下:
apiVersion:v1clusters:-cluster:…name:dev1.cluster.localcontexts:-context:cluster:dev1.cluster.localuser:dev1-kubernetes-adminname:dev1-contextusers:-name:dev1-kubernetes-adminuser:…
将子集群 dev2 的 kubeconfig 放在 ~/.kube/config-2,并修改 name 等信息,格式如下:
apiVersion:v1clusters:-cluster:…name:dev2.cluster.localcontexts:-context:cluster:dev2.cluster.localuser:dev2-kubernetes-adminname:dev2-contextusers:-name:dev2-kubernetes-adminuser:…
合并 kubeconfig
cd$HOME/.kube/KUBECONFIG=config-1:config-2kubectlconfigview–flatten>$HOME/.kube/config
查看添加的集群 Context
kubectlconfigget-contextsCURRENTNAMECLUSTERAUTHINFONAMESPACEdev1-contextdev1.cluster.localdev1-kubernetes-admindev2-contextdev2.cluster.localdev2-kubernetes-admin
切换到主集群 dev1
kubectlconfiguse-contextdev1-contextSwitchedtocontext\”dev1-context\”. 3.2 在主集群上安装 KubeFed
使用 Helm 安装 KubeFed
gitclonehttps://github.com/kubernetes-sigs/kubefed.gitcdkubefed/charts/helminstallkubefed./kubefed/–namespacekube-federation-system–create-namespace
查看负载
kubectlgetdeploy,pod-nkube-federation-systemNAMEREADYUP-TO-DATEAVAILABLEAGEdeployment.apps/kubefed-admission-webhook1/11195sdeployment.apps/kubefed-controller-manager2/22295sNAMEREADYSTATUSRESTARTSAGEpod/kubefed-admission-webhook-598bd776c6-gv4qh1/1Running095spod/kubefed-controller-manager-6d9bf98d74-n8kjz1/1Running017spod/kubefed-controller-manager-6d9bf98d74-nmb2j1/1Running014s 3.3 在主集群上安装 kubefedctl
执行命令:
wgethttps://github.com/kubernetes-sigs/kubefed/releases/download/v0.8.0/kubefedctl-0.8.0-linux-amd64.tgztar-zxvfkubefedctl-*.tgzmvkubefedctl/usr/local/bin/ 3.4 添加集群
在主集群上执行命令, 将 dev1、dev2 都添加到主集群 dev1 上。
kubefedctljoindev1-context–host-cluster-contextdev1-context–kubefed-namespace=kube-federation-system–v=2I062514:32:42.96937325920join.go:861]Usingsecretnamed:dev1-context-dev1-context-token-2w8kmI062514:32:42.97231625920join.go:934]Createdsecretinhostclusternamed:dev1-context-ln6vxI062514:32:42.99139925920join.go:299]Createdfederatedclusterresource kubefedctljoindev2-context–host-cluster-contextdev1-context–kubefed-namespace=kube-federation-system–v=2I062514:33:11.83647226424join.go:861]Usingsecretnamed:dev2-context-dev1-context-token-dcl8sI062514:33:11.84012126424join.go:934]Createdsecretinhostclusternamed:dev2-context-264dzI062514:33:11.89804426424join.go:299]Createdfederatedclusterresource
查看集群列表:
kubectl-nkube-federation-systemgetkubefedclustersNAMEAGEREADYdev1-context45sTruedev2-context16sTrue 3.5 测试集群是否联邦成功 查看已经联邦化的资源
安装 KubeFed 之后,常见的很多资源都已经联邦化,可以在 CRD 中查看:
kubectlgetcrd|grepfederatedfederatedclusterroles.types.kubefed.io2021-06-26T06:22:50Zfederatedconfigmaps.types.kubefed.io2021-06-26T06:22:50Zfederateddeployments.types.kubefed.io2021-06-26T06:22:50Zfederatedingresses.types.kubefed.io2021-06-26T06:22:50Zfederatedjobs.types.kubefed.io2021-06-26T06:22:50Zfederatednamespaces.types.kubefed.io2021-06-26T06:22:50Zfederatedreplicasets.types.kubefed.io2021-06-26T06:22:50Zfederatedsecrets.types.kubefed.io2021-06-26T06:22:50Zfederatedserviceaccounts.types.kubefed.io2021-06-26T06:22:50Zfederatedservices.types.kubefed.io2021-06-26T06:22:50Zfederatedservicestatuses.core.kubefed.io2021-06-26T06:22:50Zfederatedtypeconfigs.core.kubefed.io2021-06-26T06:22:50Z
在 federatedtypeconfigs 中也可以看到已经开启联邦的资源。
kubectlgetfederatedtypeconfigs.core.kubefed.io-nkube-federation-systemNAMEAGEclusterroles.rbac.authorization.k8s.io29mconfigmaps29mdeployments.apps29mingresses.extensions29mjobs.batch29mnamespaces29mreplicasets.apps29msecrets29mserviceaccounts29mservices29m 创建一个联邦的 Namespace
Namespace 级别的资源需要放置在联邦化的 Namespace 下,否则在进行资源分发时,Controller 会报错。
apiVersion:v1kind:Namespacemetadata:name:testing-fed—apiVersion:types.kubefed.io/v1beta1kind:FederatedNamespacemetadata:name:testing-fednamespace:testing-fedspec:placement:clusters:-name:dev1-context-name:dev2-context 在主集群创建一个联邦的 Deployment
常见的 Deployment 是这样:
apiVersion:apps/v1kind:Deploymentmetadata:name:nginxnamespace:defaultspec:replicas:1selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:-image:nginxname:nginx
而联邦的 Deployment 是这样。
apiVersion:types.kubefed.io/v1beta1kind:FederatedDeploymentmetadata:name:nginx-fednamespace:testing-fedspec:overrides:-clusterName:dev1-contextclusterOverrides:-path:/spec/replicasvalue:2-clusterName:dev2-contextclusterOverrides:-path:/spec/replicasvalue:3placement:clusters:-name:dev1-context-name:dev2-contexttemplate:metadata:labels:app:nginxnamespace:testing-fedspec:replicas:1selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:-image:nginxname:nginx
FederatedDeployment 编写时,需要注意三个字段
– overrides, 根据不同集群, 需要覆盖的字段属性。这里将 dev1 上的副本数改为 2,而将 dev2 上的副本数改为 3。
– placement, 资源需要放置的集群列表。这里放置在 dev1、dev2 两个集群。
– template, 资源的模板。这里是 Deployment 去掉 apiVersion 和 kind 的剩余部分。
验证资源是否分发成功
在 dev1 集群上
kubectl-ntesting-fedgetpodNAMEREADYSTATUSRESTARTSAGEnginx-fed-6799fc88d8-7llk91/1Running08m2snginx-fed-6799fc88d8-clc5w1/1Running08m2s
在 dev2 集群上
kubectl-ntesting-fedgetpodNAMEREADYSTATUSRESTARTSAGEnginx-fed-6799fc88d8-2ld4k1/1Running07m49snginx-fed-6799fc88d8-6dncp1/1Running07m49snginx-fed-6799fc88d8-x64fb1/1Running07m49s 4. 联邦化 Tekton 的 CRD 资源
4.1 安装 Tekton
在所有集群上都需要安装 Tekton
kubectlapply-fhttps://raw.githubusercontent.com/shaowenchen/scripts/main/image-sync/tektondev/dockerhub/release-0.24.1.yaml
由于 Tekton 社区使用的是 gcr.io 的镜像, 有些主机环境上可能无法拉取。我在 Dockerhub 上对其进行了备份, 在这里可以找到相关的 yaml, https://github.com/shaowenchen/scripts/tree/main/image-sync/tektondev/dockerhub 。
4.2 联邦化 Tekton 的 CRD
安装 KubeFed 时, 会默认将常见的 Deployment、Secret 等联邦化, 但如果是用户自定义的 CRD 就需要手动开启。
执行命令:
kubefedctlenableclustertasks.tekton.devkubefedctlenableconditions.tekton.devkubefedctlenablepipelineresources.tekton.devkubefedctlenablepipelineruns.tekton.devkubefedctlenablepipelines.tekton.devkubefedctlenableruns.tekton.devkubefedctlenabletaskruns.tekton.devkubefedctlenabletasks.tekton.dev
以 taskruns 为例, kubefedctl enable taskruns.tekton.dev 会自动创建两个资源:
customresourcedefinition.apiextensions.k8s.io/federatedtaskruns.types.kubefed.io, 联邦 CRD 资源 federatedtaskruns federatedtypeconfig.core.kubefed.io/taskruns.tekton.dev, 在 kube-federation-system 命名空间下, 创建 federatedtypeconfig 类型的资源 taskruns 开启资源分发使能
4.3 编辑新创建的联邦 CRD 资源添加字段
缺少这一步, 会导致同步到子集群的 CR 资源内容为空。因为 kubefedctl enable 联邦化 CRD 资源缺少 template 字段。
执行命令:
kubectleditcrdfederatedtasks.types.kubefed.io
在与 overrides 、placement 平级的层次,添加下面示例的 template 内容即可。
apiVersion:apiextensions.k8s.io/v1…spec:versions:-name:v1beta1schema:openAPIV3Schema:properties:spec:properties:overrides:…placement:…template:type:objectx-kubernetes-preserve-unknown-fields:truetype:object
如果觉得不够清晰,可以参考 https://github.com/shaowenchen/scripts/tree/main/image-sync/tektondev/kubefed 修改。如果你也是使用版本 0.24.1, 可以直接 kubectl apply 这些 CRD 资源。
4.4 测试多集群下分发 Tekton 对象
这里为了避免粘贴大量 yaml, 直接提前预先在子集群上创建 Task 资源, 而没有使用 FederatedTask 进行分发。
在子集群上创建 Task kubectlapply-fhttps://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.4/git-clone.yaml-ntesting-fed 在主集群 dev1 上创建 FederatedTaskRun 资源分发到子集群 dev2 apiVersion:types.kubefed.io/v1beta1kind:FederatedTaskRunmetadata:name:git-clone-testnamespace:testing-fedspec:placement:clusters:-name:dev2-contexttemplate:metadata:namespace:testing-fedspec:workspaces:-name:outputemptyDir:{}taskRef:name:git-cloneparams:-name:urlvalue:https://github.com/kelseyhightower/nocode 在子集群 dev2 上查看 Tekton 的 Taskrun 任务 kubectlgettaskrun-ntesting-fedNAMESUCCEEDEDREASONSTARTTIMECOMPLETIONTIMEgit-clone-testTrueSucceeded15s7s 5. 总结
本文主要介绍并实践了利用 KubeFed 管理多集群,对 Tekton CRD 资源进行联邦化。
多集群下的 Tekton,使用主集群管理资源,使用子集群执行流水线,能够有效均衡负载,增加流水线的并发执行量,提高 CICD 系统的可维护性。
这里的 KubeFed 主要是用来存储并分发 Tekton 对象资源。如果自研编码,可以通过数据存储加循环控制器完成,但是利用 KubeFed Controller 能快速实现,同时避免了很多潜在的问题。KubeFed 用于做跨集群的资源分发,非常适用。
6. 参考
https://github.com/kubernetes-sigs/kubefed