基于ACK One GitOps和ACR构建CI/CD流水线

ACK One GitOps可实现多集群GitOps应用的持续交付,容器镜像服务ACR支持绑定业务代码仓库,以实现应用的持续集成。本实践基于这两者构建开发(Dev)、预发(Staging)、生产(Production)集群的CI/CD流水线,实现代码修改提交到代码仓库后,自动将最新镜像更新至应用,并将最新镜像部署到各环境中。

使用限制

  • 仅适用于通过ACK One GitOps系统创建的应用。

  • 仅适用于通过Kustomize或Helm编排渲染托管在Git系统中的应用编排。

前提条件

流程概述

本实践基于ACK One GitOps和ACR来构建开发(Dev)、预发(Staging)、生产(Production)集群的CI/CD流水线,实现代码修改提交到Git仓库后,自动将最新镜像更新至应用,并按以下方式部署最新镜像到各环境中。

  • Dev集群:应用自动同步,部署最新镜像。

  • Staging、Produciton集群:应用手动同步,并基于Rollout灰度发布,部署最新镜像。

image
  1. 准备业务仓库代码仓库和应用部署代码仓库。

  2. 开启和登录ACK One GitOps后,运维团队首先配置CI构建流程和规则,并关联ACR EE实例。

  3. 开发团队将代码推送到代码仓库中,触发ACR EE构建镜像,并将新版本的镜像推送到ACR EE镜像仓库中。

  4. 镜像仓库的变更会被ACK One GitOps检测到,然后,ACK One GitOps将新的镜像版本号回写到应用部署代码仓库中。

  5. ACK One GitOps检测到应用部署代码仓库中镜像版本号的变化后,触发Application将最新镜像部署到持续集成开发集群(Dev)。

    • 对于配置了自动同步Application的持续集成测试集群,ACK One GitOps会自动变更应用的镜像版本。

    • Image Updater会监测镜像仓库中符合配置规则的镜像的更新。

    • ArgoCD会监测应用部署仓库中YAML的变化。

  6. 在完成持续部署之后,开发团队验证Dev环境中的应用是否符合预期。

  7. Dev环境验证符合预期后,由运维团队手动触发预发(Staging)和生产(Production)环境的应用同步,并使用Argo Rollout或Kruise Rollout实现灰度发布,最终更新预发和生产环境中应用的镜像。更多信息,请参见基于ACK One Gitops使用Argo Rollouts实现金丝雀发布基于ACK One Gitops使用Kruise Rollout实现金丝雀发布

    重要

    预发(Staging)和生产(Production)集群一般需要通过额外的发布流程来做多集群多地域的滚动发布,不能通过代码变更直接影响到预发和生产环境。

示例说明

本文的应用示例为echo-server示例,业务代码仓库包含2个,分别从echo-server项目echo-web-server项目分支得到;应用部署代码仓库是Fork的gitops-demo项目。由于涉及到将应用变更回写到应用部署代码仓库,所以您首先需要将该仓库Fork到您自己的账号下,并可根据个人情况修改配置,例如不同环境对应的values.yaml中的image.repositoryimage.tag。关于本实践的最终改动,请参见echo-server example

image:
  repository: registry.cn-hangzhou.aliyuncs.com/haoshuwei24/echo-server
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: "v1.0"

步骤一:基于ACR构建CI

创建ACR镜像仓库,绑定您Fork的echo-server项目,并设置构建规则。具体配置操作请参见使用企业版实例构建镜像。您可以在企业版实例的概览页开启公开匿名拉取或参见使用免密组件拉取容器镜像来免密拉取镜像。

说明

如果您使用的代码源是Github,并且遇到了拉取代码超时的问题,可开启海外机器构建来尝试解决问题。

本实践ACR配置的规则如下:检测到有新的release-开头的Tag,ACR就会自动Build docker image并Push到相应的镜像仓库。规则中正则表达式您可按需设置。

image.png

步骤二:为GitOps配置ACR镜像仓库和应用部署仓库凭证

