Tekton 与 Argo CD 结合实现 GitOps

发布时间:2021-07-10 17:31 来源: 阅读:0 作者:阳明 栏目: 云计算 欢迎投稿:712375056

前面我们使用 Tekton 完成了应用的 CI/CD 流程,但是 CD 是在 Tekton 的任务中去完成的,现在我们使用 GitOps 的方式来改造我们的流水线,将 CD 部分使用 Argo CD 来完成。

这里我们要先去回顾下前面的 Tekton 实战部分的内容,整个流水线包括 clone、test、build、docker、deploy、rollback 几个部分的任务,最后的 deploy 和 rollback 属于 CD 部分,我们只需要这部分使用 Argo CD 来构建即可。

首先我们将项目 http://git.k8s.local/course/devops-demo.git 仓库中的 Helm Chart 模板单独提取出来放到一个独立的仓库中 http://git.k8s.local/course/devops-demo-deploy,这样方便和 Argo CD 进行对接,整个项目下面只有用于应用部署的 Helm Chart 模板。

首先在 Argo CD 上面添加该仓库:

然后创建新应用,首先可以创建一个项目,在 Argo CD 中有一个 AppProject 的 CRD,表示应用程序的逻辑分组,它由以下几个关键属性组成:

  • sourceRepos:项目中的应用程序可以从中获取清单的仓库引用
  • destinations:项目中的应用可以部署到的集群和命名空间
  • roles:项目内资源访问定义的角色
  1. apiVersion: argoproj.io/v1alpha1 
  2. kind: AppProject 
  3. metadata: 
  4.   # 项目名 
  5.   name: demo 
  6.   namespace: argocd 
  7. spec: 
  8.   # 目标 
  9.   destinations: 
  10.     # 此项目的服务允许部署的 namespace,这里为全部 
  11.   - namespace: '*' 
  12.     # 此项目允许部署的集群,这里为默认集群,即为Argo CD部署的当前集群 
  13.     server: https://kubernetes.default.svc 
  14.   # 允许的数据源 
  15.   sourceRepos: 
  16.   - http://git.k8s.local/course/devops-demo-deploy.git 

更多配置信息可以前往文档 https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/ 查看,项目创建完成后,在该项目下创建一个 Application,代表环境中部署的应用程序实例。

  1. apiVersion: argoproj.io/v1alpha1 
  2. kind: Application 
  3. metadata: 
  4.   name: devops-demo 
  5.   namespace: argocd 
  6. spec: 
  7.   destination: 
  8.     namespace: default 
  9.     server: 'https://kubernetes.default.svc' 
  10.   project: demo 
  11.   source: 
  12.     path: helm  # 从 Helm 存储库创建应用程序时,chart 必须指定 path 
  13.     repoURL: 'http://git.k8s.local/course/devops-demo-deploy.git' 
  14.     targetRevision: HEAD 
  15.     helm: 
  16.       parameters: 
  17.         - name: replicaCount 
  18.           value: '2' 
  19.       valueFiles: 
  20.         - my-values.yaml 

这里我们定义了一个名为 devops-demo 的应用,应用源来自于 helm 路径,使用的是 my-values.yaml 文件,此外还可以通过 source.helm.parameters 来配置参数,同步策略我们仍然选择使用手动的方式,我们可以在 Tekton 的任务中去手动触发同步。上面的资源对象创建完成后应用就会处于 OutOfSync 状态,因为集群中还没部署该应用。

