监听镜像版本变化触发 GitOps工作流

文章目录

      • 前言
      • 工作流总览
      • 安装和配置 ArgoCD Image Updater
      • 创建 Image Pull Secret(可选)
      • 创建 Helm Chart 仓库
      • 创建 ArgoCD Application
        • 删除旧应用(可选)
        • 配置仓库访问权限
        • 创建 ArgoCD 应用
      • 体验 GitOps 工作流
      • 总结

前言

在【GitOps系列】使用 ArgoCD 快速打造GitOps工作流 博文中,我们创建的 GitOps 工作流有下面两个重要的特点:

  1. 源码和 Helm Chart 在同一个仓库下
  2. 在 CI 阶段更新了 Helm Chart 镜像版本

在开发和发布分工明确的团队中,更推荐将源码和应用定义分离,考虑到安全性和发布的严谨性,也尽量不要通过 CI 直接修改应用定义。

更合理的研发规范设计应该是这样的:

开发负责编写代码,并通过 CI 生成制品(Docker 镜像),并对生成的制品负责。而SRE 团队则对应用定义负责。在发布环节, 开发可以随时控制要发布的镜像版本,而无需关注其他的应用细节,他们之间的工作流程图如下:
监听镜像版本变化触发 GitOps工作流_第1张图片
以上工作流程图我们可以看出,开发和 SRE 团队各司其职,只操作和自己相关的 Git 仓库,互不干扰。但 SRE 团队要怎么知道开发团队什么时候发布以及发布什么版本的镜像呢?
最原始的办法是:开发在需要发布的时候将镜像版本告诉 SRE 团队,SRE 团队手动修改 Helm Chart 镜像版本并推送到 Git 仓库,等待 ArgoCD 同步完成。
这种办法虽然有效,但沟通效率低且容易出错, 我们需要一种自动化的机制来替代这个过程。
那就是借助 ArgoCD Image Updater,我们可以让 ArgoCD 自动监控镜像仓库的更新情况,一旦工作负载中的镜像版本有更新,ArgoCD 就会自动将工作负载升级为新的镜像版本,并且还可以自动将镜像的版本号回写到 Helm Chart 仓库中,保持应用定义和集群状态的一致性。

工作流总览

最终要期望实现的效果如下:
监听镜像版本变化触发 GitOps工作流_第2张图片

  1. 将一个 Git 仓库拆分成了两个,一个存放源码,一个存放 Helm Chart;
  2. 不再使用 CI 更新 Helm Chart 镜像版本,而是使用 ArgoCD Image Updater 来自动监控镜像仓库的变更。

此外,由于在日常开发中,我们一般会采用多分支进行开发,这就随时可能产生新的镜像版本。为了将开发过程和需要发布到生产环境的镜像区分开,我们会为 Main 分支构建出来的镜像增加一个 Prefix 标识,例如 main-${commit_Id},并配置 ArgoCD Image Updater 只监控包含特定标识的镜像版本。
最终实现的效果是:
当开发将代码提交到 Git 仓库 Main 分支后,将触发自动构建,并将新的镜像版本推送到镜像仓库。ArgoCD Image Updater 会以 Poll 的方式每 2 分钟检查一次工作负载的镜像是否有新的版本,如果有,那么就将工作负载的镜像更新为最新版本,并将镜像版本号写入同步到存放 Helm Chart 的仓库中。

安装和配置 ArgoCD Image Updater

注: 前提需要安装好ArgoCD ~~~
~# kubectl apply -n argocd -f https://ghproxy.com/https://raw.githubusercontent.com/argoproj-labs/argocd-image-updater/stable/manifests/install.yaml

创建 Image Pull Secret(可选)

由于 ArgoCD 会主动 Poll 镜像仓库来检查是否存在新版本,如果你使用的是私有镜像仓库,那么你需要创建 Secret 对象,以便为 ArgoCD 提供访问镜像仓库的权限。
以 DockerHub 仓库为例,执行下面的命令来创建 Secret 对象:

