使用Argo Workflows构建CI Pipeline

Argo Workflows提供简单易用的接口和工具,您可以通过YAML定义工作流,快速设置和配置CI流水线。您可以在集群中实现任务的并行执行,动态扩展所需的计算资源,并提高CI流水线的运行效率。

功能介绍

Argo Workflows构建CI Pipeline时,主要使用BuildKit实现容器镜像的构建和推送,并使用BuildKit Cache加速镜像的构建。使用NAS存储Go mod cache,可加速go testgo build运行过程,最终大幅加速CI Pipeline的流程。

image

预置工作流模板说明

您可以直接使用预置模板,也可以基于预置模板自定义自己的CI工作流模板。本示例创建名为ci-go-v1的CI工作流模板(ClusterWorkflowTemplate),使用BuildKit Cache和NAS存储Go mode cache,以加速CI Pipeline的流程。

展开查看CI工作流模板包含的流程

  1. Git Clone和Checkout

    • 用于Clone Git仓库,将Git仓库Checkout到目标分支。

    • 获取Commit ID,在构建镜像时根据Commit ID追加Tag后缀。

  2. Run Go Test

    • 默认运行Git Repo(Go项目)中的所有测试用例。

    • 可通过工作流参数enable_test控制是否运行该步骤。

    • 其中Go mod cache存储在NAS的/pkg/mod目录,用于go test和后续的go build的加速。

  3. Build & Push Image

    • 使用BuildKit构建和推送容器镜像,并使用BuildKit Cache中registry类型的cache来加速镜像构建。

    • 镜像Tag默认使用{container_tag}-{commit_id}格式,可在提交工作流时通过参数控制是否追加Commit ID。

    • 推送镜像的同时,也会推送覆盖其latest版本镜像。

展开查看CI工作流模板内容

apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
  name: ci-go-v1
spec:
  entrypoint: main
  volumes:
  - name: run-test
    emptyDir: {}
  - name: workdir
    persistentVolumeClaim:
      claimName: pvc-nas
  - name: docker-config
    secret:
      secretName: docker-config
  arguments:
    parameters:
    - name: repo_url
      value: ""
    - name: repo_name
      value: ""
    - name: target_branch
      value: "main"
    - name: container_image
      value: ""
    - name: container_tag
      value: "v1.0.0"
    - name: dockerfile
      value: "./Dockerfile"
    - name: enable_suffix_commitid
      value: "true"
    - name: enable_test
      value: "true"
  templates:
    - name: main
      dag:
        tasks:
          - name: git-checkout-pr
            inline:
              container:
                image: mirrors-ssl.aliyuncs.com/alpine:latest
                command:
                  - sh
                  - -c
                  - |
                    set -eu
                    
                    apk --update add git
          
                    cd /workdir
                    echo "Start to Clone "{{workflow.parameters.repo_url}}
                    git -C "{{workflow.parameters.repo_name}}" pull || git clone {{workflow.parameters.repo_url}} 
                    cd {{workflow.parameters.repo_name}}
          
                    echo "Start to Checkout target branch" {{workflow.parameters.target_branch}}
                    git checkout --track origin/{{workflow.parameters.target_branch}} || git checkout {{workflow.parameters.target_branch}}
                    git pull
                    
                    echo "Get commit id" 
                    git rev-parse --short origin/{{workflow.parameters.target_branch}} > /workdir/{{workflow.parameters.repo_name}}-commitid.txt
                    commitId=$(cat /workdir/{{workflow.parameters.repo_name}}-commitid.txt)
                    echo "Commit id is got: "$commitId
                                        
                    echo "Git Clone and Checkout Complete."
                volumeMounts:
                - name: "workdir"
                  mountPath: /workdir
                resources:
                  requests:
                    memory: 1Gi
                    cpu: 1
                activeDeadlineSeconds: 1200
          - name: run-test
            when: "{{workflow.parameters.enable_test}} == true"
            inline: 
              container:
                image: mirrors-ssl.aliyuncs.com/golang:alpine3.21
                command:
                  - sh
                  - -c
                  - |
                    set -eu
                    
                    if [ ! -d "/workdir/pkg/mod" ]; then
                      mkdir -p /workdir/pkg/mod
                      echo "GOMODCACHE Directory /pkg/mod is created"
                    fi
                    
                    export GOMODCACHE=/workdir/pkg/mod
                    
                    cp -R /workdir/{{workflow.parameters.repo_name}} /test/{{workflow.parameters.repo_name}} 
                    echo "Start Go Test..."
                    
                    cd /test/{{workflow.parameters.repo_name}}
                    go test -v ./...
                    
                    echo "Go Test Complete."
                volumeMounts:
                - name: "workdir"
                  mountPath: /workdir
                - name: run-test
                  mountPath: /test
                resources:
                  requests:
                    memory: 4Gi
                    cpu: 2
              activeDeadlineSeconds: 1200
            depends: git-checkout-pr    
          - name: build-push-image
            inline: 
              container:
                image: mirrors-ssl.aliyuncs.com/moby/buildkit:v0.13.0-rootless
                command:
                  - sh
                  - -c
                  - |         
                    set -eu
                     
                    tag={{workflow.parameters.container_tag}}
                    if [ {{workflow.parameters.enable_suffix_commitid}} == "true" ]
                    then
                      commitId=$(cat /workdir/{{workflow.parameters.repo_name}}-commitid.txt)
                      tag={{workflow.parameters.container_tag}}-$commitId
                    fi
                    
                    echo "Image Tag is: "$tag
                    echo "Start to Build And Push Container Image"
                    
                    cd /workdir/{{workflow.parameters.repo_name}}
                    
                    buildctl-daemonless.sh build \
                    --frontend \
                    dockerfile.v0 \
                    --local \
                    context=. \
                    --local \
                    dockerfile=. \
                    --opt filename={{workflow.parameters.dockerfile}} \
                    build-arg:GOPROXY=http://goproxy.cn,direct \
                    --output \
                    type=image,\"name={{workflow.parameters.container_image}}:${tag},{{workflow.parameters.container_image}}:latest\",push=true,registry.insecure=true \
                    --export-cache mode=max,type=registry,ref={{workflow.parameters.container_image}}:buildcache \
                    --import-cache type=registry,ref={{workflow.parameters.container_image}}:buildcache
                    
                    echo "Build And Push Container Image {{workflow.parameters.container_image}}:${tag} and {{workflow.parameters.container_image}}:latest Complete."
                env:
                  - name: BUILDKITD_FLAGS
                    value: --oci-worker-no-process-sandbox
                  - name: DOCKER_CONFIG
                    value: /.docker
                volumeMounts:
                  - name: workdir
                    mountPath: /workdir
                  - name: docker-config
                    mountPath: /.docker
                securityContext:
                  seccompProfile:
                    type: Unconfined
                  runAsUser: 1000
                  runAsGroup: 1000
                resources:
                  requests:
                    memory: 4Gi
                    cpu: 2
              activeDeadlineSeconds: 1200
            depends: run-test