ACK One GitOps组件会自动监听ACR镜像仓库的变化,并拉取最新镜像,同时会将最新镜像Tag信息回写到Git仓库中,更新应用。您通过为GitOps配置相应的访问凭证,可实现与ACR、Git仓库的交互。

  1. 连接和访问GitOps系统。具体操作,请参见登录GitOps系统

  2. 添加Git源仓库。具体操作,请参见添加仓库

  3. 创建GitOps应用。具体操作,请参见Application管理

  4. 配置ACR镜像仓库访问凭证,以使GitOps监听ACR镜像变化。

    执行以下命令,在ACK One Fleet实例的argocd命名空间下配置名为acr的Secret资源。

    kubectl -n argocd apply -f - <<EOF
    apiVersion: v1
    kind: Secret
    metadata:
      name: acr
    type: Opaque
    stringData:
      acr: <your_username>:<your_password>  # 将<your_username>:<your_password>更换为您自己的容器镜像仓库访问凭证。
    EOF
  5. 配置Git仓库访问凭证,以使GitOps回写应用镜像变更信息到Git仓库。

若您在GitOps系统中添加Git仓库时,配置了用户名和密码或配置了私钥证书,则使用该Git仓库的应用默认拥有回写应用容器镜像变更信息到Git系统的权限。

添加Git仓库时,已配置用户名和密码、私钥证书(包含使用SSH私钥添加的Repo)

您可以通过添加以下Annotation,配置使用该Git仓库的访问凭证:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-image-updater.argoproj.io/write-back-method: git

添加Git仓库时,未配置用户名和密码、私钥证书

您可以通过添加以下Annotation,配置使用该Git仓库的访问凭证:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  annotations:
    argocd-image-updater.argoproj.io/write-back-method: git:secret:argocd/git-creds

其中git:secret:argocd/git-creds表示argocd命名空间下名为git-creds的Secret资源,创建该Secret的示例如下所示:

kubectl -n argocd create secret generic git-creds \
--from-literal=username=<your_username> \
--from-literal=password=<your_password>

步骤三:配置应用的自动更新并多个集群部署应用

应用的自动更新配置可以通过在Application上添加以下Annotations实现,更多配置信息请参见更多应用镜像自动更新的相关配置

metadata:
  annotations:
    argocd-image-updater.argoproj.io/image-list: echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server,webserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-web-server
    argocd-image-updater.argoproj.io/echoserver.helm.image-name: image.echoServer.repository
    argocd-image-updater.argoproj.io/echoserver.helm.image-tag: image.echoServer.tag
    argocd-image-updater.argoproj.io/echoserver.update-strategy: latest
    argocd-image-updater.argoproj.io/webserver.helm.image-name: image.echoWebServer.repository
    argocd-image-updater.argoproj.io/webserver.helm.image-tag: image.echoWebServer.tag
    argocd-image-updater.argoproj.io/webserver.update-strategy: latest
    argocd-image-updater.argoproj.io/write-back-method: git:secret:argocd/git-creds
  • argocd-image-updater.argoproj.io/image-list的value中的echoserver是别名,其值为镜像仓库地址,可配置多个地址,中间用英文半角逗号(,)分隔。请根据您实际情况进行修改。

  • 此处为Helm编排的应用的配置,对于Kustomize编排的应用的配置,请参见Kustomize编排的应用参数设置

