多集群下的 Tekton 流水线

2023年 1月 4日 21.2k 0

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

    1
    2
    3
    4
    
    kubectl get node
    
    NAME    STATUS   ROLES                         AGE    VERSION
    node1   Ready    control-plane,master,worker   151m   v1.20.4
    
    1
    2
    3
    
    helm version
    
    version.BuildInfo{Version:"v3.2.1", GitCommit:"fe51cd1e31e6a202cba7dead9552a6d418ded79a", GitTreeState:"clean", GoVersion:"go1.13.10"}
    

    子集群 dev2

    1
    2
    3
    4
    
    kubectl get node
    
    NAME    STATUS   ROLES                         AGE   VERSION
    node1   Ready    control-plane,master,worker   42d   v1.20.4
    
  • 在主集群上配置全部集群的 Context(要求集群 Apiserver 入口在一个网络,能够直连),用来添加子集群
  • 这里 contexts 中的 name 不能含义 @ 等特殊字符, 否则 join 时会报错。因为 name 会用来创建 Secret, 需要符合 Kubernetes 的命名规范。将主集群 dev1 的 kubeconfig 放在 ~/.kube/config-1,并修改 name 等信息,格式如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    apiVersion: v1
    clusters:
    - cluster:
        ...
      name: dev1.cluster.local
    contexts:
    - context:
        cluster: dev1.cluster.local
        user: dev1-kubernetes-admin
      name: dev1-context
    users:
    - name: dev1-kubernetes-admin
      user:
        ...
    

    将子集群 dev2 的 kubeconfig 放在 ~/.kube/config-2,并修改 name 等信息,格式如下:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    apiVersion: v1
    clusters:
    - cluster:
        ...
      name: dev2.cluster.local
    contexts:
    - context:
        cluster: dev2.cluster.local
        user: dev2-kubernetes-admin
      name: dev2-context
    users:
    - name: dev2-kubernetes-admin
      user:
        ...
    
  • 合并 kubeconfig
  • 1
    2
    
    cd $HOME/.kube/
    KUBECONFIG=config-1:config-2 kubectl config view --flatten > $HOME/.kube/config
    
  • 查看添加的集群 Context
  • 1
    2
    3
    4
    5
    
    kubectl config get-contexts
    
    CURRENT   NAME           CLUSTER              AUTHINFO                NAMESPACE
              dev1-context   dev1.cluster.local   dev1-kubernetes-admin
              dev2-context   dev2.cluster.local   dev2-kubernetes-admin
    
  • 切换到主集群 dev1
  • 1
    2
    3
    
    kubectl config use-context dev1-context
    
    Switched to context "dev1-context".
    

    3.2 在主集群上安装 KubeFed

  • 使用 Helm 安装 KubeFed
  • 1
    2
    3
    
    git clone https://github.com/kubernetes-sigs/kubefed.git
    cd kubefed/charts/
    helm install kubefed ./kubefed/ --namespace kube-federation-system --create-namespace
    
  • 查看负载
  •  1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    kubectl get deploy,pod -n kube-federation-system
    
    NAME                                         READY   UP-TO-DATE   AVAILABLE   AGE
    deployment.apps/kubefed-admission-webhook    1/1     1            1           95s
    deployment.apps/kubefed-controller-manager   2/2     2            2           95s
    
    NAME                                              READY   STATUS    RESTARTS   AGE
    pod/kubefed-admission-webhook-598bd776c6-gv4qh    1/1     Running   0          95s
    pod/kubefed-controller-manager-6d9bf98d74-n8kjz   1/1     Running   0          17s
    pod/kubefed-controller-manager-6d9bf98d74-nmb2j   1/1     Running   0          14s
    

    3.3 在主集群上安装 kubefedctl

    执行命令:

    1
    2
    3
    
    wget https://github.com/kubernetes-sigs/kubefed/releases/download/v0.8.0/kubefedctl-0.8.0-linux-amd64.tgz
    tar -zxvf kubefedctl-*.tgz
    mv kubefedctl /usr/local/bin/
    

    3.4 添加集群

    在主集群上执行命令, 将 dev1、dev2 都添加到主集群 dev1 上。

    1
    2
    3
    4
    5
    
    kubefedctl join dev1-context --host-cluster-context dev1-context --kubefed-namespace=kube-federation-system --v=2
    
    I0625 14:32:42.969373   25920 join.go:861] Using secret named: dev1-context-dev1-context-token-2w8km
    I0625 14:32:42.972316   25920 join.go:934] Created secret in host cluster named: dev1-context-ln6vx
    I0625 14:32:42.991399   25920 join.go:299] Created federated cluster resource
    
    1
    2
    3
    4
    5
    
    kubefedctl join dev2-context --host-cluster-context dev1-context --kubefed-namespace=kube-federation-system --v=2
    
    I0625 14:33:11.836472   26424 join.go:861] Using secret named: dev2-context-dev1-context-token-dcl8s
    I0625 14:33:11.840121   26424 join.go:934] Created secret in host cluster named: dev2-context-264dz
    I0625 14:33:11.898044   26424 join.go:299] Created federated cluster resource
    

    查看集群列表:

    1
    2
    3
    4
    5
    
    kubectl -n kube-federation-system get kubefedclusters
    
    NAME           AGE   READY
    dev1-context   45s   True
    dev2-context   16s   True
    

    3.5 测试集群是否联邦成功

    • 查看已经联邦化的资源

    安装 KubeFed 之后,常见的很多资源都已经联邦化,可以在 CRD 中查看:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    kubectl get crd |grep federated
    
    federatedclusterroles.types.kubefed.io                2021-06-26T06:22:50Z
    federatedconfigmaps.types.kubefed.io                  2021-06-26T06:22:50Z
    federateddeployments.types.kubefed.io                 2021-06-26T06:22:50Z
    federatedingresses.types.kubefed.io                   2021-06-26T06:22:50Z
    federatedjobs.types.kubefed.io                        2021-06-26T06:22:50Z
    federatednamespaces.types.kubefed.io                  2021-06-26T06:22:50Z
    federatedreplicasets.types.kubefed.io                 2021-06-26T06:22:50Z
    federatedsecrets.types.kubefed.io                     2021-06-26T06:22:50Z
    federatedserviceaccounts.types.kubefed.io             2021-06-26T06:22:50Z
    federatedservices.types.kubefed.io                    2021-06-26T06:22:50Z
    federatedservicestatuses.core.kubefed.io              2021-06-26T06:22:50Z
    federatedtypeconfigs.core.kubefed.io                  2021-06-26T06:22:50Z
    

    federatedtypeconfigs 中也可以看到已经开启联邦的资源。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    kubectl get federatedtypeconfigs.core.kubefed.io -n kube-federation-system
    
    NAME                                     AGE
    clusterroles.rbac.authorization.k8s.io   29m
    configmaps                               29m
    deployments.apps                         29m
    ingresses.extensions                     29m
    jobs.batch                               29m
    namespaces                               29m
    replicasets.apps                         29m
    secrets                                  29m
    serviceaccounts                          29m
    services                                 29m
    
    • 创建一个联邦的 Namespace

    Namespace 级别的资源需要放置在联邦化的 Namespace 下,否则在进行资源分发时,Controller 会报错。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    apiVersion: v1
    kind: Namespace
    metadata:
      name: testing-fed
    ---
    apiVersion: types.kubefed.io/v1beta1
    kind: FederatedNamespace
    metadata:
      name: testing-fed
      namespace: testing-fed
    spec:
      placement:
        clusters:
        - name: dev1-context
        - name: dev2-context
    
    • 在主集群创建一个联邦的 Deployment

    常见的 Deployment 是这样:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - image: nginx
            name: nginx
    

    而联邦的 Deployment 是这样。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    apiVersion: types.kubefed.io/v1beta1
    kind: FederatedDeployment
    metadata:
      name: nginx-fed
      namespace: testing-fed
    spec:
      overrides:
        - clusterName: dev1-context
          clusterOverrides:
            - path: /spec/replicas
              value: 2
        - clusterName: dev2-context
          clusterOverrides:
            - path: /spec/replicas
              value: 3
      placement:
        clusters:
          - name: dev1-context
          - name: dev2-context
      template:
        metadata:
          labels:
            app: nginx
          namespace: testing-fed
        spec:
          replicas: 1
          selector:
            matchLabels:
              app: nginx
          template:
            metadata:
              labels:
                app: nginx
            spec:
              containers:
                - image: nginx
                  name: nginx
    

    FederatedDeployment 编写时,需要注意三个字段

    - overrides, 根据不同集群, 需要覆盖的字段属性。这里将 dev1 上的副本数改为 2,而将 dev2 上的副本数改为 3。
    - placement, 资源需要放置的集群列表。这里放置在 dev1、dev2 两个集群。
    - template, 资源的模板。这里是 Deployment 去掉 apiVersion 和 kind 的剩余部分。
    
    • 验证资源是否分发成功

    在 dev1 集群上

    1
    2
    3
    4
    5
    
    kubectl -n testing-fed get pod
    
    NAME                         READY   STATUS    RESTARTS   AGE
    nginx-fed-6799fc88d8-7llk9   1/1     Running   0          8m2s
    nginx-fed-6799fc88d8-clc5w   1/1     Running   0          8m2s
    

    在 dev2 集群上

    1
    2
    3
    4
    5
    6
    
    kubectl -n testing-fed get pod
    
    NAME                         READY   STATUS    RESTARTS   AGE
    nginx-fed-6799fc88d8-2ld4k   1/1     Running   0          7m49s
    nginx-fed-6799fc88d8-6dncp   1/1     Running   0          7m49s
    nginx-fed-6799fc88d8-x64fb   1/1     Running   0          7m49s
    

    4. 联邦化 Tekton 的 CRD 资源

    4.1 安装 Tekton

    在所有集群上都需要安装 Tekton

    1
    
    kubectl apply -f https://raw.githubusercontent.com/shaowenchen/image-syncer/main/tekton/v0.24.1-release-0.24.1.yaml
    

    由于 Tekton 社区使用的是 gcr.io 的镜像, 有些主机环境上可能无法拉取。我在 Dockerhub 上对其进行了备份, 在这里可以找到相关的 yaml, https://github.com/shaowenchen/image-syncer/tree/main/tekton 。

    4.2 联邦化 Tekton 的 CRD

    安装 KubeFed 时, 会默认将常见的 Deployment、Secret 等联邦化, 但如果是用户自定义的 CRD 就需要手动开启。执行命令:

    1
    2
    3
    4
    5
    6
    7
    8
    
    kubefedctl enable clustertasks.tekton.dev
    kubefedctl enable conditions.tekton.dev
    kubefedctl enable pipelineresources.tekton.dev
    kubefedctl enable pipelineruns.tekton.dev
    kubefedctl enable pipelines.tekton.dev
    kubefedctl enable runs.tekton.dev
    kubefedctl enable taskruns.tekton.dev
    kubefedctl enable tasks.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 字段。执行命令:

    1
    
    kubectl edit crd federatedtasks.types.kubefed.io
    

    在与 overridesplacement 平级的层次,添加下面示例的 template 内容即可。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    apiVersion: apiextensions.k8s.io/v1
    ...
    spec:
      versions:
      - name: v1beta1
        schema:
          openAPIV3Schema:
            properties:
              spec:
                properties:
                  overrides:
                    ...
                  placement:
                    ...
                  template:
                    type: object
                    x-kubernetes-preserve-unknown-fields: true
                type: object
    

    如果觉得不够清晰,可以参考 https://github.com/shaowenchen/demo/tree/master/tekton-0.24.1-kubefed 修改。如果你也是使用版本 0.24.1, 可以直接 kubectl apply 这些 CRD 资源。

    4.4 测试多集群下分发 Tekton 对象

    这里为了避免粘贴大量 yaml, 直接提前预先在子集群上创建 Task 资源, 而没有使用 FederatedTask 进行分发。

    • 在子集群上创建 Task
    1
    
    kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.4/git-clone.yaml -n testing-fed
    
    • 在主集群 dev1 上创建 FederatedTaskRun 资源分发到子集群 dev2
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    apiVersion: types.kubefed.io/v1beta1
    kind: FederatedTaskRun
    metadata:
      name: git-clone-test
      namespace: testing-fed
    spec:
      placement:
        clusters:
        - name: dev2-context
      template:
        metadata:
          namespace: testing-fed
        spec:
          workspaces:
            - name: output
              emptyDir: {}
          taskRef:
            name: git-clone
          params:
            - name: url
              value: https://github.com/kelseyhightower/nocode
    
    • 在子集群 dev2 上查看 Tekton 的 Taskrun 任务
    1
    2
    3
    4
    
    kubectl get taskrun -n testing-fed
    
    NAME             SUCCEEDED   REASON      STARTTIME   COMPLETIONTIME
    git-clone-test   True        Succeeded   15s         7s
    

    5. 总结

    本文主要介绍并实践了利用 KubeFed 管理多集群,对 Tekton CRD 资源进行联邦化。多集群下的 Tekton,使用主集群管理资源,使用子集群执行流水线,能够有效均衡负载,增加流水线的并发执行量,提高 CICD 系统的可维护性。这里的 KubeFed 主要是用来存储并分发 Tekton 对象资源。如果自研编码,可以通过数据存储加循环控制器完成,但是利用 KubeFed Controller 能快速实现,同时避免了很多潜在的问题。KubeFed 用于做跨集群的资源分发,非常适用。

    6. 参考

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

    相关文章

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论