$ kubectl create -n argocd secret docker-registry dockerhub-secret \
  --docker-username $DOCKER_USERNAME \
  --docker-password $DOCKER_PERSONAL_TOKEN \
  --docker-server "https://registry-1.docker.io"

secret/dockerhub-secret created

创建 Helm Chart 仓库

 $ cp -r ./kubernetes-example/helm ./kubernetes-example-helm
 $ cd kubernetes-example-helm && git init
PS:前往 GitHub 创建一个新的仓库,将其命名为 kubernetes-example-helm
$ git add .
$ git commit -m "first commit"
$ git branch -M main
$ git remote add origin https://github.com/Hugh-yw/kubernetes-example-helm.git
$ git push -u origin main

创建 ArgoCD Application

删除旧应用(可选)

清理之前实践的应用!!!
$ argocd app delete example --cascade

配置仓库访问权限

创建 ArgoCD 应用时,必须要配置仓库访问权限,但这里额外还实现了一个重要的功能:为 ArgoCD Image Updater 提供回写kubernetes-example-helm仓库的权限。

$ argocd repo add https://github.com/Hugh-yw/kubernetes-example-helm.git --username $USERNAME --password $PASSWORD

~# argocd repo list
TYPE  NAME  REPO                                                    INSECURE  OCI    LFS    CREDS  STATUS      MESSAGE  PROJECT
git         https://github.com/Hugh-yw/kubernetes-example-helm.git  false     false  false  true   Successful           
git         https://github.com/Hugh-yw/kubernetes-example.git       false     false  false  true   Successful       

创建 ArgoCD 应用

通过YAML创建:

# cat application.yaml 
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: example
  annotations:
    argocd-image-updater.argoproj.io/backend.allow-tags: regexp:^main
    argocd-image-updater.argoproj.io/backend.helm.image-name: backend.image
    argocd-image-updater.argoproj.io/backend.helm.image-tag: backend.tag
    argocd-image-updater.argoproj.io/backend.pull-secret: pullsecret:argocd/dockerhub-secret
    argocd-image-updater.argoproj.io/frontend.allow-tags: regexp:^main
    argocd-image-updater.argoproj.io/frontend.helm.image-name: frontend.image
    argocd-image-updater.argoproj.io/frontend.helm.image-tag: frontend.tag
    argocd-image-updater.argoproj.io/frontend.pull-secret: pullsecret:argocd/dockerhub-secret
    argocd-image-updater.argoproj.io/image-list: frontend=cyw/frontend, backend=cyw/backend
    argocd-image-updater.argoproj.io/update-strategy: latest
    argocd-image-updater.argoproj.io/write-back-method: git
spec:
  destination:
    namespace: gitops-example-updater
    server: https://kubernetes.default.svc
  project: default
  source:
    path: .
    repoURL: https://github.com/Hugh-yw/kubernetes-example-helm.git
    targetRevision: main
  syncPolicy:
    automated: {}
    syncOptions:
      - CreateNamespace=true

$ kubectl create -f application.yaml  -n argocd 
PS:效果等同于使用 argocd app create 命令

ArgoCD Image Updater 通过 Application Annotations 标签来实现对应的功能,简单介绍下每一个标签的作用:

  • argocd-image-updater.argoproj.io/image-list:指定需要监听的镜像,这里我们指定示例应用的前后端镜像 cyw/frontend 和 cyw/backend,同时为前后端镜像法指定了别名,分别为 frontend 和 backend。这里的别名非常重要,会影响下面所有的设置。
  • argocd-image-updater.argoproj.io/update-strategy:指定镜像更新策略。注意, latest 并不代表监听 latest 镜像版本,而是以最新推送的镜像作为更新策略。此外,semver 策略可以识别最高语义化版本的标签,digest 策略可以用来区分同一 Tag 下不同镜像 digest 的变更。
  • argocd-image-updater.argoproj.io/write-back-method:表示将镜像版本回写到镜像仓库。注意,这里对仓库的写权限来源于使用 argocd repo add 命令为 ArgoCD 配置的仓库访问权限。
  • argocd-image-updater.argoproj.io/<镜像别名>.pull-secret:为不同的镜像别名指定镜像拉取凭据。
  • argocd-image-updater.argoproj.io/<镜像别名>.allow-tags:配置符合更新条件的镜像 Tag,在这里我们使用正则表达式匹配那些镜像 Tag 以 main 开头的镜像版本,其他镜像版本则忽略。
  • argocd-image-updater.argoproj.io/<镜像别名>.helm.image-name:配置 Helm Chart values.yaml 镜像名称所在的节点,在示例应用中,backend.image 和 frontend.image 是values.yaml 配置镜像名称的节点,ArgoCD 在回写仓库时会覆盖这个值。
  • argocd-image-updater.argoproj.io/<镜像别名>.helm.image-tag:配置 Helm Chart values.yaml 镜像版本所在的节点,在示例应用中,backend.tag 和 frontend.tag 是 values.yaml 配置镜像版本的节点,ArgoCD 在回写仓库时将会覆盖这个值。