在开发集群上部署应用并实现自动部署最新的镜像

  1. 使用以下YAML内容,在开发集群上创建app-helm-dev.yaml文件。

    • ${url}:替换为开发集群的Server URL。关于如何获取集群的Server URL,请参见使用GitOps管理集群

    • repoURL:替换为您实际的应用部署仓库地址。

    由于在syncPolicy中配置了automated,所以在按规则提交了新Branch、Tag以后,可以实现自动同步和部署。

    apiVersion: argoproj.io/v1alpha1
    kind: Application
    metadata:
      name: app-helm-dev
      annotations:
        argocd-image-updater.argoproj.io/image-list: echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server,webserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-web-server
        argocd-image-updater.argoproj.io/echoserver.helm.image-name: image.echoServer.repository
        argocd-image-updater.argoproj.io/echoserver.helm.image-tag: image.echoServer.tag
        argocd-image-updater.argoproj.io/echoserver.update-strategy: latest
        argocd-image-updater.argoproj.io/webserver.helm.image-name: image.echoWebServer.repository
        argocd-image-updater.argoproj.io/webserver.helm.image-tag: image.echoWebServer.tag
        argocd-image-updater.argoproj.io/webserver.update-strategy: latest
        argocd-image-updater.argoproj.io/write-back-method: git
    spec:
      destination:
        namespace: app-helm-dev
        # https://XX.XX.XX.XX:6443
        server: ${url}
      source:
        path: manifests/helm/echo-server
        repoURL: 'git@github.com:ivan-cai/gitops-demo.git'
        targetRevision: stable-example
        helm:
          valueFiles:
            - values-dev.yaml
      project: default
      syncPolicy:
        automated: {}
        syncOptions:
          - CreateNamespace=true
  1. 部署开发环境应用。

    连接至ACK One Fleet实例,执行以下命令创建部署到开发环境的应用。

    您也可以将以下YAML复制到ArgoCD UI中创建。

    argocd app create -f app-helm-dev.yaml

在预发和生产集群上部署应用并实现手动触发灰度发布

  1. 使用以下YAML内容,在预发和生产集群上创建app-helm-staging.yaml和app-helm-production.yaml文件。

    • ${url}:分别替换为预发和生产集群的Server URL。关于如何获取集群的Server URL,请参见使用GitOps管理集群

    • repoURL:替换为您实际的应用部署仓库地址。

    由于在syncPolicy中未配置automated,所以在按规则提交了新Branch、Tag以后,只能手动同步,触发部署最新镜像。

    • 预发集群对应Application

    • 展开查看预发集群对应Application的app-helm-staging.yaml

      apiVersion: argoproj.io/v1alpha1
      kind: Application
      metadata:
        name: app-helm-staging
        annotations:
          argocd-image-updater.argoproj.io/image-list: echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server,webserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-web-server
          argocd-image-updater.argoproj.io/echoserver.helm.image-name: image.echoServer.repository
          argocd-image-updater.argoproj.io/echoserver.helm.image-tag: image.echoServer.tag
          argocd-image-updater.argoproj.io/echoserver.update-strategy: latest
          argocd-image-updater.argoproj.io/webserver.helm.image-name: image.echoWebServer.repository
          argocd-image-updater.argoproj.io/webserver.helm.image-tag: image.echoWebServer.tag
          argocd-image-updater.argoproj.io/webserver.update-strategy: latest
          argocd-image-updater.argoproj.io/write-back-method: git
      spec:
        destination:
          namespace: app-staging
          # https://XX.XX.XX.XX:6443
          server: ${url}
        source:
          path: manifests/helm/echo-server
          repoURL: 'git@github.com:ivan-cai/gitops-demo.git'
          targetRevision: stable-example
          helm:
            valueFiles:
              - values-staging.yaml
        project: default
        syncPolicy:
          syncOptions:
            - CreateNamespace=true
    • 生产集群对应Application

    • 展开查看生产集群对应Application的app-helm-staging.yaml

      apiVersion: argoproj.io/v1alpha1
      kind: Application
      metadata:
        name: app-helm-production
        annotations:
          argocd-image-updater.argoproj.io/image-list: echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server,webserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-web-server
          argocd-image-updater.argoproj.io/echoserver.helm.image-name: image.echoServer.repository
          argocd-image-updater.argoproj.io/echoserver.helm.image-tag: image.echoServer.tag
          argocd-image-updater.argoproj.io/echoserver.update-strategy: latest
          argocd-image-updater.argoproj.io/webserver.helm.image-name: image.echoWebServer.repository
          argocd-image-updater.argoproj.io/webserver.helm.image-tag: image.echoWebServer.tag
          argocd-image-updater.argoproj.io/webserver.update-strategy: latest
          argocd-image-updater.argoproj.io/write-back-method: git
      spec:
        destination:
          name: ''
          namespace: app-production
          server: 'https://39.98.XX.XX:6443'
        source:
          path: manifests/helm/echo-server
          repoURL: 'git@github.com:ivan-cai/gitops-demo.git'
          targetRevision: test2
          helm:
            valueFiles:
              - values-production.yaml
        project: default
        syncPolicy:
          syncOptions:
            - CreateNamespace=true
  2. 查看镜像变更并手动同步变更。

    1. 当存在镜像变更时,您可以查看应用部署仓库是否有更新,也可以在ArgoCD UI的应用页面,单击REFRESH刷新,更新后单击SYNC进行同步。您还可以通过应用详情页查看APP DIFFimage.png

    2. 连接至ACK One Fleet实例,执行以下命令创建部署到预发和生产环境的应用。

      argocd app sync argocd/app-helm-staging
      argocd app sync argocd/app-helm-production
  3. 触发灰度发布(金丝雀发布)。具体操作,请参见基于ACK One Gitops使用Kruise Rollout实现金丝雀发布

    执行以下命令,恢复灰度发布。

    kubectl-kruise rollout approve rollout/rollouts-demo  --kubeconfig <子集群KubeConfig文件路径>
    说明

    本实践使用Kruise Rollout完成灰度发布,您可以通过Argo Rollouts实现灰度发布。具体操作,请参见基于ACK One Gitops使用Argo Rollouts实现金丝雀发布