您可以执行kubectl apply -f cluster-workflow-template.yaml将模板部署到集群中。

展开查看模板的参数说明

参数

说明

示例值

entrypoint

定义入口模板。

main

repo_url

Git仓库的URL。

https://github.com/ivan-cai/echo-server.git

repo_name

仓库名称。

echo-server

target_branch

仓库的目标分支。默认为main。

main

container_image

待构建的镜像。格式为<ACR EE Domain>/<ACR EE命名空间>/<仓库名>

test-registry.cn-hongkong.cr.aliyuncs.com/acs/echo-server

container_tag

要构建的镜像Tag。默认为v1.0.0。

v1.0.0

dockerfile

Dockerfile目录和文件名。

项目根目录下的相对路径,默认为./Dockerfile

./Dockerfile

enable_suffix_commitid

是否在镜像Tag后追加Commit ID。

  • true(默认值):追加。

  • false:不追加。

true

enable_test

是否开启运行Go Test步骤。

  • true(默认值):开启。

  • false:不开启。

true

操作步骤

本文以公共Git仓库为例为您介绍构建CI Pipeline的操作。如果您在工作流的CI Pipeline中使用的是私有Git仓库,则需要在CI流程中先成功Clone该私有仓库。具体的Clone操作,请参见在CI Pipeline中Clone私有Git仓库

重要

保存容器镜像访问凭证的Secret和挂载的NAS存储卷都需要与最终提交的工作流在同一个命名空间下。

步骤一:创建ACR EE访问凭证

ACR EE访问凭证主要用于BuildKit推送镜像。

  1. 为ACR EE配置访问凭证。具体操作,请参见配置访问凭证

  2. 执行如下命令,在集群中创建Secret保存ACR EE的密码,供BuildKit使用。

    说明

    $repositoryDomain:替换为ACR镜像仓库地址。

    $username:替换为ACR镜像仓库用户名。

    $password:替换为ACR镜像仓库密码。

    kubectl create secret -n argo generic docker-config --from-literal="config.json={\"auths\": {\"$repositoryDomain\": {\"auth\": \"$(echo -n $username:$password|base64)\"}}}"

步骤二:挂载NAS存储卷

使用NAS存储卷后,支持在工作流的各任务之间共享数据,例如Clone的代码仓库信息,还用于存储Go mod cache,用于加速CI Pipeline中的go testgo build过程。

请参见使用存储卷挂载NAS存储卷。

步骤三:基于模板启动工作流

控制台

  1. 登录Argo控制台。在左侧导航栏单击Cluster Workflow Templates,然后单击ci-go-v1预置模板名称。

    image

  2. 在模板详情页左上角单击+ SUBMIT,然后在弹出的面板中填写相关参数,并在面板下方单击+ SUBMIT

    请参见前文的模板参数说明将参数值设置为您实际使用的参数值。

    image

    操作完成后,在Workflows详情页查看工作流运行情况:

    image

Argo CLI

  1. 使用以下内容创建workflow.yaml文件,按照模板参数说明将参数值修改为您实际使用的参数值。

    apiVersion: argoproj.io/v1alpha1
    kind: Workflow
    metadata:
      generateName: ci-go-v1-
      labels:
        workflows.argoproj.io/workflow-template: ackone-ci
      namespace: argo  
    spec:
      arguments:
        parameters:
        - name: repo_url
          value: https://github.com/ivan-cai/echo-server.git
        - name: repo_name
          value: echo-server
        - name: target_branch
          value: main
        - name: container_image
          value: "test-registry.cn-hongkong.cr.aliyuncs.com/acs/echo-server"
        - name: container_tag
          value: "v1.0.0"
        - name: dockerfile
          value: ./Dockerfile
        - name: enable_suffix_commitid
          value: "true"
        - name: enable_test
          value: "true"
      workflowTemplateRef:
        name: ci-go-v1
        clusterScope: true
  2. 执行以下命令提交工作流。

    argo submit workflow.yaml

联系我们

若您有任何产品建议或疑问,请加入钉钉群(钉钉群号:35688562)联系我们。