体验 GitOps 工作流

作为开发同学,尝试修改 frontend/src/App.js 源代码文件,例如修改文件第 49 行的“Hi! I am a geekbang”内容。修改完成后, 将代码推送到 GitHub 的 main 分支 merge。
此时会触发两个 GitHub Action 工作流。其中,当 build-every-branch 工作流被触发时,它将构建 Tag 为 main 开头的镜像版本,并将其推送到镜像仓库中,如下图所示:
监听镜像版本变化触发 GitOps工作流_第3张图片
跟另一个 GitHub Action 工作流不同的是:
它也不会去主动修改 kubernetes-example-helm 仓库的 values.yaml 文件,在完成镜像推送后工作流也就结束了。
与此同时,ArgoCD Image Updater 将会每 2 分钟从镜像仓库检索 frontend 和 backend 的镜像版本,一旦发现有新的并且以 main 开头的镜像版本,它将自动使用新版本来更新集群内工作负载的镜像,并将镜像版本回写到 kubernetes-example-helm 仓库。
在回写时,ArgoCD Image Updater 并不会直接修改仓库的 values.yaml 文件,而是会创建一个专门用于覆盖 Helm Chart values.yaml 的.argocd-source-example.yaml文件。
监听镜像版本变化触发 GitOps工作流_第4张图片
当我们看到这个文件时,说明 ArgoCD Image Updater 已经触发了镜像更新,并且成功将镜像版本回写到了镜像仓库。同时,这个文件记录了详细的覆盖 values.yaml 值的策略。
这样,当 ArgoCD 在做自动同步时,会将这份文件的内容覆盖 values.yaml 对应的值,比如 frontend.tag 的值会被覆盖为 main-e1f492f,这样,回写后的 Helm Chart 和集群内资源对象就仍然能够保持一致性。

至此,我们就完成了通过监听新镜像版本来触发 GitOps 工作流的整个过程。

总结

此次实践,我们将应用源码和应用定义(Helm Chart)拆分成了两个仓库,在开发和发布角色相对独立的研发流程下,这种方式既能够保持他们之间职责独立,权责清晰,同时还保留了开发随时发布生产环境的能力,但是希望集成审批流程,有足够权限的人审批通过后再进行发布!

值得注意的是:在实际的业务场景中,研发同学一般会使用多分支的模式来开发。这意味着每个分支的每个提交都会产生新的镜像版本,所以,为了区分开发过程的镜像和需要被发布到生产环境的镜像,在此次实践中约定了以main开头的镜像版本即为需要发布到生产环境的镜像版本。你可以根据项目的实际情况做调整,例如使用v1.0.0的版本号来区分,同时更新argocd-image-updater.argoproj.io/<镜像别名>.allow-tags字段的正则表达式。

总体来说,在这种仓库分离的场景下,要将开发者的提交和发布过程自动化地连接起来,双方需要重点关注生产环境的镜像版本策略,并将它配置到 ArgoCD 应用的 Annotations 注解内,这样便能够让 ArgoCD Image Updater 代替人工来自动监控需要发布到生产环境的image。

你可能感兴趣的:(CLOUD,NATIVE,#,Kubernetes,CI/CD,GitOps)