Tekton 與 Argo CD 結(jié)合實現(xiàn) GitOps
前面我們使用 Tekton 完成了應(yīng)用的 CI/CD 流程,但是 CD 是在 Tekton 的任務(wù)中去完成的,現(xiàn)在我們使用 GitOps 的方式來改造我們的流水線,將 CD 部分使用 Argo CD 來完成。
這里我們要先去回顧下前面的 Tekton 實戰(zhàn)部分的內(nèi)容,整個流水線包括 clone、test、build、docker、deploy、rollback 幾個部分的任務(wù),最后的 deploy 和 rollback 屬于 CD 部分,我們只需要這部分使用 Argo CD 來構(gòu)建即可。
首先我們將項目 http://git.k8s.local/course/devops-demo.git 倉庫中的 Helm Chart 模板單獨提取出來放到一個獨立的倉庫中 http://git.k8s.local/course/devops-demo-deploy,這樣方便和 Argo CD 進(jìn)行對接,整個項目下面只有用于應(yīng)用部署的 Helm Chart 模板。
首先在 Argo CD 上面添加該倉庫:
然后創(chuàng)建新應(yīng)用,首先可以創(chuàng)建一個項目,在 Argo CD 中有一個 AppProject 的 CRD,表示應(yīng)用程序的邏輯分組,它由以下幾個關(guān)鍵屬性組成:
- sourceRepos:項目中的應(yīng)用程序可以從中獲取清單的倉庫引用
- destinations:項目中的應(yīng)用可以部署到的集群和命名空間
- roles:項目內(nèi)資源訪問定義的角色
- apiVersion: argoproj.io/v1alpha1
- kind: AppProject
- metadata:
- # 項目名
- name: demo
- namespace: argocd
- spec:
- # 目標(biāo)
- destinations:
- # 此項目的服務(wù)允許部署的 namespace,這里為全部
- - namespace: '*'
- # 此項目允許部署的集群,這里為默認(rèn)集群,即為Argo CD部署的當(dāng)前集群
- server: https://kubernetes.default.svc
- # 允許的數(shù)據(jù)源
- sourceRepos:
- - http://git.k8s.local/course/devops-demo-deploy.git
更多配置信息可以前往文檔 https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/ 查看,項目創(chuàng)建完成后,在該項目下創(chuàng)建一個 Application,代表環(huán)境中部署的應(yīng)用程序?qū)嵗?/p>
- apiVersion: argoproj.io/v1alpha1
- kind: Application
- metadata:
- name: devops-demo
- namespace: argocd
- spec:
- destination:
- namespace: default
- server: 'https://kubernetes.default.svc'
- project: demo
- source:
- path: helm # 從 Helm 存儲庫創(chuàng)建應(yīng)用程序時,chart 必須指定 path
- repoURL: 'http://git.k8s.local/course/devops-demo-deploy.git'
- targetRevision: HEAD
- helm:
- parameters:
- - name: replicaCount
- value: '2'
- valueFiles:
- - my-values.yaml
這里我們定義了一個名為 devops-demo 的應(yīng)用,應(yīng)用源來自于 helm 路徑,使用的是 my-values.yaml 文件,此外還可以通過 source.helm.parameters 來配置參數(shù),同步策略我們?nèi)匀贿x擇使用手動的方式,我們可以在 Tekton 的任務(wù)中去手動觸發(fā)同步。上面的資源對象創(chuàng)建完成后應(yīng)用就會處于 OutOfSync 狀態(tài),因為集群中還沒部署該應(yīng)用。
現(xiàn)在接下來我們?nèi)バ薷闹暗?Tekton 流水線,之前的 Pipeline 流水線如下所示:
- # pipeline.yaml
- apiVersion: tekton.dev/v1beta1
- kind: Pipeline
- metadata:
- name: pipeline
- spec:
- workspaces: # 聲明 workspaces
- - name: go-repo-pvc
- params:
- # 定義代碼倉庫
- - name: git_url
- - name: revision
- type: string
- default: "master"
- # 定義鏡像參數(shù)
- - name: image
- - name: registry_url
- type: string
- default: "harbor.k8s.local"
- - name: registry_mirror
- type: string
- default: "https://ot2k4d59.mirror.aliyuncs.com/"
- # 定義 helm charts 參數(shù)
- - name: charts_dir
- - name: release_name
- - name: release_namespace
- default: "default"
- - name: overwrite_values
- default: ""
- - name: values_file
- default: "values.yaml"
- tasks: # 添加task到流水線中
- - name: clone
- taskRef:
- name: git-clone
- workspaces:
- - name: output
- workspace: go-repo-pvc
- params:
- - name: url
- value: $(params.git_url)
- - name: revision
- value: $(params.revision)
- - name: test
- taskRef:
- name: test
- - name: build # 編譯二進(jìn)制程序
- taskRef:
- name: build
- runAfter: # 測試任務(wù)執(zhí)行之后才執(zhí)行 build task
- - test
- - clone
- workspaces: # 傳遞 workspaces
- - name: go-repo
- workspace: go-repo-pvc
- - name: docker # 構(gòu)建并推送 Docker 鏡像
- taskRef:
- name: docker
- runAfter:
- - build
- workspaces: # 傳遞 workspaces
- - name: go-repo
- workspace: go-repo-pvc
- params: # 傳遞參數(shù)
- - name: image
- value: $(params.image)
- - name: registry_url
- value: $(params.registry_url)
- - name: registry_mirror
- value: $(params.registry_mirror)
- - name: deploy # 部署應(yīng)用
- taskRef:
- name: deploy
- runAfter:
- - docker
- workspaces:
- - name: source
- workspace: go-repo-pvc
- params:
- - name: charts_dir
- value: $(params.charts_dir)
- - name: release_name
- value: $(params.release_name)
- - name: release_namespace
- value: $(params.release_namespace)
- - name: overwrite_values
- value: $(params.overwrite_values)
- - name: values_file
- value: $(params.values_file)
- - name: rollback # 回滾
- taskRef:
- name: rollback
- when:
- - input: "$(tasks.deploy.results.helm-status)"
- operator: in
- values: ["failed"]
- params:
- - name: release_name
- value: $(params.release_name)
- - name: release_namespace
- value: $(params.release_namespace)
現(xiàn)在我們需要去掉最后的 deploy 和 rollback 兩個任務(wù),當(dāng) Docker 鏡像構(gòu)建推送完成后,我們只需要去修改部署代碼倉庫中的 values 文件,然后再去手動觸發(fā) Argo CD 同步狀態(tài)即可(如果開啟了自動同步這一步都可以省略了),而回滾操作直接在 Argo CD 中去操作即可,不需要定義一個單獨的 Task 任務(wù)。
定義一個如下所示的 Taks 任務(wù):
- apiVersion: tekton.dev/v1alpha1
- kind: Task
- metadata:
- name: sync
- spec:
- volumes:
- - name: argocd-secret
- secret:
- secretName: $(inputs.params.argocd_secret)
- params:
- - name: argocd_url
- description: "The URL of the ArgoCD server"
- - name: argocd_secret
- description: "The secret containing the username and password for the tekton task to connect to argo"
- - name: commit_id
- description: "The commit ID to update"
- - name: app_name
- description: "The name of the argo app to update"
- - name: app_revision
- default: "HEAD"
- description: "The revision of the argo app to update"
- steps:
- - name: deploy
- image: argoproj/argocd
- volumeMounts:
- - name: argocd-secret
- mountPath: /var/secret
- command:
- - sh
- args:
- - -ce
- - |
- set -e
- echo "update commit id"
- argocd login --insecure $(params.argocd_url) --username $(/bin/cat /var/secret/username) --password $(/bin/cat /var/secret/password)
- argocd app sync $(params.app_name) --revision $(params.app_revision)
- argocd app wait $(params.app_name) --health
由于我們這里只需要修改 Helm Chart 的 Values 文件中的 image.tag 參數(shù),最好的方式當(dāng)然還是在一個 Task 中去修改 values.yaml 文件并 commit 到 Repo 倉庫中去,當(dāng)然也可以為了簡單直接在 Argo CD 的應(yīng)用側(cè)配置參數(shù)即可,比如可以使用 argocd app set 命令來為應(yīng)用配置參數(shù),然后下面再用 argocd app sync 命令手動觸發(fā)同步操作,這里其實就可以有很多操作了,比如我們可以根據(jù)某些條件來判斷是否需要部署,滿足條件后再執(zhí)行 sync 操作,最后使用 wait 命令等待應(yīng)用部署完成。
除了通過手動 argocd app set 的方式來配置參數(shù)之外,可能更好的方式還是直接去修改 Repo 倉庫中的 values 值,這樣在源代碼倉庫中有一個版本記錄,我們可以新建如下所示的一個任務(wù)用來修改 values 值:
- apiVersion: tekton.dev/v1beta1
- kind: Task
- metadata:
- name: change-manifests
- spec:
- params:
- - name: git_url
- description: Git repository containing manifest files to update
- - name: git_email
- default: pipeline@k8s.local
- - name: git_name
- default: Tekton Pipeline
- - name: git_manifest_dir
- description: Manifests files dir
- - name: tool_image
- default: cnych/helm-kubectl-curl-git-jq-yq
- - name: image_tag
- description: Deploy docker image tag
- steps:
- - name: git-push
- image: $(params.tool_image)
- env:
- - name: GIT_USERNAME
- valueFrom:
- secretKeyRef:
- name: gitlab-auth
- key: username
- optional: true
- - name: GIT_PASSWORD
- valueFrom:
- secretKeyRef:
- name: gitlab-auth
- key: password
- optional: true
- command: ["/bin/bash"]
- args:
- - -c
- - |
- set -eu
- echo Load environment variables from previous steps
- source /workspace/env-config
- git config --global user.email "$(params.git_email)"
- git config --global user.name "$(params.git_name)"
- git clone --branch master --depth 1 http://${GIT_USERNAME}:${GIT_PASSWORD}@$(params.git_url) repo
- cd "repo/$(params.git_manifest_dir)"
- ls -l
- echo old value:
- cat my-values.yaml | yq r - 'image.tag'
- echo replacing with new value:
- echo $(params.image_tag)
- yq w --inplace my-values.yaml 'image.tag' "$(params.image_tag)"
- echo verifying new value
- yq r my-values.yaml 'image.tag'
- if ! git diff-index --quiet HEAD --; then
- git status
- git add .
- git commit -m "helm values updated by tekton pipeline in change-manifests task"
- git push
- else
- echo "no changes, git repository is up to date"
- fi
現(xiàn)在我們的流水線就變成了如下所示的清單:
- # pipeline.yaml
- apiVersion: tekton.dev/v1beta1
- kind: Pipeline
- metadata:
- name: pipeline
- spec:
- workspaces: # 聲明 workspaces
- - name: go-repo-pvc
- params:
- # 定義代碼倉庫
- - name: git_url
- - name: git_infra_url
- - name: revision
- type: string
- default: "master"
- # 定義鏡像參數(shù)
- - name: image
- - name: image_tag
- - name: registry_url
- type: string
- default: "harbor.k8s.local"
- - name: registry_mirror
- type: string
- default: "https://ot2k4d59.mirror.aliyuncs.com/"
- - name: git_manifest_dir
- default: "helm"
- # 定義 argocd 參數(shù)
- - name: argocd_url
- - name: argocd_secret
- - name: app_name
- - name: app_revision
- type: string
- default: "HEAD"
- tasks: # 添加task到流水線中
- - name: clone
- taskRef:
- name: git-clone
- workspaces:
- - name: output
- workspace: go-repo-pvc
- params:
- - name: url
- value: $(params.git_url)
- - name: revision
- value: $(params.revision)
- - name: test
- taskRef:
- name: test
- - name: build # 編譯二進(jìn)制程序
- taskRef:
- name: build
- runAfter: # 測試任務(wù)執(zhí)行之后才執(zhí)行 build task
- - test
- - clone
- workspaces: # 傳遞 workspaces
- - name: go-repo
- workspace: go-repo-pvc
- - name: docker # 構(gòu)建并推送 Docker 鏡像
- taskRef:
- name: docker
- runAfter:
- - build
- workspaces: # 傳遞 workspaces
- - name: go-repo
- workspace: go-repo-pvc
- params: # 傳遞參數(shù)
- - name: image
- value: $(params.image):$(params.image_tag)
- - name: registry_url
- value: $(params.registry_url)
- - name: registry_mirror
- value: $(params.registry_mirror)
- - name: manifests
- taskRef:
- name: change-manifests
- runAfter:
- - docker
- params:
- - name: git_url
- value: $(params.git_infra_url)
- - name: git_manifest_dir
- value: $(params.git_manifest_dir)
- - name: image_tag
- value: $(params.image_tag)
- - name: sync
- taskRef:
- name: sync
- runAfter:
- - manifests
- params:
- - name: argocd_url
- value: $(params.argocd_url)
- - name: argocd_secret
- value: $(params.argocd_secret)
- - name: app_name
- value: $(params.app_name)
- - name: app_revision
- value: $(params.app_revision)
最后創(chuàng)建用于 Argo CD 登錄使用的 Secret 對象:
- apiVersion: v1
- kind: Secret
- metadata:
- name: argocd-auth
- type: Opaque
- stringData:
- username: admin
- password: admin321
最后修改 Tekton Triggers 中的 Template,如下所示:
- # gitlab-template.yaml
- apiVersion: triggers.tekton.dev/v1alpha1
- kind: TriggerTemplate
- metadata:
- name: gitlab-template
- spec:
- params: # 定義參數(shù),和 TriggerBinding 中的保持一致
- - name: gitrevision
- - name: gitrepositoryurl
- resourcetemplates: # 定義資源模板
- - apiVersion: tekton.dev/v1beta1
- kind: PipelineRun # 定義 pipeline 模板
- metadata:
- generateName: gitlab-run- # TaskRun 名稱前綴
- spec:
- serviceAccountName: tekton-build-sa
- pipelineRef:
- name: pipeline
- workspaces:
- - name: go-repo-pvc
- persistentVolumeClaim:
- claimName: go-repo-pvc
- params:
- - name: git_url
- value: $(tt.params.gitrepositoryurl)
- - name: git_infra_url
- value: git.k8s.local/course/devops-demo-deploy.git
- - name: image
- value: "harbor.k8s.local/course/devops-demo"
- - name: image_tag
- value: "$(tt.params.gitrevision)"
- - name: argocd_url
- value: argocd.k8s.local
- - name: argocd_secret
- value: argocd-auth
- - name: app_name
- value: devops-demo
現(xiàn)在我們的整個流水線就更加精簡了?,F(xiàn)在我們?nèi)?yīng)用倉庫中修改下源代碼并提交就可以觸發(fā)我們的流水線了。
可以看到當(dāng)我們提交代碼后,整個流水線構(gòu)建會一直卡在最后的 sync 任務(wù),這是因為我們執(zhí)行了 argocd app wait $(params.app_name) --health 這個命令,需要等待應(yīng)用健康后才會退出。
- $ curl devops-demo.k8s.local
- {"msg":"Hello Tekton + ArgoCD On GitLab"}
但實際上上面我們的應(yīng)用已經(jīng)部署成功了,只是 Argo CD 的健康檢查沒有通過,Argo CD 為幾種標(biāo)準(zhǔn)的 Kubernetes 資源提供了內(nèi)置的健康策略,然后將這些策略作為一個整體呈現(xiàn)在應(yīng)用的健康狀態(tài)中,比如會檢查副本數(shù)是否正常,PVC 是否綁定等,而對于 Ingress 資源會檢查 status.loadBalancer.ingress 列表是否非空,需要至少有一個 hostname 或 IP 值,而我們這里部署的 Ingress 中的值為空:
- $ kubectl get ingress devops-demo -o yaml
- apiVersion: extensions/v1beta1
- kind: Ingress
- ......
- spec:
- rules:
- - host: devops-demo.k8s.local
- http:
- paths:
- - backend:
- serviceName: devops-demo
- servicePort: http
- path: /
- pathType: ImplementationSpecific
- status:
- loadBalancer: {}
所以健康檢查一直不通過,在 Argo CD 頁面上也可以證實是 Ingress 導(dǎo)致健康檢查沒通過:
這個時候需要我們?nèi)プ远x Ingress 資源的監(jiān)控檢查方式,Argo CD 支持用 Lua 來編寫檢查規(guī)則,修改 Argo CD 的 Configmap 配置文件:
- $ kubectl edit cm -n argocd argocd-cm
- # Please edit the object below. Lines beginning with a '#' will be ignored,
- # and an empty file will abort the edit. If an error occurs while saving this file will be
- # reopened with the relevant failures.
- #
- apiVersion: v1
- data:
- resource.customizations: | # 定制 Ingress 資源的健康檢查方式
- extensions/Ingress:
- health.lua: |
- hs = {}
- hs.status = "Healthy"
- return hs
- ......
修改完成后,我們的應(yīng)用就會變成健康狀態(tài)了。
如果需要回滾,則可以直接在 Argo CD 頁面上點擊 HISTORY AND ROLLBACK 安裝查看部署的歷史記錄選擇回滾的版本即可:
可以查看整個 Tekton 流水線的狀態(tài):
- $ tkn pr describe gitlab-run-vdlm6
- Name: gitlab-run-vdlm6
- Namespace: default
- Pipeline Ref: pipeline
- Service Account: tekton-build-sa
- Timeout: 1h0m0s
- Labels:
- tekton.dev/pipeline=pipeline
- triggers.tekton.dev/eventlistener=gitlab-listener
- triggers.tekton.dev/trigger=gitlab-push-events-trigger
- triggers.tekton.dev/triggers-eventid=eeda9157-5eb3-4399-be4b-88955cb56764
- 🌡️ Status
- STARTED DURATION STATUS
- 4 minutes ago 2 minutes Succeeded
- 📦 Resources
- No resources
- ⚓ Params
- NAME VALUE
- ∙ git_url http://git.k8s.local/course/devops-demo.git
- ∙ git_infra_url git.k8s.local/course/devops-demo-deploy.git
- ∙ image harbor.k8s.local/course/devops-demo
- ∙ image_tag 332798d9e28422341fd64704ab9b54b944d77084
- ∙ argocd_url argocd.k8s.local
- ∙ argocd_secret argocd-auth
- ∙ app_name devops-demo
- 📝 Results
- No results
- 📂 Workspaces
- NAME SUB PATH WORKSPACE BINDING
- ∙ go-repo-pvc --- PersistentVolumeClaim (claimName=go-repo-pvc)
- 🗂 Taskruns
- NAME TASK NAME STARTED DURATION STATUS
- ∙ gitlab-run-vdlm6-sync-svmxl sync 3 minutes ago 42 seconds Succeeded
- ∙ gitlab-run-vdlm6-manifests-d297d manifests 3 minutes ago 26 seconds Succeeded
- ∙ gitlab-run-vdlm6-docker-g2tqx docker 4 minutes ago 48 seconds Succeeded
- ∙ gitlab-run-vdlm6-build-mkcrd build 4 minutes ago 9 seconds Succeeded
- ∙ gitlab-run-vdlm6-test-gjr4c test 4 minutes ago 4 seconds Succeeded
- ∙ gitlab-run-vdlm6-clone-57vpw clone 4 minutes ago 8 seconds Succeeded
最后用一張圖來總結(jié)下我們使用 Tekton 結(jié)合 Argo CD 來實現(xiàn) GitOps 的工作流: