Argo Workflows 中文快速指南·
Argo Workflows 是一个云原生的通用的工作流引擎。本教程主要介绍如何用其完成持续集成(Continous Integration, CI)任务。
本文全部内容来自:https://github.com/LinuxSuRen/argo-workflows-guide
如果您感觉本文对您或其他人有帮助,欢迎点赞、转发、分享。更加丰富、详细的内容也会在上面的 GitHub 仓库中更新,大家可以在上面的 issue 中交流。
基本概念对任何工具的基本概念有一致的认识和理解,是我们学习以及与他人交流的基础。
以下是本文涉及到的概念:
WorkflowTemplate,工作流模板Workflow,工作流为方便读者理解,下面就几个同类工具做对比:
Argo Workflow
Jenkins
WorkflowTemplate
Pipeline
Workflow
Build
安装首先,你需要有一套 Kubernetes 环境。下面的工具可以帮助你快速按照好一套 Kubernetes 环境:
推荐使用 hd 安装下面的工具
安装 hd 的命令为:curl https://linuxsuren.github.io/tools/install.sh|bash
工具
工具安装
使用
k3d
hd i k3d
k3d cluster create
kubekey
hd i kk
kk create cluster
minikube
hd i minikube
minikube start
当 Kubernetes 环境就绪后,就可以通过下面的命令会在命名空间(argo)下安装最新版本的 Argo Workflow:
代码语言:javascript复制kubectl create namespace argo
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/latest/download/install.yaml如果你的环境访问 GitHub 时有网络问题,可以使用下面的命令来安装:
代码语言:javascript复制docker run -it --rm -v /root/.kube/:/root/.kube --network host ghcr.io/linuxsuren/argo-workflows-guide:master推荐使用的工具:
k9s
K9s is a terminal based UI to interact with your Kubernetes clusters.
设置访问方式我们可以用下面的方式或者其他方式来设置 Argo Workflows 的访问端口:
代码语言:javascript复制kubectl -n argo port-forward deploy/argo-server --address 0.0.0.0 2746:2746需要注意的是,这里默认的配置下,服务器设置了自签名的证书提供 HTTPS 服务,因此,确保你使用 https:// 协议进行访问。
例如,地址为:https://10.121.218.242:2746/
Argo Workflows UI 提供了多种认证登录方式,对于学习、体验等场景,我们可以通过下面的命令直接设置绕过登录:
代码语言:javascript复制kubectl patch deployment \
argo-server \
--namespace argo \
--type='json' \
-p='[{"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": [
"server",
"--auth-mode=server"
]}]'简单示例下面是一个非常简单的示例:
代码语言:javascript复制cat < apiVersion: argoproj.io/v1alpha1 kind: WorkflowTemplate metadata: name: hello-world spec: entrypoint: hd # 执行入口,类似于 Go、Java 语言的的 main 函数 templates: - container: args: - search - kubectl command: - hd image: ghcr.io/linuxsuren/hd:v0.0.70 # 任务镜像 name: main name: hd EOF执行成功后,就可以在下面的地址访问到刚刚创建的工作流模板: https://10.121.218.242:2746/workflow-templates/default 选择其中一个模板,点击 SUBMIT 按钮,并设置对应的参数后即可触发工作流的执行。 在 Workflows 的详情页面中,我们做如下的操作: RESUBMIT,使用相同的模板以及参数触发一次新的执行小结通过前面的步骤,我们可以观察到 Argo Workflow 有如下特点: 需要具备基本的容器知识需要熟悉 Kubernetes 的基本资源,例如:PodTemplate、ConfigMap、Secret、Volume 等实现特定任务,基本上是需要寻找官方提供的镜像,或自行构建镜像完整示例代码语言:javascript复制cat < apiVersion: argoproj.io/v1alpha1 kind: WorkflowTemplate metadata: name: gogit spec: entrypoint: main # 执行入口 arguments: # 工作流全局参数 parameters: - name: repo value: https://github.com/linuxsuren/gogit - name: branch value: master # Volume 模板申明,用于工作流中多个 Pod 之间共享存储 # 例如:克隆代码、构建代码的 Pod 之间共享目录 # 动态创建 Volume,与当前工作流的生命流程保持一致 volumeClaimTemplates: - metadata: name: work spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 64Mi templates: - name: main dag: tasks: - name: clone template: clone # 引用下面的模板,并传入参数 arguments: parameters: - name: repo value: "{{workflow.parameters.repo}}" - name: branch value: "{{workflow.parameters.branch}}" - name: build template: build depends: checkout # 通过 depends 设置执行任务之间的顺序关系 - name: clone inputs: parameters: - name: repo - name: branch container: volumeMounts: - mountPath: /work # 共享该目录 name: work image: alpine/git:v2.26.2 workingDir: /work # 代码会克隆到这个目录中 args: - clone - --depth - "1" - --branch - "{{inputs.parameters.branch}}" - --single-branch - "{{inputs.parameters.repo}}" - . - name: build container: image: golang:1.19 volumeMounts: - name: work mountPath: /work workingDir: /work env: - name: GOPROXY # 根据需要来设置相应的环境变量,例如这里的 Golang 代理 value: https://goproxy.io,direct command: - make args: - build # 执行 Makefile 中的 build 指令来构建 Golang 代码 EOF小结通过上面的例子,我们可以看到 Argo Workflows 的如下特点: 一个工作流中的多个任务之间默认是并行执行的,如果希望顺序执行则可以通过 depends 设置工作流中可以申明多个任务模板,只有被 entrypoint 引用到的模板才会被执行每执行一个任务都会对应启动一个 Pod一个工作流之间的多个任务需要共享目录的话,需要挂载 VolumeWebhook所有主流 Git 仓库都是支持 webhook 的,借助 webhook 可以当代码发生变化后实时地触发工作流的执行。 Argo Workflows 利用 WorkflowEventBinding 将收到的 webhook 请求与 WorkflowTemplate 做关联。请参考下面的例子: 代码语言:javascript复制cat < apiVersion: argoproj.io/v1alpha1 kind: WorkflowEventBinding metadata: name: pull-request-binding spec: event: # 通过 webhook 的 payload 对请求进行过滤,并联动触发对应的工作流模板 selector: payload.project.name == "gogit" && payload.object_attributes.state == "opened" submit: workflowTemplateRef: name: gogit # 关联工作流模板 arguments: parameters: - name: branch valueFrom: # 从 webhook 的 payload 中提取值作为参数 event: payload.object_attributes.source_branch EOF然后,在代码仓库中添加如下的 webhook 地址(其中,default 是 WorkflowEventBinding 所在的命名空间): 代码语言:javascript复制https://argo-workflow-ip:port/api/v1/events/default/ 小结从上面的例子中,我们可以看到: Argo Workflows 以申明式的资源将 webhook 与工作流模板做关联,非常地灵活webhook 绑定并不局限在 Git 代码仓库上,还可以与其他类型的 webhook 做关联通过从 webhook 的 payload 中提取值,可以非常方便地为工作流模板参数传递值关联代码仓库对于不少的团队而言,会出于各种考虑而选择私有部署 Git 服务,例如:Gitlab、Gitee 等。而将工作流的执行结果与代码仓库的 Pull Request 相关联几乎是一个标配。以下是关联后的几点好处: 工作流执行失败后阻止 Pull Request 的合并在 Pull Request 页面中可以直接看到工作流执行状态下面会基于 https://github.com/LinuxSuRen/gogit/ 给出一个关联方案: 代码语言:javascript复制cat < apiVersion: v1 data: token: eW91ci10b2tlbg== kind: Secret metadata: name: git-secret type: Opaque --- apiVersion: argoproj.io/v1alpha1 kind: WorkflowTemplate metadata: name: hook spec: entrypoint: main arguments: parameters: - name: pr value: 1 - name: argoServer value: https://localhost:8080 hooks: exit: # 只有 exit 这个 hook 名称是固定的 template: hook all: # 这里可以是任意字符串,重点在于 expression 这里的表达式 template: hook expression: "true" # 可以通过表达式 expression 对事件进行过滤 templates: - container: args: - search - kubectl command: - hd image: ghcr.io/linuxsuren/hd:v0.0.70 # 任务镜像 name: main name: hd - name: hook volumes: - name: git-secret secret: defaultMode: 0400 secretName: git-secret # 包含 token 字段的 Secret container: image: ghcr.io/linuxsuren/gogit:master@sha256:4855f4ffbc1644eb7246f94cc9ee12c793ed4c26ba18e1d4d9afa57b72f1e846 args: - --provider=github # 支持 GitHub、Gitlab 等,私有部署的话需要参数 --server 指定地址 - --owner=LinuxSuRen # 根据需要修改 owner、repo、username - --repo=gogit - --username=LinuxSuRen - --token=file:///root/.ssh/token - --pr={{workflow.parameters.pr}} - --target={{workflow.parameters.argoServer}}/workflows/{{workflow.namespace}}/{{workflow.name}} - --status={{workflow.status}} volumeMounts: - mountPath: /root/.ssh/ name: git-secret EOF触发上面的工作流后,就会在指定的仓库 Pull Request 上出现构建状态。 参考链接官方文档小结从这个示例中,我们可以看到: hook 机制依然是非常的灵活,但 expression 表达式可能会是一个具有挑战的部分hook 机制有点像是 Golang 的 __init 函数,作为特殊的入口,可以调用其他的模板日志持久化Argo Workflows 默认不会持久化工作流日志,而是从每个任务对应的 Pod 中获取日志。而对于 Kubernetes 来说,Pod 是一个没有保障的最小执行单元,可能会由于人为或者某种策略被删除。当 Pod 被删除后,日志就无法查看了。因此,对于生产环境而言,必须要持久化日志。 Argo Workflows 执行多种存储协议,以下是兼容 S3 的 MinIO 存储: 首先,下载、安装以及配置 minio。本文仅作学习、演示使用,生产环境中,请按照官方文档进行安装、配置。 代码语言:javascript复制hd i minio minio server /tmp/minio --console-address ":9001"然后,访问 minio 管理界面 http://localhost:9001,创建名为 argo-workflow 的 bucket。创建 Access Key,并写入下面的 Secret 中。 安装如下配置修改 ConfigMap: 代码语言:javascript复制kubectl create secret generic minio-workflow \ --from-literal=accessKey=supersecret \ --from-literal=secretKey=topsecret cat < apiVersion: v1 kind: ConfigMap metadata: name: workflow-controller-configmap namespace: argo data: artifactRepository: | archiveLogs: true # 全局设置使得所有工作流日志做持久化 s3: bucket: argo-workflow # 在 minio 中创建的 bucket endpoint: minio.minio.svc insecure: true # 当 minio 没有启用 TLS accessKeySecret: name: minio-workflow key: accessKey secretKeySecret: name: minio-workflow key: secretKey EOF完成上面的配置后,再次执行任意工作流,并将执行完成的 Pod 删除后,我们依然可以在 UI 上查看任务日志。并且,可以在 minio 中看到了新增的文件。每个 Pod 的日志在 minio 中分别以一个文件的形式存储。 我们可以通过 minio 的命令行客户端 mc 看到类似如下的文件: 代码语言:javascript复制mc alias set myminio http://localhost:9001 minioadmin minioadmin # mc ls myminio/argo-workflow -r [2022-12-09 10:53:31 CST] 20B STANDARD hello-world-5mjgp/hello-world-5mjgp-clone-3848310779/main.log [2022-12-09 10:55:39 CST] 16KiB STANDARD hello-world-5mjgp/hello-world-5mjgp-image-2614052838/main.log [2022-12-09 10:54:35 CST] 5.9KiB STANDARD hello-world-5mjgp/hello-world-5mjgp-scan-4101005739/main.log [2022-12-09 10:53:51 CST] 435B STANDARD hello-world-5mjgp/hello-world-5mjgp-test-1532501286/main.log参考链接支持的外部存储类型官方文档小结通过上面的例子,我们可以看到: Argo Workflows 能以非侵入式的配置,使得工作流日志输出到对象存储等外部存储中Argo Workflows 的任务有输入、输出(input、output)的概念,日志的持久化是将日志作为输出写入到预先配置好的外部存储日志的持久化,可以分别在全局 ConfigMap、Workflow Spec、WorkflowTemplate 中配置ReferencesDevOps Practice Guide https://github.com/LinuxSuRen/devops-practice-guide