Tekton 与 Argo CD 结合实现 GitOps
前面我们使用 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
:项目内资源访问定义的角色
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
# 项目名
name: demo
namespace: argocd
spec:
# 目标
destinations:
# 此项目的服务允许部署的 namespace,这里为全部
- namespace: '*'
# 此项目允许部署的集群,这里为默认集群,即为Argo CD部署的当前集群
server: https://kubernetes.default.svc
# 允许的数据源
sourceRepos:
- http://git.k8s.local/course/devops-demo-deploy.git
更多配置信息可以前往文档 https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/ 查看,项目创建完成后,在该项目下创建一个 Application,代表环境中部署的应用程序实例。
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 存储库创建应用程序时,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
的应用,应用源来自于 helm 路径,使用的是 my-values.yaml
文件,此外还可以通过 source.helm.parameters
来配置参数,同步策略我们仍然选择使用手动的方式,我们可以在 Tekton 的任务中去手动触发同步。上面的资源对象创建完成后应用就会处于 OutOfSync
状态,因为集群中还没部署该应用。
现在接下来我们去修改之前的 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"
# 定义镜像参数
- name: image
- name: registry_url
type: string
default: "harbor.k8s.local"
- name: registry_mirror
type: string
default: "https://ot2k4d59.mirror.aliyuncs.com/"
# 定义 helm charts 参数
- 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 # 编译二进制程序
taskRef:
name: build
runAfter: # 测试任务执行之后才执行 build task
- test
- clone
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc
- name: docker # 构建并推送 Docker 镜像
taskRef:
name: docker
runAfter:
- build
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc
params: # 传递参数
- name: image
value: $(params.image)
- name: registry_url
value: $(params.registry_url)
- name: registry_mirror
value: $(params.registry_mirror)
- name: deploy # 部署应用
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)
现在我们需要去掉最后的 deploy 和 rollback 两个任务,当 Docker 镜像构建推送完成后,我们只需要去修改部署代码仓库中的 values 文件,然后再去手动触发 Argo CD 同步状态即可(如果开启了自动同步这一步都可以省略了),而回滚操作直接在 Argo CD 中去操作即可,不需要定义一个单独的 Task 任务。
定义一个如下所示的 Taks 任务:
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
参数,最好的方式当然还是在一个 Task 中去修改 values.yaml 文件并 commit 到 Repo 仓库中去,当然也可以为了简单直接在 Argo CD 的应用侧配置参数即可,比如可以使用 argocd app set
命令来为应用配置参数,然后下面再用 argocd app sync
命令手动触发同步操作,这里其实就可以有很多操作了,比如我们可以根据某些条件来判断是否需要部署,满足条件后再执行 sync 操作,最后使用 wait
命令等待应用部署完成。
除了通过手动 argocd app set
的方式来配置参数之外,可能更好的方式还是直接去修改 Repo 仓库中的 values 值,这样在源代码仓库中有一个版本记录,我们可以新建如下所示的一个任务用来修改 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
现在我们的流水线就变成了如下所示的清单:
# 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"
# 定义镜像参数
- 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 参数
- 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 # 编译二进制程序
taskRef:
name: build
runAfter: # 测试任务执行之后才执行 build task
- test
- clone
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc
- name: docker # 构建并推送 Docker 镜像
taskRef:
name: docker
runAfter:
- build
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc
params: # 传递参数
- 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)
最后创建用于 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: # 定义参数,和 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
现在我们的整个流水线就更加精简了。现在我们去应用仓库中修改下源代码并提交就可以触发我们的流水线了。
可以看到当我们提交代码后,整个流水线构建会一直卡在最后的 sync 任务,这是因为我们执行了 argocd app wait $(params.app_name) --health
这个命令,需要等待应用健康后才会退出。
$ curl devops-demo.k8s.local
{"msg":"Hello Tekton + ArgoCD On GitLab"}
但实际上上面我们的应用已经部署成功了,只是 Argo CD 的健康检查没有通过,Argo CD 为几种标准的 Kubernetes 资源提供了内置的健康策略,然后将这些策略作为一个整体呈现在应用的健康状态中,比如会检查副本数是否正常,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 导致健康检查没通过:
这个时候需要我们去自定义 Ingress 资源的监控检查方式,Argo CD 支持用 Lua 来编写检查规则,修改 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
......
修改完成后,我们的应用就会变成健康状态了。
如果需要回滚,则可以直接在 Argo CD 页面上点击 HISTORY AND ROLLBACK
安装查看部署的历史记录选择回滚的版本即可:
可以查看整个 Tekton 流水线的状态:
$ 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
最后用一张图来总结下我们使用 Tekton 结合 Argo CD 来实现 GitOps 的工作流:
K8S 进阶训练营
扫描二维码获取
更多云原生知识
k8s 技术圈