步骤四:回滚应用

如果应用发布失败,则需要回滚应用。您可以通过以下两种方式进行应用回滚。

快速回滚

  • 在ArgoCD控制台的应用页面,单击HISTORY AND ROLLBACK,然后选择相应版本,单击ROLLBACK进行回滚。更多信息,请参见回滚应用版本

  • 通过ArgoCD CLI回滚应用。具体操作,请参见通过Argo CLI回滚应用

端到端回滚

您可以通过以下Git命令完成回滚提交的代码,并自动触发CI/CD。

# 回滚上一个commit。
git revert HEAD
# git revert HEAD~3..HEAD 表示从当前 HEAD 节点开始向前回退3个commit。
# git revert <commit-id-1> <commit-id-2> ... <commit-id-n> 可用来回退非连续的多个commit。

# revert完后,推送至原来分支,触发CI/CD。
git push origin HEAD:${branch}

回滚后的变更被Image Updater更新到应用部署代码仓库后,再次同步到应用中。

步骤五:测试CI/CD流水线

  1. 根据ACR CI配置的构建规则,向源代码仓库推送满足规则的Branch/Tag,触发ACR自动Build并Push image。可执行以下命令,推送新的Tag,您可按需设置实际Tag名称。

    git clone https://github.com/{xxx}/echo-web-server.git
    cd echo-web-server
    git push origin HEAD:release-v3
  2. 查看新的镜像是否构建完成。

    1. 登录容器镜像服务控制台

    2. 在顶部菜单栏,选择所需地域。

    3. 在左侧导航栏,选择实例列表

    4. 实例列表页面单击目标企业版实例。

    5. 在企业版实例管理页面选择仓库管理 > 镜像仓库

    6. 在镜像仓库页面,单击目标镜像仓库,然后在左侧导航栏选择构建,在构建日志区域,查看新的镜像是否构建完成。

  3. 新镜像构建完成以后,执行以下命令,查看argocd-image-updater的日志。

    kubectl -nargocd logs argocd-server-<xxxxx> -c argocd-image-updater -f

    预期输出:

    time="2023-07-19T07:35:41Z" level=info msg="Successfully updated image 'demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-web-server:v1.0' to 'demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-web-server:v3-5a7147', but pending spec update (dry run=false)" alias=echowebserver application=echo-web-server 
    time="2023-07-19T07:35:41Z" level=info msg="Committing 1 parameter update(s) for application echo-web-server" application=echo-web-server
  4. 在GitHub上查看应用部署代码仓库中是否自动生成manifests/helm/echo-server/.argocd-source-${appname}.yaml文件。如成功生成,表示回写成功。本实践将生成3个此类文件,分别对应开发、预发和生产环境下对应的3个Application,其中开发环境文件示例内容如下图所示。

    image.png

  5. 在开发环境查看Deployment的image已经更新为v3-5a7147版本;而预发环境和生产环境则需要手动触发同步,并触发灰度发布后,相应的Deployment的image才会变更为v3-5a7147版本。