现在接下来我们去修改之前的 Tekton 流水线,之前的 Pipeline 流水线如下所示:

  1. # pipeline.yaml 
  2. apiVersion: tekton.dev/v1beta1 
  3. kind: Pipeline 
  4. metadata: 
  5.   name: pipeline 
  6. spec: 
  7.   workspaces: # 声明 workspaces 
  8.     - name: go-repo-pvc 
  9.   params: 
  10.     # 定义代码仓库 
  11.     - name: git_url 
  12.     - name: revision 
  13.       type: string 
  14.       default"master" 
  15.     # 定义镜像参数 
  16.     - name: image 
  17.     - name: registry_url 
  18.       type: string 
  19.       default"harbor.k8s.local" 
  20.     - name: registry_mirror 
  21.       type: string 
  22.       default"https://ot2k4d59.mirror.aliyuncs.com/" 
  23.     # 定义 helm charts 参数 
  24.     - name: charts_dir 
  25.     - name: release_name 
  26.     - name: release_namespace 
  27.       default"default" 
  28.     - name: overwrite_values 
  29.       default"" 
  30.     - name: values_file 
  31.       default"values.yaml" 
  32.   tasks: # 添加task到流水线中 
  33.     - name: clone 
  34.       taskRef: 
  35.         name: git-clone 
  36.       workspaces: 
  37.         - nameoutput 
  38.           workspace: go-repo-pvc 
  39.       params: 
  40.         - name: url 
  41.           value: $(params.git_url) 
  42.         - name: revision 
  43.           value: $(params.revision) 
  44.     - name: test 
  45.       taskRef: 
  46.         name: test 
  47.     - name: build # 编译二进制程序 
  48.       taskRef: 
  49.         name: build 
  50.       runAfter: # 测试任务执行之后才执行 build task 
  51.         - test 
  52.         - clone 
  53.       workspaces: # 传递 workspaces 
  54.         - name: go-repo 
  55.           workspace: go-repo-pvc 
  56.     - name: docker # 构建并推送 Docker 镜像 
  57.       taskRef: 
  58.         name: docker 
  59.       runAfter: 
  60.         - build 
  61.       workspaces: # 传递 workspaces 
  62.         - name: go-repo 
  63.           workspace: go-repo-pvc 
  64.       params: # 传递参数 
  65.         - name: image 
  66.           value: $(params.image) 
  67.         - name: registry_url 
  68.           value: $(params.registry_url) 
  69.         - name: registry_mirror 
  70.           value: $(params.registry_mirror) 
  71.     - name: deploy # 部署应用 
  72.       taskRef: 
  73.         name: deploy 
  74.       runAfter: 
  75.         - docker 
  76.       workspaces: 
  77.         - name: source 
  78.           workspace: go-repo-pvc 
  79.       params: 
  80.         - name: charts_dir 
  81.           value: $(params.charts_dir) 
  82.         - name: release_name 
  83.           value: $(params.release_name) 
  84.         - name: release_namespace 
  85.           value: $(params.release_namespace) 
  86.         - name: overwrite_values 
  87.           value: $(params.overwrite_values) 
  88.         - name: values_file 
  89.           value: $(params.values_file) 
  90.     - namerollback # 回滚 
  91.       taskRef: 
  92.         namerollback 
  93.       when
  94.         - input: "$(tasks.deploy.results.helm-status)" 
  95.           operator: in 
  96.           values: ["failed"
  97.       params: 
  98.         - name: release_name 
  99.           value: $(params.release_name) 
  100.         - name: release_namespace 
  101.           value: $(params.release_namespace) 

现在我们需要去掉最后的 deploy 和 rollback 两个任务,当 Docker 镜像构建推送完成后,我们只需要去修改部署代码仓库中的 values 文件,然后再去手动触发 Argo CD 同步状态即可(如果开启了自动同步这一步都可以省略了),而回滚操作直接在 Argo CD 中去操作即可,不需要定义一个单独的 Task 任务。

定义一个如下所示的 Taks 任务:

  1. apiVersion: tekton.dev/v1alpha1 
  2. kind: Task 
  3. metadata: 
  4.   name: sync 
  5. spec: 
  6.   volumes: 
  7.   - name: argocd-secret 
  8.     secret: 
  9.       secretName: $(inputs.params.argocd_secret) 
  10.   params: 
  11.     - name: argocd_url 
  12.       description: "The URL of the ArgoCD server" 
  13.     - name: argocd_secret 
  14.       description: "The secret containing the username and password for the tekton task to connect to argo" 
  15.     - name: commit_id 
  16.       description: "The commit ID to update" 
  17.     - name: app_name 
  18.       description: "The name of the argo app to update" 
  19.     - name: app_revision 
  20.       default"HEAD" 
  21.       description: "The revision of the argo app to update" 
  22.   steps: 
  23.   - name: deploy 
  24.     image: argoproj/argocd 
  25.     volumeMounts: 
  26.     - name: argocd-secret 
  27.       mountPath: /var/secret 
  28.     command: 
  29.     - sh 
  30.     args: 
  31.     - -ce 
  32.     - | 
  33.       set -e 
  34.       echo "update commit id" 
  35.       argocd login --insecure $(params.argocd_url) --username $(/bin/cat /var/secret/username) --password $(/bin/cat /var/secret/password) 
  36.       argocd app sync $(params.app_name) --revision $(params.app_revision) 
  37.       argocd app wait $(params.app_name) --health 

由于我们这里只需要修改 Helm Chart 的 Values 文件中的 image.tag 参数,最好的方式当然还是在一个 Task 中去修改 values.yaml 文件并 commit 到 Repo 仓库中去,当然也可以为了简单直接在 Argo CD 的应用侧配置参数即可,比如可以使用 argocd app set 命令来为应用配置参数,然后下面再用 argocd app sync 命令手动触发同步操作,这里其实就可以有很多操作了,比如我们可以根据某些条件来判断是否需要部署,满足条件后再执行 sync 操作,最后使用 wait 命令等待应用部署完成。

除了通过手动 argocd app set 的方式来配置参数之外,可能更好的方式还是直接去修改 Repo 仓库中的 values 值,这样在源代码仓库中有一个版本记录,我们可以新建如下所示的一个任务用来修改 values 值:

  1. apiVersion: tekton.dev/v1beta1 
  2. kind: Task 
  3. metadata: 
  4.   name: change-manifests 
  5. spec: 
  6.   params: 
  7.     - name: git_url 
  8.       description: Git repository containing manifest files to update 
  9.     - name: git_email 
  10.       default: pipeline@k8s.local 
  11.     - name: git_name 
  12.       default: Tekton Pipeline 
  13.     - name: git_manifest_dir 
  14.       description: Manifests files dir 
  15.     - name: tool_image 
  16.       default: cnych/helm-kubectl-curl-git-jq-yq 
  17.     - name: image_tag 
  18.       description: Deploy docker image tag 
  19.   steps: 
  20.     - name: git-push 
  21.       image: $(params.tool_image) 
  22.       env: 
  23.         - name: GIT_USERNAME 
  24.           valueFrom: 
  25.             secretKeyRef: 
  26.               name: gitlab-auth 
  27.               key: username 
  28.               optional: true 
  29.         - name: GIT_PASSWORD 
  30.           valueFrom: 
  31.             secretKeyRef: 
  32.               name: gitlab-auth 
  33.               keypassword 
  34.               optional: true 
  35.       command: ["/bin/bash"
  36.       args: 
  37.         - -c 
  38.         - | 
  39.           set -eu 
  40.           echo Load environment variables from previous steps 
  41.           source /workspace/env-config 
  42.           git config --global user.email "$(params.git_email)" 
  43.           git config --global user.name "$(params.git_name)" 
  44.           git clone --branch master --depth 1 http://${GIT_USERNAME}:${GIT_PASSWORD}@$(params.git_url) repo 
  45.           cd "repo/$(params.git_manifest_dir)" 
  46.           ls -l 
  47.           echo old value: 
  48.           cat my-values.yaml | yq r - 'image.tag' 
  49.           echo replacing with new value: 
  50.           echo $(params.image_tag) 
  51.           yq w --inplace my-values.yaml 'image.tag' "$(params.image_tag)" 
  52.           echo verifying new value 
  53.           yq r my-values.yaml 'image.tag' 
  54.           if ! git diff-index --quiet HEAD --; then 
  55.             git status 
  56.             git add . 
  57.             git commit -m "helm values updated by tekton pipeline in change-manifests task" 
  58.             git push 
  59.           else 
  60.               echo "no changes, git repository is up to date" 
  61.           fi 

现在我们的流水线就变成了如下所示的清单:

  1. # pipeline.yaml 
  2. apiVersion: tekton.dev/v1beta1 
  3. kind: Pipeline 
  4. metadata: 
  5.   name: pipeline 
  6. spec: 
  7.   workspaces: # 声明 workspaces 
  8.     - name: go-repo-pvc 
  9.   params: 
  10.     # 定义代码仓库 
  11.     - name: git_url 
  12.     - name: git_infra_url 
  13.     - name: revision 
  14.       type: string 
  15.       default"master" 
  16.     # 定义镜像参数 
  17.     - name: image 
  18.     - name: image_tag 
  19.     - name: registry_url 
  20.       type: string 
  21.       default"harbor.k8s.local" 
  22.     - name: registry_mirror 
  23.       type: string 
  24.       default"https://ot2k4d59.mirror.aliyuncs.com/" 
  25.     - name: git_manifest_dir 
  26.       default"helm" 
  27.     # 定义 argocd 参数 
  28.     - name: argocd_url 
  29.     - name: argocd_secret 
  30.     - name: app_name 
  31.     - name: app_revision 
  32.       type: string 
  33.       default"HEAD" 
  34.   tasks: # 添加task到流水线中 
  35.     - name: clone 
  36.       taskRef: 
  37.         name: git-clone 
  38.       workspaces: 
  39.         - nameoutput 
  40.           workspace: go-repo-pvc 
  41.       params: 
  42.         - name: url 
  43.           value: $(params.git_url) 
  44.         - name: revision 
  45.           value: $(params.revision) 
  46.     - name: test 
  47.       taskRef: 
  48.         name: test 
  49.     - name: build # 编译二进制程序 
  50.       taskRef: 
  51.         name: build 
  52.       runAfter: # 测试任务执行之后才执行 build task 
  53.         - test 
  54.         - clone 
  55.       workspaces: # 传递 workspaces 
  56.         - name: go-repo 
  57.           workspace: go-repo-pvc 
  58.     - name: docker # 构建并推送 Docker 镜像 
  59.       taskRef: 
  60.         name: docker 
  61.       runAfter: 
  62.         - build 
  63.       workspaces: # 传递 workspaces 
  64.         - name: go-repo 
  65.           workspace: go-repo-pvc 
  66.       params: # 传递参数 
  67.         - name: image 
  68.           value: $(params.image):$(params.image_tag) 
  69.         - name: registry_url 
  70.           value: $(params.registry_url) 
  71.         - name: registry_mirror 
  72.           value: $(params.registry_mirror) 
  73.     - name: manifests 
  74.       taskRef: 
  75.         name: change-manifests 
  76.       runAfter: 
  77.         - docker 
  78.       params: 
  79.       - name: git_url 
  80.         value: $(params.git_infra_url) 
  81.       - name: git_manifest_dir 
  82.         value: $(params.git_manifest_dir) 
  83.       - name: image_tag 
  84.         value: $(params.image_tag) 
  85.     - name: sync 
  86.       taskRef: 
  87.         name: sync 
  88.       runAfter: 
  89.         - manifests 
  90.       params: 
  91.       - name: argocd_url 
  92.         value: $(params.argocd_url) 
  93.       - name: argocd_secret 
  94.         value: $(params.argocd_secret) 
  95.       - name: app_name 
  96.         value: $(params.app_name) 
  97.       - name: app_revision 
  98.         value: $(params.app_revision) 

最后创建用于 Argo CD 登录使用的 Secret 对象:

  1. apiVersion: v1 
  2. kind: Secret 
  3. metadata: 
  4.   name: argocd-auth 
  5. type: Opaque 
  6. stringData: 
  7.   username: admin 
  8.   password: admin321 

最后修改 Tekton Triggers 中的 Template,如下所示:

  1. # gitlab-template.yaml 
  2. apiVersion: triggers.tekton.dev/v1alpha1 
  3. kind: TriggerTemplate 
  4. metadata: 
  5.   name: gitlab-template 
  6. spec: 
  7.   params: # 定义参数,和 TriggerBinding 中的保持一致 
  8.     - name: gitrevision 
  9.     - name: gitrepositoryurl 
  10.   resourcetemplates: # 定义资源模板 
  11.     - apiVersion: tekton.dev/v1beta1 
  12.       kind: PipelineRun # 定义 pipeline 模板 
  13.       metadata: 
  14.         generateName: gitlab-run- # TaskRun 名称前缀 
  15.       spec: 
  16.         serviceAccountName: tekton-build-sa 
  17.         pipelineRef: 
  18.           name: pipeline 
  19.         workspaces: 
  20.           - name: go-repo-pvc 
  21.             persistentVolumeClaim: 
  22.               claimName: go-repo-pvc 
  23.         params: 
  24.           - name: git_url 
  25.             value: $(tt.params.gitrepositoryurl) 
  26.           - name: git_infra_url 
  27.             value: git.k8s.local/course/devops-demo-deploy.git 
  28.           - name: image 
  29.             value: "harbor.k8s.local/course/devops-demo" 
  30.           - name: image_tag 
  31.             value: "$(tt.params.gitrevision)" 
  32.           - name: argocd_url 
  33.             value: argocd.k8s.local 
  34.           - name: argocd_secret 
  35.             value: argocd-auth 
  36.           - name: app_name 
  37.             value: devops-demo 

现在我们的整个流水线就更加精简了。现在我们去应用仓库中修改下源代码并提交就可以触发我们的流水线了。

可以看到当我们提交代码后,整个流水线构建会一直卡在最后的 sync 任务,这是因为我们执行了 argocd app wait $(params.app_name) --health 这个命令,需要等待应用健康后才会退出。

  1. $ curl devops-demo.k8s.local 
  2. {"msg":"Hello Tekton + ArgoCD On GitLab"

但实际上上面我们的应用已经部署成功了,只是 Argo CD 的健康检查没有通过,Argo CD 为几种标准的 Kubernetes 资源提供了内置的健康策略,然后将这些策略作为一个整体呈现在应用的健康状态中,比如会检查副本数是否正常,PVC 是否绑定等,而对于 Ingress 资源会检查 status.loadBalancer.ingress 列表是否非空,需要至少有一个 hostname 或 IP 值,而我们这里部署的 Ingress 中的值为空:

  1. $ kubectl get ingress devops-demo -o yaml 
  2. apiVersion: extensions/v1beta1 
  3. kind: Ingress 
  4. ...... 
  5. spec: 
  6.   rules: 
  7.   - host: devops-demo.k8s.local 
  8.     http: 
  9.       paths: 
  10.       - backend: 
  11.           serviceName: devops-demo 
  12.           servicePort: http 
  13.         path: / 
  14.         pathType: ImplementationSpecific 
  15. status: 
  16.   loadBalancer: {} 

所以健康检查一直不通过,在 Argo CD 页面上也可以证实是 Ingress 导致健康检查没通过:

这个时候需要我们去自定义 Ingress 资源的监控检查方式,Argo CD 支持用 Lua 来编写检查规则,修改 Argo CD 的 Configmap 配置文件:

  1. $ kubectl edit cm -n argocd argocd-cm 
  2. # Please edit the object below. Lines beginning with a '#' will be ignored, 
  3. and an empty file will abort the edit. If an error occurs while saving this file will be 
  4. # reopened with the relevant failures. 
  5. apiVersion: v1 
  6. data: 
  7.   resource.customizations: |  # 定制 Ingress 资源的健康检查方式 
  8.     extensions/Ingress: 
  9.         health.lua: | 
  10.           hs = {} 
  11.           hs.status = "Healthy" 
  12.           return hs 
  13. ...... 

修改完成后,我们的应用就会变成健康状态了。

如果需要回滚,则可以直接在 Argo CD 页面上点击 HISTORY AND ROLLBACK 安装查看部署的历史记录选择回滚的版本即可:

可以查看整个 Tekton 流水线的状态:

  1. $ tkn pr describe gitlab-run-vdlm6 
  2. Name:              gitlab-run-vdlm6 
  3. Namespace:         default 
  4. Pipeline Ref:      pipeline 
  5. Service Account:   tekton-build-sa 
  6. Timeout:           1h0m0s 
  7. Labels: 
  8.  tekton.dev/pipeline=pipeline 
  9.  triggers.tekton.dev/eventlistener=gitlab-listener 
  10.  triggers.tekton.dev/trigger=gitlab-push-events-trigger 
  11.  triggers.tekton.dev/triggers-eventid=eeda9157-5eb3-4399-be4b-88955cb56764 
  12.  
  13. 🌡️  Status 
  14.  
  15. STARTED         DURATION    STATUS 
  16. 4 minutes ago   2 minutes   Succeeded 
  17.  
  18. 📦 Resources 
  19.  
  20.  No resources 
  21.  
  22. ⚓ Params 
  23.  
  24.  NAME              VALUE 
  25.  ∙ git_url         http://git.k8s.local/course/devops-demo.git 
  26.  ∙ git_infra_url   git.k8s.local/course/devops-demo-deploy.git 
  27.  ∙ image           harbor.k8s.local/course/devops-demo 
  28.  ∙ image_tag       332798d9e28422341fd64704ab9b54b944d77084 
  29.  ∙ argocd_url      argocd.k8s.local 
  30.  ∙ argocd_secret   argocd-auth 
  31.  ∙ app_name        devops-demo 
  32.  
  33. 📝 Results 
  34.  
  35.  No results 
  36.  
  37. 📂 Workspaces 
  38.  
  39.  NAME            SUB PATH   WORKSPACE BINDING 
  40.  ∙ go-repo-pvc   ---        PersistentVolumeClaim (claimName=go-repo-pvc) 
  41.  
  42. 🗂  Taskruns 
  43.  
  44.  NAME                                 TASK NAME   STARTED         DURATION     STATUS 
  45.  ∙ gitlab-run-vdlm6-sync-svmxl        sync        3 minutes ago   42 seconds   Succeeded 
  46.  ∙ gitlab-run-vdlm6-manifests-d297d   manifests   3 minutes ago   26 seconds   Succeeded 
  47.  ∙ gitlab-run-vdlm6-docker-g2tqx      docker      4 minutes ago   48 seconds   Succeeded 
  48.  ∙ gitlab-run-vdlm6-build-mkcrd       build       4 minutes ago   9 seconds    Succeeded 
  49.  ∙ gitlab-run-vdlm6-test-gjr4c        test        4 minutes ago   4 seconds    Succeeded 
  50.  ∙ gitlab-run-vdlm6-clone-57vpw       clone       4 minutes ago   8 seconds    Succeeded 

最后用一张图来总结下我们使用 Tekton 结合 Argo CD 来实现 GitOps 的工作流:

【编辑推荐】

免责声明:本站发布的内容(图片、视频和文字)以原创、来自本网站内容采集于网络互联网转载等其它媒体和分享为主,内容观点不代表本网站立场,如侵犯了原作者的版权,请告知一经查实,将立刻删除涉嫌侵权内容,联系我们QQ:712375056,同时欢迎投稿传递力量。