【阅读原文】戳:云原生时代:从Jenkins到Argo Workflows,构建高效CI Pipeline
Argo Workflows
Argo Workflows[1]是用于在Kubernetes上编排Job的开源的云原生工作流引擎。可以轻松自动化和管理Kubernetes上的复杂工作流程。适用于各种场景,包括定时任务、机器学习、ETL和数据分析、模型训练、数据流pipline、CI/CD等。
Kubernetes Jobs只提供基础的任务执行,但是无法定义步骤依赖关系和顺序、缺乏工作流模版、没有可视化界面,也不支持工作流级别的错误处理等,对于批处理、数据处理、科学计算、持续集成等业务场景,Kubernetes Job无法胜任。
Argo Workflows作为CNCF的毕业项目,已被使用在多种场景,持续集成(CI)是其一个重要应用领域。
CI与Jenkins
持续集成和持续部署(CI/CD)是软件开发生命周期中的重要部分,它允许团队以敏捷流程开发应用并提高所构建应用程序的质量。持续集成(CI)是面向开发者的自动化流程,经测试、构建等步骤,有助于更频繁、可靠地将代码变更提交到主分支。
Jenkins作为CI/CD领域最常见的解决方案,其具有开源免费、插件丰富、社区成熟诸多优点,但它仍然存在一些问题,尤其是云原生大背景的当下:
•非kubernetes原生;
•随着pipeline和插件的增加,Jenkins会面临性能瓶颈;
•自动扩展能力不足,并发不足,运行时间长,空闲计算浪费成本;
•维护成本方面,虽然Jenkins的插件生态系统丰富,但这也可能导致插件版本不兼容、更新不及时或安全漏洞等问题,管理插件更新和权限是一个持续的挑战;
•项目隔离/权限分配方案的缺陷等。
Argo Workflows与Jenkins的对比
相比于Jenkins,Argo Workflows有诸多优势。Argo Workflows构建在Kubernetes之上,使其具有Kubernetes经过时间考验的优势,其Autoscaling和并发等能力,使得Argo Workflows可以处理大规模的pipelins,具有更快的运行速度,和更低的费用/使用成本,让开发者更加聚焦业务功能和为客户提供、传播价值;并且与Argo生态的Argo CD、Argo Rollout、Argo Event的无缝集成,为CI等场景提供更强大的能力。您可以基于Argo Workflows来构建更加云原生、大规模、高效率、低成本的CI Pipeline。
对比如下:
Argo Workflows | Jenkins | |
kubernetes原生 | kubernetes原生,因此也具有k8s的部分管理容器的优势,如: 容器故障后自动恢复 弹性伸缩 支持RBAC,配合Argo的集成SSO能力,很容易实现企业的多租隔离场景 |
非kubernetes原生 |
Autoscaling、并发、性能 | Argo被用来处理大规模pipeline,自动扩展 并发让运行更快,效率更高 |
Jenkins更适合规模较小的场景,在处理大量pipelines时,性能下降。自动扩展能力差。 并发不足,运行时间长 |
成本 | 自动伸缩,最小化成本 原生支持Spot ECI运行任务,降低成本 |
Jenkins空闲计算浪费成本 |
社区与生态 | Argo社区不断壮大,与其生态的Argo CD、Argo Rollout、Argo Event的无缝集成,为CI等场景提供更强大的能力 | Jenkins社区成熟、资源丰富,大量插件降低使用门槛,但随着时间推移,插件更新和权限管理极大增加运维成本,使开发者更多精力在维护插件,而非聚焦业务功能和为客户提供价值 |
基于ACK One Serverless Argo工作流的CI Pipeline
ACK One Serverless Argo 工作流
ACK One Serverless Argo工作流[2]作为一款完全遵循社区规范的全托管式Argo Workflows服务,致力于应对大规模计算密集型作业,通过集成阿里云ECI实现自动扩展和极致弹性、按需扩容以最小化成本,通过使用spot ECI(抢占式ECI实例[3])可以降低80%成本。
CI Pipeline 概述
基于ACK One Serverless Argo工作流集群构建CI Pipeline,主要使用BuildKit[4]实现容器镜像的构建和推送,并使用BuildKit Cache[5]加速镜像的构建,使用NAS来存储Go mod cache加速go test和go build,最终大幅加速CI Pipeline流程。
我们将实现的CI Pipeline的Cluster Workflow Template预置在工作流集群中(名为ci-go-v1),其中主要包含3个步骤:
1.Git Clone&Checkout:Clone Git仓库,Checkout到目标分支;并获取commit id。
2.Run Go Test:通过参数控制是否运行,使用NAS存储Go mod cache进行加速。
3.Build&Push Image:
a.使用BuildKit构建和推送容器镜像,并使用BuildKit Cache中 registry类型cache来加速镜像构建;
b.镜像tag默认使用 {container_tag}-{commit_id} 格式,可在提交工作流时通过参数控制是否追加commit id;
c.推送镜像的同时,也会推送覆盖其latest镜像。
您可执行以下步骤完成CI Pipeline的运行,详细步骤请参见最佳实践[6]:
1.在工作流集群中准备好ACR EE的凭据和NAS存储卷
2.基于预置模板启动工作流(workflow)运行CI Pipeline
预置CI Pipeline模板
工作流集群中默认已经预置了名为ci-go-v1的工作流模板(ClusterWorkflowTemplate),yaml如下所示,详细参数说明请参见最佳实践[6]:
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: 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 {{workflow.parameters.target_branch}} 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: golang:1.22-alpine 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: 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
在控制台运行CI Pipeline
1.登录ACK One工作流集群控制台[7];
2.在基础信息,开启工作流控制台(Argo),并访问进入页面;
3.左侧菜单栏Cluster Workflow Templates,单击ci-go-v1预置模板进入详情页;
4.单击+SUBMIT,在右侧填入您的参数,单击下方+SUBMIT。
参数说明:
参数 | 说明 | 参数值 |
repo_url | 仓库url | https://github.com/ivan-cai/echo-server.git |
repo_name | 仓库名 | echo-server |
target_branch | 目标分支 | 默认是main |
container_image | 要build的镜像信息 | test-registry.cn-hongkong.cr.aliyuncs.com/acs/echo-server |
container_tag | 要build的镜像tag | 默认v1.0.0 |
dockerfile | Dockerfile目录和文件名 (项目根目录下的相对路径) |
默认./Dockerfile |
enable_suffix_commitid | 在container_tag后追加commit id | true/false(默认true) |
enable_test | 开启运行Go Test步骤 | true/false(默认true) |
执行完以后,可在Argo UI的workflow详情页查看运行情况,如下所示:
总结
ACK One Serverless Argo工作流作为全托管的Argo工作流服务,可以帮助您实现更大规模、具有更快的运行速度、及更低成本的CI Pipeline,与ACK One GitOps[8](Argo CD)、Argo Event等事件驱动架构可以构建完整的自动化CI/CD Pipeline。
欢迎加入ACK One客户交流钉钉与我们一同交流。(钉钉群号:35688562)
相关链接:
[1] Argo Workflows
https://argoproj.github.io/argo-workflows/
[2] ACK One Serverless Argo工作流
[3] 抢占式ECI实例
https://help.aliyun.com/zh/eci/use-cases/run-jobs-on-a-preemptible-instance?spm=a2c4g.11186623.0.i7
[4] BuildKit
https://github.com/moby/buildkit
[5] BuildKit Cache
https://github.com/moby/buildkit?tab=readme-ov-file#cache
[6] 最佳实践
[7] ACK One工作流集群控制台
[8] ACK One GitOps
我们是阿里巴巴云计算和大数据技术幕后的核心技术输出者。
获取关于我们的更多信息~