更多应用镜像自动更新的相关配置

配置更新指定的容器镜像

您可以通过设置Annotation,为GitOps系统中创建的应用标记一个或者多个自动更新的容器镜像,格式如下。

argocd-image-updater.argoproj.io/image-list: <image_spec_list>

image_spec_list可以填写单个容器镜像,也可以填写多个,多个容器镜像之间用英文半角逗号(,)分割,每个容器镜像描述的格式如下所示。

<alias_name>=]<image_path>[:<version_constraint>

alias_name是应用的容器镜像别名,可用于在做其他配置时引用。别名需为字母字符串,且只允许在image-list的Annotation中使用。在本文示例中,指定需要自动更新的镜像为echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server:v1.0,为其设置的别名为echoserver

argocd-image-updater.argoproj.io/image-list: echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server:v1.0

镜像Tags的条件过滤

echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server:v1.0镜像为例,您可以设置过滤条件,当且仅当ACR镜像仓库中echo-server镜像有符合过滤条件的新Tags推送时,才触发应用的自动更新。

通过正则表达式过滤允许的Tags,规范如下所示。

argocd-image-updater.argoproj.io/<image_name>.allow-tags: <match_func>

其中,match_func的格式为标准的正则表达式。本示例如下所示。

argocd-image-updater.argoproj.io/echoserver.allow-tags: regexp:^v[1-9].*

设置容器镜像更新策略

容器镜像的更新策略有以下几种,默认镜像更新策略为semver。

更新策略

描述

semver

按语义化版本号排序并更新到最新的镜像Tag。

latest

按创建时间排序并更新到最新的镜像Tag。

说明

此时间并非镜像推送到仓库的时间。

name

按字母排序并更新到最新的镜像Tag。

digest

更新到最新推送的可变标签版本。

Annotation的格式如下所示。

argocd-image-updater.argoproj.io/<image_name>.update-strategy: <strategy>

本示例中使用的镜像更新策略为semver,如下所示。

argocd-image-updater.argoproj.io/echoserver.update-strategy: semver

Helm、Kustomize编排的应用参数设置

  • Helm编排的应用参数设置

应用可能包含多个容器镜像的描述,比如gitops-demo示例应用的values.yaml文件中有image.echoServer.repositoryimage.echoServer.tag配置,Annotations相关配置如下所示。

annotations:
  argocd-image-updater.argoproj.io/image-list: echoserver=demo-test-registry.cn-hangzhou.cr.aliyuncs.com/cidemo/echo-server:v1.0
  argocd-image-updater.argoproj.io/echoserver.helm.image-name: image.echoServer.repository
  argocd-image-updater.argoproj.io/echoserver.helm.image-tag: image.echoServer.tag
  argocd-image-updater.argoproj.io/echoserver.update-strategy: latest
  argocd-image-updater.argoproj.io/write-back-method: git
  • Kustomize编排的应用参数设置

Kustomize编排类型的应用容器镜像的自动更新设置,需要先设置被更新的容器镜像的别名(可以包含Tag),然后设置原始容器镜像地址(不包含Tag),Annotation格式如下所示:

annotations:
  argocd-image-updater.argoproj.io/image-list: <image_alias>=<image_name>:<image_tag>
  argocd-image-updater.argoproj.io/<image_alias>.kustomize.image-name: <original_image_name>