{"id":20470633,"url":"https://github.com/devops-ws/argo-workflows-guide","last_synced_at":"2025-03-05T13:28:16.183Z","repository":{"id":133664298,"uuid":"576082320","full_name":"devops-ws/argo-workflows-guide","owner":"devops-ws","description":"Argo Workflows Guide","archived":false,"fork":false,"pushed_at":"2024-05-14T02:47:23.000Z","size":94,"stargazers_count":27,"open_issues_count":0,"forks_count":8,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-16T02:17:15.746Z","etag":null,"topics":["argo-workflows","guide"],"latest_commit_sha":null,"homepage":"https://devops-ws.github.io/argo-workflows-guide/","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devops-ws.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2022-12-09T01:00:05.000Z","updated_at":"2024-12-30T22:27:33.000Z","dependencies_parsed_at":"2023-03-13T11:08:10.556Z","dependency_job_id":"e451934b-e98d-4b5c-a671-63056a7919d6","html_url":"https://github.com/devops-ws/argo-workflows-guide","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devops-ws%2Fargo-workflows-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devops-ws%2Fargo-workflows-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devops-ws%2Fargo-workflows-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devops-ws%2Fargo-workflows-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devops-ws","download_url":"https://codeload.github.com/devops-ws/argo-workflows-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242034182,"owners_count":20061080,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["argo-workflows","guide"],"created_at":"2024-11-15T14:13:37.049Z","updated_at":"2025-03-05T13:28:16.157Z","avatar_url":"https://github.com/devops-ws.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"[Argo Workflows](https://argoproj.github.io/argo-workflows/) 是一个[云原生](https://en.wikipedia.org/wiki/Cloud-native_computing)的通用的工作流引擎。本教程主要介绍如何用其完成持续集成（Continous Integration, CI）任务。\n\n## 基本概念\n对任何工具的基本概念有一致的认识和理解，是我们学习以及与他人交流的基础。\n\n以下是本文涉及到的概念：\n\n* WorkflowTemplate，工作流模板\n* Workflow，工作流\n\n为方便读者理解，下面就几个同类工具做对比：\n\n| Argo Workflow | Jenkins |\n|---|---|\n| WorkflowTemplate | Pipeline |\n| Workflow | Build |\n\n## 最佳实践\n* 把所有 Workflow YAML 文件存到一个 Git 仓库（例如：`infra/workflows`）中，并利用 [Argo CD](https://github.com/devops-ws/argo-cd-guide) 同步到 Kubernetes 集群\n* 团队之间共用的部分封装为 `ClusterWorkflowTemplate`\n\n## 安装\n首先，你需要有一套 [Kubernetes](https://github.com/kubernetes/kubernetes/) 环境。下面的工具可以帮助你快速按照好一套 Kubernetes 环境：\n\n\u003e 推荐使用 [hd](https://github.com/LinuxSuRen/http-downloader) 安装下面的工具\n\u003e\n\u003e 安装 `hd` 的命令为：`curl https://linuxsuren.github.io/tools/install.sh|bash`\n\n| 工具 | 工具安装 |使用 |\n|---|---|---|\n| [k3d](https://k3d.io/) | `hd i k3d` | `k3d cluster create` |\n| [kubekey](https://github.com/kubesphere/kubekey) | `hd i kk` | `kk create cluster` |\n| [minikube](https://github.com/kubernetes/minikube) | `hd i minikube` | `minikube start` |\n\n当 Kubernetes 环境就绪后，就可以通过下面的命令会在命名空间（`argo`）下安装最新版本的 `Argo Workflow`：\n\n```shell\nkubectl create namespace argo\nkubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/latest/download/install.yaml\n```\n\n如果你的环境访问 GitHub 时有网络问题，可以使用下面的命令来安装：\n\n```shell\ndocker run -it --rm -v $HOME/.kube/:/root/.kube --network host --pull always ghcr.io/linuxsuren/argo-workflows-guide:master\n```\n\n推荐使用的工具：\n\n|||\n|---|---|\n| [k9s](https://k9scli.io/) | K9s is a terminal based UI to interact with your Kubernetes clusters. |\n\n## 设置访问方式\n我们可以用下面的方式或者其他方式来设置 Argo Workflows 的访问端口：\n\n```shell\nkubectl -n argo port-forward deploy/argo-server --address 0.0.0.0 2746:2746\n# 或者设置为 NodePort\nkubectl -n argo patch svc argo-server --type='json' -p '[{\"op\":\"replace\", \"path\":\"/spec/type\", \"value\":\"NodePort\"}, {\"op\":\"add\", \"path\":\"/spec/ports/0/nodePort\",\"value\":31517}]'\n# 暴露 k3d 端口\nk3d node edit k3d-k3s-default-serverlb --port-add 31517:31517\n```\n\n\u003e 需要注意的是，这里默认的配置下，服务器设置了自签名的证书提供 HTTPS 服务，因此，确保你使用 `https://` 协议进行访问。\n\n例如，地址为：`https://10.121.218.242:2746/`\n\nArgo Workflows UI 提供了多种认证登录方式，对于学习、体验等场景，我们可以通过下面的命令直接设置绕过登录：\n\n```shell\nkubectl patch deployment \\\n  argo-server \\\n  --namespace argo \\\n  --type='json' \\\n  -p='[{\"op\": \"replace\", \"path\": \"/spec/template/spec/containers/0/args\", \"value\": [\n  \"server\",\n  \"--auth-mode=server\"\n]}]'\n```\n\n## 简单示例\n\n下面是一个非常简单的示例：\n\n```shell\ncat \u003c\u003cEOF | kubectl apply -n default -f -\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: hello-world\nspec:\n  entrypoint: hd # 执行入口，类似于 Go、Java 语言的的 main 函数\n  templates:\n  - container:\n      args:\n      - search\n      - kubectl\n      command:\n      - hd\n      image: ghcr.io/linuxsuren/hd:v0.0.70 # 任务镜像\n      name: main\n    name: hd\nEOF\n```\n\n执行成功后，就可以在下面的地址访问到刚刚创建的工作流模板：\n\n`https://10.121.218.242:2746/workflow-templates/default`\n\n选择其中一个模板，点击 `SUBMIT` 按钮，并设置对应的参数后即可触发工作流的执行。\n\n在 Workflows 的详情页面中，我们做如下的操作：\n\n* RESUBMIT，使用相同的模板以及参数触发一次新的执行\n\n### 小结\n通过前面的步骤，我们可以观察到 Argo Workflow 有如下特点：\n\n* 需要具备基本的容器知识\n* 需要熟悉 Kubernetes 的基本资源，例如：PodTemplate、ConfigMap、Secret、Volume 等\n* 实现特定任务，基本上是需要寻找官方提供的镜像，或自行构建镜像\n\n## 完整示例\n\n```shell\ncat \u003c\u003cEOF | kubectl apply -n default -f -\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: gogit\nspec:\n  entrypoint: main                  # 执行入口\n  arguments:\n    # 工作流全局参数\n    parameters:\n      - name: repo\n        value: https://github.com/linuxsuren/gogit\n      - name: branch\n        value: master\n\n  # Volume 模板申明，用于工作流中多个 Pod 之间共享存储\n  # 例如：克隆代码、构建代码的 Pod 之间共享目录\n  # 动态创建 Volume，与当前工作流的生命流程保持一致\n  volumeClaimTemplates:\n    - metadata:\n        name: work\n      spec:\n        accessModes: [\"ReadWriteOnce\"]\n        resources:\n          requests:\n            storage: 64Mi\n\n  templates:\n  - name: main\n    dag:\n      tasks:\n        - name: clone\n          template: clone   # 引用下面的模板，并传入参数\n          arguments:\n            parameters:\n              - name: repo\n                value: \"{{workflow.parameters.repo}}\"\n              - name: branch\n                value: \"{{workflow.parameters.branch}}\"\n        - name: build\n          template: build\n          depends: clone # 通过 depends 设置执行任务之间的顺序关系\n  \n  - name: clone\n    inputs:\n      parameters:\n        - name: repo\n        - name: branch\n    container:\n      volumeMounts:\n        - mountPath: /work              # 共享该目录\n          name: work\n      image: alpine/git:v2.26.2\n      workingDir: /work                 # 代码会克隆到这个目录中\n      args:\n        - clone\n        - --depth\n        - \"1\"\n        - --branch\n        - \"{{=sprig.trimPrefix('refs/heads/', inputs.parameters['branch'])}}\"       # 利用模板函数处理分支名称\n        - --single-branch\n        - \"{{inputs.parameters.repo}}\"\n        - .\n  - name: build\n    container:\n      image: golang:1.19\n      volumeMounts:\n        - name: work\n          mountPath: /work\n      workingDir: /work\n      env:\n        - name: GOPROXY     # 根据需要来设置相应的环境变量，例如这里的 Golang 代理\n          value: https://goproxy.io,direct\n      command:\n        - make\n      args:\n        - build             # 执行 Makefile 中的 build 指令来构建 Golang 代码\nEOF\n```\n\n### 小结\n\n通过上面的例子，我们可以看到 Argo Workflows 的如下特点：\n\n* 一个工作流中的多个任务之间默认是并行执行的，如果希望顺序执行则可以通过 `depends` 设置\n* 工作流中可以申明多个任务模板，只有被 `entrypoint` 引用到的模板才会被执行\n* 每执行一个任务都会对应启动一个 Pod\n* 一个工作流之间的多个任务需要共享目录的话，需要挂载 Volume\n* 对于参数格式的处理，我们可以利用模板函数来实现\n\n## 构建镜像\n这里，我以构建并推送镜像到私有镜像仓库（例如： [Harbor](https://github.com/devops-ws/harbor-guide) ）中为例，分享 Argo Workflows 的使用。\n\n下面是这个例子中用到的相关工具：\n\n* 构建工具 [buildkit](https://github.com/moby/buildkit)\n* 私有 Git 仓库\n* 私有镜像仓库\n\n准备工作：\n\n* 在集群中的每个节点上[配置 Docker 支持 HTTP 镜像地址](https://github.com/devops-ws/harbor-guide#docker-daemon)\n* 创建 Git 凭据\n  * `kubectl create secret generic gitlab-secret -n default --dry-run=client -oyaml --from-file=id_rsa=/root/.ssh/id_rsa --from-file=known_hosts=/root/.ssh/known_hosts --from-literal=token=h-zez9CWzyzykbLoS53s`\n* 创建 Docker 凭据（下面已包含）\n\n```shell\n# 执行下面的命令登录 Harbor\n# docker login 10.121.218.184:30002 -uyour-username -pyour-password\n# https://github.com/moby/buildkit/blob/master/docs/buildkitd.toml.md\nkubectl create secret generic harbor --from-file=config.json=/root/.docker/config.json -n default\ncat \u003c\u003cEOF | kubectl apply -n default -f -\n---\napiVersion: v1\ndata:\n  buildkitd.toml: |\n    debug = false\n    [worker.containerd]\n      namespace = \"buildkit\"\n    [registry.\"10.121.218.184:30002\"]       # 支持从私有镜像仓库中拉取镜像\n      http = true\n      insecure = true\nkind: ConfigMap\nmetadata:\n  name: buildkit\n---\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: image-build\nspec:\n  entrypoint: main\n  arguments:\n    parameters:\n      - name: repo\n        value: git@10.121.218.82:demo/hello-world.git\n      - name: branch\n        value: master\n\n  volumeClaimTemplates:                           # 用于在多个 Pod 之间共享代码\n    - metadata:\n        name: work\n      spec:\n        accessModes: [\"ReadWriteOnce\"]\n        resources:\n          requests:\n            storage: 64Mi\n\n  templates:\n  - name: main\n    dag:\n      tasks:\n        - name: clone\n          template: clone\n          arguments:\n            parameters:\n              - name: repo\n                value: \"{{workflow.parameters.repo}}\"\n              - name: branch\n                value: \"{{workflow.parameters.branch}}\"\n        - name: image\n          template: image\n          depends: clone\n          arguments:\n            parameters:\n              - name: image\n                value: demo/hello-world\n              - name: dockerfile\n                value: .\n\n  - name: clone\n    inputs:\n      parameters:\n        - name: repo\n        - name: branch\n    volumes:\n      - name: git-secret\n        secret:\n          defaultMode: 0400\n          secretName: gitlab-secret\n    container:\n      volumeMounts:\n        - mountPath: /work\n          name: work\n        - mountPath: /root/.ssh/\n          name: git-secret\n      image: alpine/git:v2.26.2\n      workingDir: /work\n      args:\n        - clone\n        - --depth\n        - \"1\"\n        - --branch\n        - \"{{inputs.parameters.branch}}\"\n        - --single-branch\n        - \"{{inputs.parameters.repo}}\"\n        - .\n  - name: image\n    inputs:\n      parameters:\n        - name: image\n        - name: dockerfile\nhostAliases:\t\t\t\t\t# 关联 IP 和主机名\n      - ip: \"192.168.21.110\"\n        hostnames:\n        - \"your.com\"\n    volumes:\n      - name: docker-config\n        secret:\n          secretName: harbor                        # 这里需要和上面创建的 Secret 名称保持一致\n      - name: cache\n        hostPath:\n          path: /mnt/data\n          type: DirectoryOrCreate\n      - name: buildkit\n        configMap:\n          name: buildkit\n    container:\n      image: moby/buildkit:v0.9.3-rootless\n      volumeMounts:\n        - name: work\n          mountPath: /work\n        - name: docker-config\n          mountPath: /.docker\n        - name: cache\n          mountPath: /cache\n        - mountPath: /etc/buildkit/\n          name: buildkit\n      workingDir: /work/\n      securityContext:\n        privileged: true\n      env:\n        - name: BUILDKITD_FLAGS\n          value: --oci-worker-no-process-sandbox --config=/etc/buildkit/buildkitd.toml # 支持从 HTTP 地址拉取镜像\n        - name: DOCKER_CONFIG\n          value: /.docker\n      command:\n        - buildctl-daemonless.sh\n      args:\n        - build\n        - --frontend\n        - dockerfile.v0\n        - --local\n        - context=.\n        - --local\n        - dockerfile={{inputs.parameters.dockerfile}}\n        - --output\n        - type=image,name=10.121.218.184:30002/{{inputs.parameters.image}},push=true,registry.insecure=true   # 支持推送的 HTTP 地址\n        - --opt\n        - build-arg:GOPROXY=http://goproxy.goproxy.svc:8081,direct        # 设置内网 Go 缓存代理\nEOF\n```\n\n需要在每个构建节点上执行如下的命令：\n```shell\necho 15000 \u003e /proc/sys/user/max_user_namespaces\n```\n\n除了 `buildkit` 以外，也可以考虑使用 `kaniko`（你可以从 [library.yaml](templates/library.yaml)中找到对应的配置）。\n\n### 小结\n在上面的例子中，有如下几点需要注意的：\n\n* 采用 buildkit 构建镜像，避免挂载本地 Docker 的 `/var/run/docker.sock` 文件\n* 上面的例子，在 Kubernetes 集群不以 Docker 作为[容器运行](https://kubernetes.io/docs/setup/production-environment/container-runtimes/)时也能正常使用\n* 在实际使用过程中，有遇到过 buildkit 报错的情况，可以考虑增加重试机制进一步保障构建成功\n* `registry.insecure=true` 这个参数对于私有化环境中没有证书的情况非常重要\n* buildkit 还支持缓存持久化，从而加快构建速度，有兴趣的朋友可以翻阅官方文档，或帮助完善这里的例子\n* Go 缓存代理是可选的，但推荐在内网中部署以加快依赖下载速度\n\n## 循环任务\nArgo Workflow 的 [Loop](https://argoproj.github.io/argo-workflows/walk-through/loops/) 功能，可以简化重复的任务，方便维护。以下是一个例子：\n\n```shell\ncat \u003c\u003cEOF | kubectl apply -n default -f -\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: output\nspec:\n  entrypoint: main\n\n  templates:\n  - name: main\n    dag:\n      tasks:\n        - name: build-image\n          template: build-image\n          depends: clone\n          arguments:\n            parameters:\n              - name: version\n                value: \"{{tasks.clone.outputs.parameters.version}}\"\n  - name: build-image\n    inputs:\n      parameters:\n        - name: version\n          default: \"\"\n    steps:\n    - - name: image\n        templateRef:\n          name: library\n          template: image\n          clusterScope: true\n        arguments:\n          parameters:\n            - name: image\n              value: al-cloud/{{item.name}}:{{inputs.parameters.version}}\n            - name: dockerfile\n              value: build/{{item.context}}\n            - name: tag\n              value: \"{{inputs.parameters.version}}\"\n        withItems: # 设置循环的参数\n        - { name: 'apiserver', context: 'al-cloud' }\n        - { name: 'controller', context: 'component-manager' }\n        - { name: 'app-template', context: 'app-template' }\n        - { name: 'manifest', context: 'manifest' }\n        - { name: 'agent', context: 'agent' }\n        - { name: 'api-test', context: 'api-test' }\nEOF\n```\n\n## 结果输出与引用\nArgo Workflows 支持制品（artifact）与变量的输出，下面是变量输出以及引用的例子：\n\n```shell\ncat \u003c\u003cEOF | kubectl apply -n default -f -\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: output\nspec:\n  entrypoint: main\n\n  templates:\n  - name: main\n    dag:\n      tasks:\n        - name: version\n          template: version\n        - name: print\n          template: print\n          depends: version\n          arguments:\n            parameters:\n              - name: version\n                value: \"{{tasks.version.outputs.parameters.version}}\"       # 引用输出变量\n  - name: version\n    container:\n      image: alpine/git:v2.26.2\n      command:\n      - sh\n      - -c\n      - 'echo v1.1 \u003e /tmp/version'         # 将期望输出的内容写入文件\n    outputs:\n      parameters:\n      - name: version\n        valueFrom:\n          path: /tmp/version               # 读取容器中的文件，并作为内容输出到变量 version 中\n  - name: print\n    inputs:\n      parameters:\n        - name: version                    # 定义输入变量\n    container:\n      image: alpine\n      command:\n      - sh\n      - -c\n      - 'echo {{inputs.parameters.version}}'\nEOF\n```\n\n## Webhook\n所有主流 Git 仓库都是支持 webhook 的，借助 webhook 可以当代码发生变化后实时地触发工作流的执行。\n\nArgo Workflows 利用 `WorkflowEventBinding` 将收到的 webhook 请求与 WorkflowTemplate 做关联。请参考下面的例子：\n\n```shell\ncat \u003c\u003cEOF kubectl apply -n default -f -\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: submit-workflow-template\nrules:\n  - apiGroups:\n      - argoproj.io\n    resources:\n      - workfloweventbindings\n    verbs:\n      - list\n  - apiGroups:\n      - argoproj.io\n    resources:\n      - workflowtemplates\n    verbs:\n      - get\n  - apiGroups:\n      - argoproj.io\n    resources:\n      - workflows\n    verbs:\n      - create\n---\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: github.com\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: github.com\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: Role\n  name: submit-workflow-template\nsubjects:\n  - kind: ServiceAccount\n    name: github.com\n    namespace: default\n---\napiVersion: v1\nstringData:\n  github.com: |\t\t\t                  # 这里对应 ServiceAcccount 名称\n    type: github\t\t                  # 固定的几个类型\n    secret: \"argo-workflow-secret\"    # webhook 中配置的 Secret Token\nkind: Secret\nmetadata:\n  name: argo-workflows-webhook-clients\ntype: Opaque\n---\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowEventBinding\nmetadata:\n  name: pull-request-binding\nspec:\n  event:\n    # 通过 webhook 的 payload 对请求进行过滤，并联动触发对应的工作流模板\n    selector: payload.project.name == \"gogit\" \u0026\u0026 payload.object_attributes.state == \"opened\"\n  submit:\n    workflowTemplateRef:\n      name: gogit       # 关联工作流模板\n    arguments:\n      parameters:\n      - name: branch\n        valueFrom:\n          # 从 webhook 的 payload 中提取值作为参数\n          event: payload.object_attributes.source_branch\nEOF\n```\n\n然后，在代码仓库中添加如下的 webhook 地址（其中，`default` 是 `WorkflowEventBinding` 所在的命名空间）：\n\n```\nhttps://argo-workflow-ip:port/api/v1/events/default/\n```\n\n上面的 Secret 名称 `argo-workflows-webhook-clients` 是固定的，所在命名空间也就是 webhook 地址中的 `default`。支持的 Git Provider 名称也是固定的几个：\n\n* `bitbucket`\n* `bitbucketserver`\n* `github`\n* `gitlab`\n\n### 小结\n\n从上面的例子中，我们可以看到：\n\n* Argo Workflows 以申明式的资源将 webhook 与工作流模板做关联，非常地灵活\n* webhook 绑定并不局限在 Git 代码仓库上，还可以与其他类型的 webhook 做关联\n* 通过从 webhook 的 payload 中提取值，可以非常方便地为工作流模板参数传递值\n\n## Argo Event\n\n[Argo Event](https://github.com/argoproj/argo-events) 是另外一种使得代码更新后自动触发流水线的方式。你需要单独[安装](https://argoproj.github.io/argo-events/quick_start/)。\n\n![](https://argoproj.github.io/argo-events/assets/argo-events-architecture.png)\n\n* EventSource 接受消息（来自 webhook 或其他）\n  * 每个 EventSource 资源对应一个无状态服务（Deployment）\n* EventBus 为消息总线\n  * 为一个有状态服务（Statefulsets）\n* Sensor 用于获取消息并触发动作（流水线）\n  * 每个 Sensor 资源对应一个无状态服务（Deployment）\n\n以下是默认的消息总线，无需做如何配置，创建后会自动创建一个有状态服务：\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: EventBus\nmetadata:\n  name: default\n  namespace: default\nspec:\n  nats:\n    native:\n      # Optional, defaults to 3. If it is \u003c 3, set it to 3, that is the minimal requirement.\n      replicas: 3\n      # Optional, authen strategy, \"none\" or \"token\", defaults to \"none\"\n      auth: none\n```\n\n下面的资源会自动创建 `EventSource` 的 `Deployment` 和 `Service`（可以手动修改服务为 `NodePort`）：\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: EventSource\nmetadata:\n  name: default\n  namespace: default\nspec:\n  service:\n    ports:\n      - port: 12000\n        targetPort: 12000\n  gitlab:\n    pr:\n      # Project namespace paths or IDs\n      projects:\n        - \"cmp/al-cloud\"\n      webhook:\n        endpoint: /push # 固定值\n        port: \"12000\" # 固定值\n        method: POST\n        url: http://172.11.0.6:32168 # Sensor 的访问地址\n      accessToken:\n        key: gitlab-token\n        name: gitlab-secret\n      events:\n        - PushEvents\n        - MergeRequestsEvents\n        - TagPushEvents\n        - NoteEvents\n      secretToken:\n        key: webhook-secret\n        name: gitlab-secret\n      enableSSLVerification: false\n      gitlabBaseURL: http://10.121.218.82:6080\n      deleteHookOnFinish: true\n```\n\n下面的资源会自动创建 `Sensor` 的 `Deployment`：\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: Sensor\nmetadata:\n  name: default\n  namespace: default\nspec:\n  dependencies:\n    - name: pr\n      eventSourceName: default\n      eventName: pr\n      filters:\n        data:\n          - path: body.object_attributes.state\n            type: string\n            value:\n              - opened\n  triggers:\n    - template:\n        name: argo-workflow-trigger\n        argoWorkflow:\n          operation: submit\n          source:\n            resource:\n              apiVersion: argoproj.io/v1alpha1\n              kind: Workflow\n              metadata:\n                generateName: default-\n              spec:\n                arguments:\n                  parameters:\n                    - name: branch\n                    - name: pr\n                workflowTemplateRef:\n                  name: default\n          parameters:\n            - src:\n                dependencyName: pr\n                dataKey: body.object_attributes.source_branch\n              dest: spec.arguments.parameters.0.value\n            - src:\n                dependencyName: pr\n                dataKey: body.object_attributes.iid\n              dest: spec.arguments.parameters.1.value\n```\n\n下面是 Gitlab 创建 `release` 分支或推送到 `master` 分支时的写法：\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: Sensor\nmetadata:\n  name: al-cloud-release\n  namespace: default\nspec:\n  dependencies:\n    - name: push\n      eventSourceName: default\n      eventName: al-cloud-push\n      filters:\n        exprLogicalOperator: \"or\"\n        data:\n          - path: body.object_kind\n            type: string\n            value:\n              - push\n          - path: body.before\n            type: string\n            value:\n              - \"0000000000000000000000000000000000000000\"\n        exprs:\n          - expr: ref =~ \"refs/heads/release-\"\n            fields:\n              - name: ref\n                path: body.ref\n          - expr: ref == \"refs/heads/master\"\n            fields:\n              - name: ref\n                path: body.ref\n\n  triggers:\n    - template:\n        name: trigger\n        argoWorkflow:\n          operation: submit\n          source:\n            resource:\n              apiVersion: argoproj.io/v1alpha1\n              kind: Workflow\n              metadata:\n                generateName: al-cloud-push-\n              spec:\n                arguments:\n                  parameters:\n                    - name: branch\n                workflowTemplateRef:\n                  name: pr-al-cloud\n          parameters:\n            - src:\n                dependencyName: push\n                dataKey: body.ref\n              dest: spec.arguments.parameters.0.value\n```\n\n## 关联代码仓库\n\n对于不少的团队而言，会出于各种考虑而选择私有部署 Git 服务，例如：Gitlab、Gitee 等。而将工作流的执行结果与代码仓库的 Pull Request 相关联几乎是一个**标配**。以下是关联后的几点好处：\n\n* 工作流执行失败后阻止 Pull Request 的合并\n* 在 Pull Request 页面中可以直接看到工作流执行状态\n\n下面会基于 https://github.com/LinuxSuRen/gogit/ 给出一个关联方案：\n\n```shell\ncat \u003c\u003cEOF | kubectl apply -n default -f -\napiVersion: v1\ndata:\n  token: eW91ci10b2tlbg==\nkind: Secret\nmetadata:\n  name: git-secret\ntype: Opaque\n---\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: hook\nspec:\n  entrypoint: main\n  arguments:\n    parameters:\n      - name: pr\n        value: 1\n      - name: argoServer\n        value: https://localhost:8080\n\n  hooks:\n    exit:                   # 只有 exit 这个 hook 名称是固定的\n      template: hook\n    all:                    # 这里可以是任意字符串，重点在于 expression 这里的表达式\n      template: hook\n      expression: \"true\"    # 可以通过表达式 expression 对事件进行过滤\n\n  templates:\n  - container:\n      args:\n      - search\n      - kubectl\n      command:\n      - hd\n      image: ghcr.io/linuxsuren/hd:v0.0.70 # 任务镜像\n      name: main\n    name: hd\n  - name: hook\n    volumes:\n      - name: git-secret\n        secret:\n          defaultMode: 0400\n          secretName: git-secret    # 包含 token 字段的 Secret\n    container:\n      image: ghcr.io/linuxsuren/gogit:master@sha256:4855f4ffbc1644eb7246f94cc9ee12c793ed4c26ba18e1d4d9afa57b72f1e846\n      args:\n        - --provider=github         # 支持 GitHub、Gitlab 等，私有部署的话需要参数 --server 指定地址\n        - --owner=LinuxSuRen        # 根据需要修改 owner、repo、username\n        - --repo=gogit\n        - --username=LinuxSuRen\n        - --token=file:///root/.ssh/token\n        - --pr={{workflow.parameters.pr}}\n        - --target={{workflow.parameters.argoServer}}/workflows/{{workflow.namespace}}/{{workflow.name}}\n        - --status={{workflow.status}}\n      volumeMounts:\n        - mountPath: /root/.ssh/\n          name: git-secret\nEOF\n```\n\n触发上面的工作流后，就会在指定的仓库 Pull Request 上出现构建状态。\n\n### 参考链接\n\n* [官方文档](https://argoproj.github.io/argo-workflows/lifecyclehook/)\n\n### 小结\n\n从这个示例中，我们可以看到：\n\n* hook 机制依然是非常的灵活，但 expression 表达式可能会是一个具有挑战的部分\n* hook 机制有点像是 Golang 的 `__init` 函数，作为特殊的入口，可以调用其他的模板\n\n## 日志持久化\nArgo Workflows 默认不会持久化工作流日志，而是从每个任务对应的 Pod 中获取日志。而对于 Kubernetes 来说，Pod 是一个没有保障的最小执行单元，可能会由于人为或者某种策略被删除。当 Pod 被删除后，日志就无法查看了。因此，对于生产环境而言，必须要持久化日志。\n\nArgo Workflows 执行多种存储协议，以下是兼容 S3 的 MinIO 存储：\n\n首先，下载、安装以及配置 minio。本文仅作学习、演示使用，生产环境中，请按照官方文档进行安装、配置。\n\n```shell\nhd i minio\nminio server /tmp/minio --console-address \":9001\"\n```\n\n然后，访问 minio 管理界面 `http://localhost:9001`，创建名为 `argo-workflow` 的 `bucket`。创建 `Access Key`，并写入下面的 `Secret` 中。\n\n安装如下配置修改 `ConfigMap`：\n\n```shell\nkubectl create secret generic minio-workflow \\\n  --from-literal=accessKey=supersecret \\\n  --from-literal=secretKey=topsecret\ncat \u003c\u003cEOF | kubectl apply -n default -f -\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: workflow-controller-configmap\n  namespace: argo\ndata:\n  artifactRepository: |\n    archiveLogs: true          # 全局设置使得所有工作流日志做持久化\n    s3:\n      bucket: argo-workflow    # 在 minio 中创建的 bucket\n      endpoint: minio.minio.svc\n      insecure: true                  # 当 minio 没有启用 TLS\n      accessKeySecret:\n        name: minio-workflow\n        key: accessKey\n      secretKeySecret:\n        name: minio-workflow\n        key: secretKey\nEOF\n```\n\n完成上面的配置后，再次执行任意工作流，并将执行完成的 Pod 删除后，我们依然可以在 UI 上查看任务日志。并且，可以在 minio 中看到了新增的文件。每个 Pod 的日志在 minio 中分别以一个文件的形式存储。\n\n我们可以通过 minio 的命令行客户端 `mc` 看到类似如下的文件：\n\n```shell\nmc alias set myminio http://localhost:9001 minioadmin minioadmin\n# mc ls myminio/argo-workflow -r\n[2022-12-09 10:53:31 CST]    20B STANDARD hello-world-5mjgp/hello-world-5mjgp-clone-3848310779/main.log\n[2022-12-09 10:55:39 CST]  16KiB STANDARD hello-world-5mjgp/hello-world-5mjgp-image-2614052838/main.log\n[2022-12-09 10:54:35 CST] 5.9KiB STANDARD hello-world-5mjgp/hello-world-5mjgp-scan-4101005739/main.log\n[2022-12-09 10:53:51 CST]   435B STANDARD hello-world-5mjgp/hello-world-5mjgp-test-1532501286/main.log\n```\n\n### 参考链接\n\n* [支持的外部存储类型](https://argoproj.github.io/argo-workflows/configure-artifact-repository/)\n* [官方文档](https://argoproj.github.io/argo-workflows/configure-archive-logs/)\n\n### 小结\n\n通过上面的例子，我们可以看到：\n\n* Argo Workflows 能以非侵入式的配置，使得工作流日志输出到对象存储等外部存储中\n* Argo Workflows 的任务有输入、输出（input、output）的概念，日志的持久化是将日志作为输出写入到预先配置好的外部存储\n* 日志的持久化，可以分别在全局 ConfigMap、Workflow Spec、WorkflowTemplate 中配置\n\n## 引用已有模板中的任务\n\nArgo Workflows 允许以三种方式引用已有的任务：\n\n* 当前工作流\n* 当前命名空间中的工作流模板\n* 全局（Cluster 级别）的工作流模板\n\n这相当于 Java、Golang 等编程语言中的引用方式，分别可以引用：当前源文件、当前包、其他包下的函数。\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: hello-world\nspec:\n  templates:\n  - name: hd\n    dag:\n      tasks:\n      - name: hd\n        templateRef:            # 表示引用其他模板中的任务\n          name: hook            # 模板名称\n          template: hook        # 模板中的任务名称\n          clusterScope: true    # 为 true 是从全局（Cluster）中查找模板，为 false 时从当前命名空间中查找\n        arguments:\n          parameters:           # 给所引用的任务传递参数\n          - name: pr\n            value: 1\n```\n\n### 小结\n\n我们可以将公用的模板作为模板库，供工作流调用，这样就可以使得工作流变得简单。\n\n## 任务模板类型\n\n|||\n|---|---|\n| 容器 | 指定单个容器 |\n| 脚本 ||\n| [容器集合](https://argoproj.github.io/argo-workflows/container-set-template/) | 支持多个容器 |\n| [Directed-Acyclic Graph (DAG)](https://argoproj.github.io/argo-workflows/walk-through/dag/) | 支持指定任务之间的依赖关系，默认会尽可能地并发执行。 |\n| [HTTP](https://argoproj.github.io/argo-workflows/http-template/) | 支持发送 HTTP 请求 |\n| 资源 | 直接操作 Kubernetes 资源 |\n\n## 认证模型\nArgo workflows 支持三种认证模型：\n\n* server\n  * 采用服务端的 ServiceAccount，UI 节目无需登录认证，可作为体验、测试等场景使用\n* client\n  * 客户端需要提供 Token 等认证信息\n  * 从 v3.0+ 开始作为 Argo workflows 的默认认证方式\n* sso\n  * 后端有对应的 ServiceAccount 选择机制，包括有：优先级、表达式等匹配不同的用户、用户组权限\n\n其中，`sso` 和 `client` 可以组合使用，分别为：UI、webhook、SDK Client 等提供认证。\n\n## SSO\n为了保证 Argo workflows 同时支持 [SSO(Single Sign-On) ](https://argoproj.github.io/argo-workflows/argo-server-sso/)以及 webhook 的执行，需要设置认证模式为：\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: argo-server\n  namespace: argo\nspec:\n  template:\n    spec:\n      containers:\n      - args:\n        - server\n        - --auth-mode=sso           # UI 登录后所有操作使用的权限，参考后面的配置\n        - --auth-mode=client        # webhook 触发时采用的权限模式\n        name: argo-server\n```\n\n下面以 [Dex](https://github.com/devops-ws/dex-guide) 为例（需要有：`read_user`、`openid` 的授权），给出配置 SSO 信息：\n```yaml\napiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: workflow-controller-configmap\n  namespace: argo\ndata:\n  sso: |\n    issuer: https://10.121.218.184:31392/api/dex                    # Dex 服务地址\n    clientId:\n      name: argo-workflows-sso\n      key: client-id\n    clientSecret:\n      name: argo-workflows-sso\n      key: client-secret\n    redirectUrl: https://10.121.218.184:30298/oauth2/callback       # 这里 Argo workflows 的地址必须是浏览器可访问的\n    insecureSkipVerify: true\n    scopes:\n    - groups                        # 用组作为权限划分\n    - email\n    rbac:\n      enabled: true                 # 启用 RBAC 权限认证，下面需要提供对应的配置\n```\n\n创建上面所需要的 Secret：\n```shell\ncat \u003c\u003cEOF | kubectl apply -f argo -f\napiVersion: v1\ndata:\n  # 下面的 client-id、client-secret 可以向 oauth 服务提供者拿到\n  client-id: YXJnby13b3JrZmxvd3Mtc3Nv\n  client-secret: cmljaw==\nkind: Secret\nmetadata:\n  name: argo-workflows-sso\ntype: Opaque\nEOF\n```\n\n为 SSO 登录的用户提供只读权限：\n```shell\ncat \u003c\u003cEOF | kubectl apply -n argo -f -\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: user-default-login\n  annotations:\n    workflows.argoproj.io/rbac-rule: \"'dev' in groups\"        # dev 用户组登录后会使用该账号\n    workflows.argoproj.io/rbac-rule-precedence: \"10\"          # 多条规则匹配的情况下，选择数字大的\nEOF\n\ncat \u003c\u003cEOF | kubectl apply -n argo -f -\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\nmetadata:\n  labels:\n    app.kubernetes.io/instance: argo-workflow\n  name: argo-view-default-login-binding\nroleRef:\n  apiGroup: rbac.authorization.k8s.io\n  kind: ClusterRole\n  name: argo-aggregate-to-view                          # 内置的只读角色\nsubjects:\n- kind: ServiceAccount\n  name: user-default-login\n  namespace: argo\nEOF\n```\n\n### 小结\n可以给 Argo workflows 配置任意兼容 OAuth 2 的提供商，例如：Dex、GitHub、Gitlab 公有云、Gitlab 社区版、Argo CD 等。\n\n内置的角色包括（以下都是 ClusterRole）：\n\n* `argo-aggregate-to-view`\n* `argo-aggregate-to-edit`\n* `argo-aggregate-to-admin`\n* `argo-cluster-role`，没有 `workfloweventbindings` 的权限\n* `argo-server-cluster-role`，包含所有需要的权限\n\n## 插件机制\nArgo Workflows 内置了[几种类型的任务模板](#任务模板类型)，这些任务类型或是方便解决特定问题，或是可以解决通用问题。此外，我们还可以通过[执行器（Executor）插件](https://argoproj.github.io/argo-workflows/plugins/)扩展 Argo Workflows 的功能。\n\n执行器插件，会作为工作流 Pod 中 sidecar 的形式存在，通过 HTTP 提供服务。Argo Workflows 规定了 URI，以及 Request 和 Response。据此，我们可以看出来插件的几个特点：\n\n* 插件可以用任何编程语言实现\n* 执行插件任务时无需启动新的 Pod，减少了对 Pod 的消耗\n\n该插件功能默认是未启用的，我们可以在控制器（Controller）中添加环境变量的方式启用插件功能。请参考如下配置：\n\n```yaml\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: workflow-controller\nspec:\n  template:\n    spec:\n      containers:\n        - name: workflow-controller\n          env:\n            - name: ARGO_EXECUTOR_PLUGINS\n              value: \"true\"\n```\n\n安装插件时，只需要添加一个 ConfigMap 即可。例如：\n\n```yaml\napiVersion: v1\ndata:\n  sidecar.automountServiceAccountToken: \"false\"\n  sidecar.container: |\n    args:\n    - --provider\n    - gitlab\n    image: ghcr.io/linuxsuren/workflow-executor-gogit:master\n    command:\n    - workflow-executor-gogit\n    name: gogit-executor-plugin\n    ports:\n    - containerPort: 3001\n    resources:\n      limits:\n        cpu: 500m\n        memory: 128Mi\n      requests:\n        cpu: 250m\n        memory: 64Mi\n    securityContext:\n      allowPrivilegeEscalation: true\n      runAsNonRoot: true\n      runAsUser: 65534\nkind: ConfigMap\nmetadata:\n  labels:\n    workflows.argoproj.io/configmap-type: ExecutorPlugin\n  name: gogit-executor-plugin\n  namespace: argo\n```\n\n我们可以把上面的 ConfigMap 添加到 Argo Workflows 控制器所在的命名空间中，也可以添加到执行工作流所在的命名空间中。另外，当存在多个同名的插件时，会以工作流所在命名空间的插件为主。\n\n插件安装成功的话，你可以在控制器中查看到类似如下的日志输出：\n\n```\nlevel=info msg=\"Executor plugin added\" name=gogit-executor-plugin\n```\n\n插件的使用方法如下：\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: plugin\n  namespace: default\nspec:\n  entrypoint: main\n  hooks:\n    exit:\n      template: status\n    all:\n      template: status\n      expression: \"true\"\n  templates:\n  - container:\n      args:\n        - search\n        - kubectl\n      command:\n        - hd\n      image: ghcr.io/linuxsuren/hd:v0.0.70\n    name: main\n  - name: status\n    plugin:\n      gogit-executor-plugin:                    # 下面支持任何格式给插件传递参数\n        owner: linuxsuren\n        repo: test\n        pr: \"3\"\n```\n\n这里有[更多社区维护的插件](https://argoproj.github.io/argo-workflows/plugin-directory/)，有通过 Python、Golang、Rust 等语言实现的。\n\n如果你想了解如何开发一个插件，可以继续往后阅读。下面介绍插件机制对 HTTP 的请求、响应的规定：\n\n* Request payload 中可以解析到与当前工作流的信息，包括：名称、命名空间、插件参数\n  * 我们可以参考 [ExecuteTemplateArgs](https://github.com/argoproj/argo-workflows/blob/774bf47ee678ef31d27669f7d309dee1dd84340c/pkg/plugins/executor/template_executor_plugin.go#L19) 来解析请求\n* Response 需要告知任务执行的状态\n  * 我们可以参考 [ExecuteTemplateReply](https://github.com/argoproj/argo-workflows/blob/774bf47ee678ef31d27669f7d309dee1dd84340c/pkg/plugins/executor/template_executor_plugin.go#L32) 作为 HTTP 响应的数据\n\n## 归档\nArgo Workflow 支持将工作流执行记录（Workflow）的信息存储到 PostgreSQL 或 MySQL 中，以达到更长久地保存执行记录但又不会影响到\nKubernetes 集群的性能。\n\n这里，给出一个归档（ [Archive](https://argoproj.github.io/argo-workflows/workflow-archive/) ）数据到 PostgreSQL 的配置方法：\n\n首先，安装 [PostgreSQL](https://www.postgresql.org/) 。这里采用 Helm Chart 的方式来安装：\n```shell\nhelm repo add bitnami https://charts.bitnami.com/bitnami\nhelm repo update\ncat \u003e values.yaml \u003c\u003cEOF\nauth:\n  enablePostgresUser: true\n  postgresPassword: \"StrongPassword\"\n  username: \"root\"\n  password: \"root\"\n  database: \"app_db\"\nEOF\nhelm install postgresql-dev -f values.yaml bitnami/postgresql\n```\n\nArgo Workflows 会以 Secret 的方式读取数据库的用户名、密码，下面是创建 Secret 的命令：\n```shell\nkubectl create secret generic --from-literal=username=root --from-literal=password=root argo-postgres-config -n argo\n```\n\n然后，参考下面的 ConfigMap 启用工作流的归档功能：\n```yaml\napiVersion: v1\ndata:\n  persistence: |\n    archive: true\n    postgresql:\n      host: postgresql-dev.argocd.svc\n      port: 5432\n      database: app_db\n      tableName: argo_workflows\n      userNameSecret:\n        name: argo-postgres-config\n        key: username\n      passwordSecret:\n        name: argo-postgres-config\n        key: password\nkind: ConfigMap\nmetadata:\n  name: workflow-controller-configmap\n  namespace: argo\n```\n\n上面的配置步骤都完成，执行工作流后，我们可以在 UI 界面左侧菜单上看到归档的执行记录。也可以通过数据库命令行客户端连接数据库，查看数据的表记录信息：\n```shell\nexport POSTGRES_PASSWORD=root\nkubectl run postgresql-dev-client --rm --tty -i --restart='Never' --namespace default --image docker.io/bitnami/postgresql:14.1.0-debian-10-r80 --env=\"PGPASSWORD=$POSTGRES_PASSWORD\" --command -- psql --host postgresql-dev.argocd.svc -U root -d app_db -p 5432\n```\n\n下面是一些 PostgreSQL 命令行客户端的参考：\n```shell\n\\dt                                                   # 查看当前数据库中的表\nselect name,phase from argo_archived_workflows;       # 查看已归档的工作流执行记录\n```\n你会看到类似如下的输出：\n```sql\napp_db=\u003e \\dt\n                    List of relations\n Schema |              Name              | Type  | Owner\n--------+--------------------------------+-------+-------\n public | argo_archived_workflows        | table | root\n public | argo_archived_workflows_labels | table | root\n public | argo_workflows                 | table | root\n public | schema_history                 | table | root\n(4 rows)\n\napp_db=\u003e select name,phase from argo_archived_workflows;\n     name     |   phase\n--------------+-----------\n plugin-pl6rx | Succeeded\n plugin-8gs7c | Succeeded\n```\n\n## GC\nArgo Workflows 有个工作流执行记录（Workflow）的清理机制，也就是 Garbage Collect(GC)。GC 机制可以避免有太多的执行记录，\n防止 Kubernetes 的后端存储 Etcd 过载。\n\n我们可以在 ConfigMap 中配置期望保留的工作执行记录数量，这里支持为不同状态的执行记录设定不同的保留数量。配置方法如下：\n\n```yaml\napiVersion: v1\ndata:\n  retentionPolicy: |\n    completed: 3\n    failed: 3\n    errored: 3\nkind: ConfigMap\nmetadata:\n  name: workflow-controller-configmap\n  namespace: argo\n```\n\n需要注意的是，这里的清理机制会将多余的 Workflow 资源从 Kubernetes 中删除。如果希望能更多历史记录的话，建议启用并配置好归档功能。\n\n除了工作流有回收清理机制外，也可以针对 Pod 设置回收机制，参考配置如下：\n\n```yaml\napiVersion: argoproj.io/v1alpha1\nkind: WorkflowTemplate\nmetadata:\n  name: hello-world  # Name of this Workflow\n  namespace: default\nspec:\n  podGC:\n    strategy: OnPodCompletion\n```\n\n清理策略的可选值包括：\n\n* `OnPodCompletion`\n* `OnPodSuccess`\n* `OnWorkflowCompletion`\n* `OnWorkflowSuccess`\n\n建议 PodGC 与日志持久化配合使用，不然可能会由于 Pod 被删除后无法查看工作流日志。\n\n## 可观测\nArgo Workflows 支持通过 Prometheus 采集监控指标，包括：[预定义、自定义](https://argoproj.github.io/argo-workflows/metrics/)的指标，下面是添加自定义指标的示例：\n\n```yaml\nspec:\n  metrics:\n    prometheus:\n      - name: exec_duration_gauge\n        labels:\n          - key: name\n            value: '{{workflow.name}}' # 工作流名称\n          - key: templatename\n            value: '{{workflow.labels.workflows.argoproj.io/workflow-template}}' # 工作流模板名称\n          - key: namespace\n            value: '{{workflow.namespace}}' # 工作流所在命名空间\n        help: Duration gauge by name\n        gauge:\n          value: '{{workflow.duration}}' # 工作流执行时长\n      - counter:\n          value: \"1\"\n        help: \"Total count of all the failed workflows\"\n        labels:\n        - key: name\n          value: '{{workflow.name}}'\n        - key: namespace\n          value: '{{workflow.namespace}}'\n        - key: templatename\n          value: '{{workflow.labels.workflows.argoproj.io/workflow-template}}'\n        name: failed_count\n        when: '{{workflow.status}} == Failed'\n      - counter:\n          value: \"1\"\n        help: \"Total count of all the successed workflows\"\n        labels:\n        - key: name\n          value: '{{workflow.name}}'\n        - key: namespace\n          value: '{{workflow.namespace}}'\n        - key: templatename\n          value: '{{workflow.labels.workflows.argoproj.io/workflow-template}}'\n        name: successed_count\n        when: '{{workflow.status}} == Succeeded'\n      - counter:\n          value: \"1\"\n        help: \"Total count of all the workflows\"\n        labels:\n        - key: name\n          value: '{{workflow.name}}'\n        - key: namespace\n          value: '{{workflow.namespace}}'\n        - key: templatename\n          value: '{{workflow.labels.workflows.argoproj.io/workflow-template}}'\n        name: total_count\n```\n\n上面包含了工作流的成功、失败、总量的数据指标。\n\n## 工作流默认配置\n在实际场景下，我们往往需要配置不少的工作流模板，而这些模板中也通常会有一些通用的配置项，例如：\n拉取私有镜像的凭据、Pod 回收策略、卷挂载等待。我们可以把这些公共配置加到 ConfigMap 中，请参考如下：\n\n```yaml\napiVersion: v1\ndata:\n  workflowDefaults: |\n    spec:\n      podGC:\n        strategy: OnPodCompletion           # Pod 完成后即删除\n      imagePullSecrets:\n      - name: harbor-pull                   # 公共的私有镜像拉取凭据\n      volumeClaimTemplates:                 # 默认的代码拉取卷位置\n        - metadata:\n            name: work\n          spec:\n            accessModes: [\"ReadWriteOnce\"]\n            resources:\n              requests:\n                storage: 64Mi\nkind: ConfigMap\nmetadata:\n  name: workflow-controller-configmap\n  namespace: argo\n```\n\n## Golang SDK\nArgo Workflows 官方[维护了 Golang、Java、Python 语言](https://argoproj.github.io/argo-workflows/client-libraries/)的 SDK。下面以 Golang 为例，讲解 SDK 的使用方法。\n\n在运行下面的示例前，有两点需要注意的：\n\n* Argo Workflows Server 地址\n* Token\n\n你可以选择直接使用 `argo-server` 的 Service 地址，将端口 `2746` 转发到本地，或将 Service 修改为 `NodePort`，或者其他方法暴露端口。也可以执行下面的命令，再启动一个 Argo 服务：\n\n```shell\nargo server\n```\n\n第二个，就是用户认证的问题了。如果你对 Kubernetes 认证系统非常熟悉的话，可以跳过这一段，直接找一个 Token。为了让你对 Argo 的用户认证更加了解，我们为下面的测试代码创建一个新的 ServiceAccount。\n\n我们需要分别创建：\n\n* Role，规定可以对哪些资源有哪些操作权限\n\n```shell\nkubectl create role demo --verb=get,list,update,create --resource=workflows.argoproj.io --resource=workflowtemplates.argoproj.io -n default\n```\n\n* ServiceAccount，代表一个用户\n\n```shell\nkubectl create serviceaccount demo -n default\n```\n\n* RoleBinding，将用户和角色（Role）进行绑定\n\n```shell\nkubectl create rolebinding demo --role=demo --serviceaccount=default:demo -n default\n```\n\n* Secret，关联一个 ServiceAccount，并自动生成 Token\n\n```shell\nkubectl apply -n default -f - \u003c\u003cEOF\napiVersion: v1\nkind: Secret\nmetadata:\n  name: demo.service-account-token\n  annotations:\n    kubernetes.io/service-account.name: demo\ntype: kubernetes.io/service-account-token\nEOF\n```\n\n\u003e 上面的例子中，我们使用的是 `Role` 和 `RoleBinding` ，这样的角色只能允许访问所在命名空间（namespace）的资源。上面创建的用户，只能够访问 `default` 这命名空间下的 `Workflow` 和 `WorkflowTemplate` 。\n\u003e 如果想要创建一个全局的角色以及绑定，可以使用 `ClusterRole` 和 `ClusterRoleBinding` 。\n\n上面的用户创建完成后，我们就可以通过下面的命令拿到指定权限的 `Token` 了：\n\n```shell\nkubectl get secret -n default demo.service-account-token -ojsonpath={.data.token}|base64 -d\n```\n\n接下来，创建一个 Golang 工程，并将下面的示例代码拷贝到源文件 `main.go` 中。\n\n```shell\nmkdir demo\ncd demo\ngo mod init github.com/linuxsuren/demo\ngo get github.com/argoproj/argo-workflows/v3@v3.4.4\ngo mod tidy\n```\n\n示例代码：\n\n```golang\npackage main\n\nimport (\n\t\"fmt\"\n\t\"github.com/argoproj/argo-workflows/v3/pkg/apiclient\"\n\t\"github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflow\"\n\t\"github.com/argoproj/argo-workflows/v3/pkg/apiclient/workflowtemplate\"\n\t\"github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)\n\n/**\n** Before run this demo, please create a parameterless WorkflowTemplate in namespace default.\n** In this demo, we will print all the WorkflowTemplates in namespace default.\n** Then run a Workflow base on the first WorkflowTemplate.\n */\n\nfunc main() {\n\topt := apiclient.Opts{\n\t\tArgoServerOpts: apiclient.ArgoServerOpts{\n\t\t\tURL:                \"localhost:31808\", // argo-server address\n\t\t\tPath:               \"/\",\n\t\t\tSecure:             true,\n\t\t\tInsecureSkipVerify: true,\n\t\t},\n\t\tAuthSupplier: func() string {\n\t\t\treturn \"Bearer your-token\"\n\t\t},\n\t}\n\tctx, client, err := apiclient.NewClientFromOpts(opt) // the context will carry on auth\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\twftClient, err := client.NewWorkflowTemplateServiceClient()\n\tif err != nil {\n\t\tfmt.Println(\"failed to get the WorkflowTemplates client\", err)\n\t\treturn\n\t}\n\tdefaultNamespace := \"default\"\n\n\tfmt.Println(\"get the WorkflowTemplate list from\", defaultNamespace)\n\twftList, err := wftClient.ListWorkflowTemplates(ctx, \u0026workflowtemplate.WorkflowTemplateListRequest{\n\t\tNamespace: defaultNamespace,\n\t})\n\tif err != nil {\n\t\tfmt.Println(\"failed to list WorkflowTemplates\", err)\n\t\treturn\n\t}\n\tfor _, wft := range wftList.Items {\n\t\tfmt.Println(wft.Namespace, wft.Name)\n\t}\n\n\tif wftList.Items.Len() \u003e 0 {\n\t\twft := wftList.Items[0]\n\n\t\twfClient := client.NewWorkflowServiceClient()\n\t\t_, err := wfClient.CreateWorkflow(ctx, \u0026workflow.WorkflowCreateRequest{\n\t\t\tNamespace: defaultNamespace,\n\t\t\tWorkflow: \u0026v1alpha1.Workflow{\n\t\t\t\tObjectMeta: metav1.ObjectMeta{\n\t\t\t\t\tGenerateName: wft.Name,\n\t\t\t\t},\n\t\t\t\tSpec: v1alpha1.WorkflowSpec{\n\t\t\t\t\tWorkflowTemplateRef: \u0026v1alpha1.WorkflowTemplateRef{\n\t\t\t\t\t\tName: wft.Name,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t})\n\t\tif err != nil {\n\t\t\tfmt.Println(\"failed to create workflow\", err)\n\t\t}\n\t}\n}\n```\n\n最后，执行命令：`go run .`\n\n\u003e 把上面的示例代码编译后，二进制文件大致在 60M+\n\n## References\n* [DevOps Practice Guide](https://github.com/LinuxSuRen/devops-practice-guide)\n* [Argo CD Guide](https://github.com/LinuxSuRen/argo-cd-guide)\n* [Argo Rollouts Guide](https://github.com/LinuxSuRen/argo-rollouts-guide)\n* [更多场景下的模板样例](templates/README.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevops-ws%2Fargo-workflows-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevops-ws%2Fargo-workflows-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevops-ws%2Fargo-workflows-guide/lists"}