An open API service indexing awesome lists of open source software.

https://github.com/chriskery/argo-workflow-guide


https://github.com/chriskery/argo-workflow-guide

argo

Last synced: 6 months ago
JSON representation

Awesome Lists containing this project

README

          

# argo-workflow-guide

[Argo Workflows](https://argoproj.github.io/argo-workflows/) 是一个[云原生](https://en.wikipedia.org/wiki/Cloud-native_computing)的通用的工作流引擎。本教程主要介绍如何用其完成持续集成(Continous Integration, CI)任务。

## 基本概念

对任何工具的基本概念有一致的认识和理解,是我们学习以及与他人交流的基础。
以下是本文涉及到的概念:

- WorkflowTemplate,工作流模板
- Workflow,工作流

为方便读者理解,下面就几个同类工具做对比:

| Argo Workflow | Jenkins |
| ---------------- | -------- |
| WorkflowTemplate | Pipeline |
| Workflow | Build |

## 安装

通过如下命令安装 argo:

```shell
kubectl create namespace argo
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/latest/download/install.yaml
```

如果你的环境访问 GitHub 时有网络问题,可以使用下面的命令来安装:

```shell
docker run -it --rm -v $HOME/.kube/:/root/.kube --network host --pull always ghcr.io/linuxsuren/argo-workflows-guide:master
```

Argo 组件:
上面的安装命令会安装两个 Deploy,分别对应 Argo 的两个组件:

- Workflow Controller:负责运行 Workflows
- Argo Server:提供 UI 和 API

## 安装 Argo CLI
访问如下链接查看 Argo Cli 安装方法详情:[https://github.com/argoproj/argo-workflows/releases/](https://github.com/argoproj/argo-workflows/releases/)
For Mac:

```shell
# Download the binary
curl -sLO https://github.com/argoproj/argo-workflows/releases/download/v3.5.6/argo-darwin-amd64.gz

# Unzip
gunzip argo-darwin-amd64.gz

# Make binary executable
chmod +x argo-darwin-amd64

# Move binary to path
mv ./argo-darwin-amd64 /usr/local/bin/argo

# Test installation
argo version
```

## 设置访问方式
默认情况下argo-server采用客户端认证,这要求客户端使用**Kubernetes bearer token 进行身份认证。**对于学习、体验等场景,我们可以通过下面的命令直接设置绕过登录:
```shell
kubectl patch deployment \
argo-server \
--namespace argo \
--type='json' \
-p='[{"op": "replace", "path": "/spec/template/spec/containers/0/args", "value": [
"server",
"--auth-mode=server"
]}]'
````

我们可以用下面的方式或者其他方式来设置 Argo Workflows 的访问端口:

```shell
kubectl -n argo port-forward deploy/argo-server --address 0.0.0.0 2746:2746
# 或者设置为 NodePort
kubectl -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}]'
```

需要注意的是,这里默认的配置下,服务器设置了自签名的证书提供 HTTPS 服务,因此,确保你使用 https:// 协议进行访问。
例如,地址为:https://10.121.218.242:2746/

## Workflow 概念

#### Workflow 被定义为 Kubernetes 里面的资源。每一个 Workflow 由一个或多个模版组成(称为 Template),这些模版中的某一个称为 Entrypoint(即 Workflow 的运行起点)。

```shell
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: hello
spec:
serviceAccountName: argo # this is the service account that the workflow will run with
entrypoint: main # the first template to run in the workflows
templates:
- name: main
container: # this is a container template
image: docker/whalesay # this image prints "hello world" to the console
command: ["cowsay"]
```

在上面的示例中,我们定义了一个 Workflow,他有一个模版,叫作 main,entrypoint 为 main 模版。

## Template

### 基本概念

Template 可分为两种大类:work 和**orchestration。**

- **work 定义了一系列需要完成的工作,work 类型包括:**
- Container
- Container Set
- Data
- Resource
- Script
- **orchestrates:对 work 进行编排,包括:**
- DAG
- Steps
- Suspend

**比如我们定义了三个 work-work1、work2、work3,我们想要串行执行三个 work,则需要 DAG 对 work 进行编排。**

### Work 类型

- **Container:不同的 Container 运行在不同的 Pod 中**
- **ContainerSet:在同一个 Pod 中运行多个 Container**
- **Data:允许你从某个存储(比如 S3)中获取数据。**
- Resource: 允许你创建一个 K8S 资源并等待某个条件满足,一般用于需要跟其他的 Kubernetes 系统进行协作的场景。
- **script:其实也是 Container,不过启动命令使用脚本的方式提供。**

### Orchestrates

##### DAG:

```shell
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: dag-
spec:
entrypoint: main
templates:
- name: main
dag:
tasks:
- name: a
template: whalesay
- name: b
template: whalesay
dependencies:
- a
- name: whalesay
container:
image: docker/whalesay
command: [ cowsay ]
args: [ "hello world" ]
```

这里定义了两个 templates,一个是 main、一个是 whalesay,main 作为 entrypoint。main 里面包含两个 tasks,a 和 b,都使用 whalesay template,但 b 依赖 a,也就是说,在 a 成功运行完成之前,b 不会运行。运行完成后查看执行结果:

```shell
argo -n argo get @latest
STEP TEMPLATE PODNAME DURATION MESSAGE
✔ dag-shxn5 main
├─✔ a whalesay dag-shxn5-289972251 6s
└─✔ b whalesay dag-shxn5-306749870
```

DAG Loops
Argo Flow 支持运行大量的并行的作业,DAG 定义了一个`withItems`属性,可以用来进行任务的循环。

```shell
dag:
tasks:
- name: print-message
template: whalesay
arguments:
parameters:
- name: message
value: "{{item}}"
withItems:
- "hello world"
- "goodbye world"
```

在这个例子中,print-message 将会运行 2 次。{{item}}市 Template Tags 的写法,在运行时会被解析成 "hello world" 和 "goodbye world"。DAG 默认情况会并行执行 Item,因此两个任务会同时被启动。
DAG Loop 提供了另外一个叫做`withSequence`,可以直接用来定义任务数量,而无需一行行写 items:

```shell
dag:
tasks:
- name: print-message
template: whalesay
arguments:
parameters:
- name: message
value: "{{item}}"
withSequence:
count: 5
等价于:
withItems:
- "0"
- "1"
- "2"
- "3"
- "4"
```

**Template Tags(模版变量)**
**Template Tags 其实就是在 Template 中定义了一系列的变量,这些变量的值在运行时进行传入。(类似 Helm Template 变量,渲染时通过 values.yaml 进行传值)**
**不同的 Work 类型可以定义不同的 Template Tags,但也有一些变量是跟类型无关的,如下所示:**

```shell
- name: main
container:
image: docker/whalesay
command: [ cowsay ]
args: [ "hello {{workflow.name}}" ]
```

{{workflow.name}} 引用了当前 Workflow 的 name。

##### Step:

Exit Handler:

```shell
dag:
tasks:
- name: a
template: whalesay
onExit: tidy-up
```

上面的意思是 a 运行完成以后执行 task tidy-up,如果我们想要在某些任务结束后执行另外一个 task,我们可以使用 Exit Handler。

## Workflow Template

**Workflow templates** (区别于 template) 允许我们定义可重用的 Template 模版:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: hello
spec:
entrypoint: main
templates:
- name: main
container:
image: docker/whalesay
command: [cowsay]
```

## 简单示例

下面是一个非常简单的 Argo Workflow 示例:

1. 通过 Argo cli 提交:

```go
argo submit -n argo --watch https://raw.githubusercontent.com/argoproj/argo-workflows/main/examples/hello-world.yaml
```

--watch flag 会监听 workflow 的运行状态,监测 workflow 是否成功运行。当 workflow 运行结束后,针对 workflow 的监听会停止。

```shell
Name: hello-world-vkg5j
Namespace: argo
ServiceAccount: unset (will run with the default ServiceAccount)
Status: Pending
Created: Wed Apr 24 20:19:19 +0800 (now)
Progress:
Name: hello-world-vkg5j
Namespace: argo
ServiceAccount: unset (will run with the default ServiceAccount)
Status: Running
Created: Wed Apr 24 20:19:19 +0800 (now)
Started: Wed Apr 24 20:19:19 +0800 (now)
Duration: 0 seconds
Progress: 0/1
```

argo cli 相关命令:

```shell
1.argo list -n argo //列出workflow list
。@latest is an alias for the latest workflow:
2.argo get -n argo @latest/--name xx //查看workflow详情
3.argo logs -n argo @latest/--name xx //查看workflow日志
```

2. 通过 kubectl 提交:

```shell
cat < /tmp/hello_world.txt"]
outputs:
parameters:
- name: hello-param
valueFrom:
path: /tmp/hello_world.txt
```

这里定义了一个输出参数 hello-param,他的内容是 container 结束时候的/tmp/hello_world.txt 的内容,即"hello world"。
在 DAG 或者 Step 中,我们可以使用**template tag 将**某个任务的输出作为其他任务的输入 paramter:

```shell
dag:
tasks:
- name: generate-parameter
template: whalesay
- name: consume-parameter
template: print-message
dependencies:
- generate-parameter
arguments:
parameters:
- name: message
value: "{{tasks.generate-parameter.outputs.parameters.hello-param}}"
```

## CronWorkflow

CronWorkflow 使用 cron 进行调度:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
name: hello-cron
spec:
schedule: "* * * * *"
workflowSpec:
entrypoint: main
templates:
- name: main
container:
image: docker/whalesay
```

### Artifact

Argo 将存储在对象存储(S3, MinIO, GCS, etc.).里面的文件叫做一个 Artifact。我们可以引用某个 Artifact 作为输入,也可以指定输出到 Artifact 中。Argo 称存储 Artifact 的对象存储为**artifact repository。**

- An **input artifact** is a file downloaded from storage (i.e. S3) and mounted as a volume within the container.
- An **output artifact** is a file created in the container that is uploaded to storage.

输出 Artifact:

```yaml
- name: save-message
container:
image: docker/whalesay
command: [sh, -c]
args: ["cowsay hello world > /tmp/hello_world.txt"]
outputs:
artifacts:
- name: hello-art
path: /tmp/hello_world.txt
```

当容器结束的时候,会存储容器内的/tmp/hello_world.txt 到**artifact repository 中,文件名为 hello-art。Artifact 支持存储目录。**

## Webhook

所有主流 Git 仓库都是支持 webhook 的,借助 webhook 可以当代码发生变化后实时地触发工作流的执行。

1. It only allows you to create workflows from a WorkflowTemplate , so is more secure.
2. It allows you to parse the HTTP payload and use it as parameters.
3. It allows you to integrate with other systems without you having to change those systems.
4. Webhooks also support GitHub and GitLab, so you can trigger workflow from git actions.

Argo Workflows 利用 WorkflowEventBinding 将收到的 webhook 请求与 WorkflowTemplate 做关联。请参考下面的例子:

```shell
cat < values.yaml < \dt
List of relations
Schema | Name | Type | Owner
--------+--------------------------------+-------+-------
public | argo_archived_workflows | table | root
public | argo_archived_workflows_labels | table | root
public | argo_workflows | table | root
public | schema_history | table | root
(4 rows)
```

app_db=> select name,phase from argo_archived_workflows;
name | phase
--------------+-----------
plugin-pl6rx | Succeeded
plugin-8gs7c | Succeeded

````
## GC
Argo Workflows 有个工作流执行记录(Workflow)的清理机制,也就是 Garbage Collect(GC)。GC 机制可以避免有太多的执行记录, 防止 Kubernetes 的后端存储 Etcd 过载。
我们可以在 ConfigMap 中配置期望保留的工作执行记录数量,这里支持为不同状态的执行记录设定不同的保留数量。配置方法如下:
```yaml
apiVersion: v1
data:
retentionPolicy: |
completed: 3
failed: 3
errored: 3
kind: ConfigMap
metadata:
name: workflow-controller-configmap
namespace: argo
````

需要注意的是,这里的清理机制会将多余的 Workflow 资源从 Kubernetes 中删除。如果希望能更多历史记录的话,建议启用并配置好归档功能。
除了工作流有回收清理机制外,也可以针对 Pod 设置回收机制,参考配置如下:

```yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: hello-world # Name of this Workflow
namespace: default
spec:
podGC:
strategy: OnPodCompletion
```

清理策略的可选值包括:

- OnPodCompletion
- OnPodSuccess
- OnWorkflowCompletion
- OnWorkflowSuccess

建议 PodGC 与日志持久化配合使用,不然可能会由于 Pod 被删除后无法查看工作流日志。

## 可观测

Argo Workflows 支持通过 Prometheus 采集监控指标,包括:[预定义、自定义](https://argoproj.github.io/argo-workflows/metrics/)的指标,下面是添加自定义指标的示例:

```yaml
spec:
metrics:
prometheus:
- name: exec_duration_gauge
labels:
- key: name
value: "{{workflow.name}}" # 工作流名称
- key: templatename
value: "{{workflow.labels.workflows.argoproj.io/workflow-template}}" # 工作流模板名称
- key: namespace
value: "{{workflow.namespace}}" # 工作流所在命名空间
help: Duration gauge by name
gauge:
value: "{{workflow.duration}}" # 工作流执行时长
- counter:
value: "1"
help: "Total count of all the failed workflows"
labels:
- key: name
value: "{{workflow.name}}"
- key: namespace
value: "{{workflow.namespace}}"
- key: templatename
value: "{{workflow.labels.workflows.argoproj.io/workflow-template}}"
name: failed_count
when: "{{workflow.status}} == Failed"
- counter:
value: "1"
help: "Total count of all the successed workflows"
labels:
- key: name
value: "{{workflow.name}}"
- key: namespace
value: "{{workflow.namespace}}"
- key: templatename
value: "{{workflow.labels.workflows.argoproj.io/workflow-template}}"
name: successed_count
when: "{{workflow.status}} == Succeeded"
- counter:
value: "1"
help: "Total count of all the workflows"
labels:
- key: name
value: "{{workflow.name}}"
- key: namespace
value: "{{workflow.namespace}}"
- key: templatename
value: "{{workflow.labels.workflows.argoproj.io/workflow-template}}"
name: total_count
```

上面包含了工作流的成功、失败、总量的数据指标。

## 工作流默认配置

在实际场景下,我们往往需要配置不少的工作流模板,而这些模板中也通常会有一些通用的配置项,例如: 拉取私有镜像的凭据、Pod 回收策略、卷挂载等待。我们可以把这些公共配置加到 ConfigMap 中,请参考如下:

```yaml
apiVersion: v1
data:
workflowDefaults: |
spec:
podGC:
strategy: OnPodCompletion # Pod 完成后即删除
imagePullSecrets:
- name: harbor-pull # 公共的私有镜像拉取凭据
volumeClaimTemplates: # 默认的代码拉取卷位置
- metadata:
name: work
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 64Mi
kind: ConfigMap
metadata:
name: workflow-controller-configmap
namespace: argo
```

## Golang SDK

Argo Workflows 官方[维护了 Golang、Java、Python 语言](https://argoproj.github.io/argo-workflows/client-libraries/)的 SDK。下面以 Golang 为例,讲解 SDK 的使用方法。
在运行下面的示例前,有两点需要注意的:

- Argo Workflows Server 地址
- Token

你可以选择直接使用 argo-server 的 Service 地址,将端口 2746 转发到本地,或将 Service 修改为 NodePort,或者其他方法暴露端口。也可以执行下面的命令,再启动一个 Argo 服务:

```shell
argo server
```

第二个,就是用户认证的问题了。如果你对 Kubernetes 认证系统非常熟悉的话,可以跳过这一段,直接找一个 Token。为了让你对 Argo 的用户认证更加了解,我们为下面的测试代码创建一个新的 ServiceAccount。
我们需要分别创建:

- Role,规定可以对哪些资源有哪些操作权限

```shell
kubectl create role demo --verb=get,list,update,create --resource=workflows.argoproj.io --resource=workflowtemplates.argoproj.io -n default
```

- ServiceAccount,代表一个用户

```shell
kubectl create serviceaccount demo -n default
```

- RoleBinding,将用户和角色(Role)进行绑定

```shell
kubectl create rolebinding demo --role=demo --serviceaccount=default:demo -n default
```

- Secret,关联一个 ServiceAccount,并自动生成 Token

```shell
kubectl apply -n default -f - < 0 {
wft := wftList.Items[0]

wfClient := client.NewWorkflowServiceClient()
_, err := wfClient.CreateWorkflow(ctx, &workflow.WorkflowCreateRequest{
Namespace: defaultNamespace,
Workflow: &v1alpha1.Workflow{
ObjectMeta: metav1.ObjectMeta{
GenerateName: wft.Name,
},
Spec: v1alpha1.WorkflowSpec{
WorkflowTemplateRef: &v1alpha1.WorkflowTemplateRef{
Name: wft.Name,
},
},
},
})
if err != nil {
fmt.Println("failed to create workflow", err)
}
}
```

}

```
最后,执行命令:go run .
把上面的示例代码编译后,二进制文件大致在 60M+
## References

- [DevOps Practice Guide](https://github.com/LinuxSuRen/devops-practice-guide)
- [Argo CD Guide](https://github.com/LinuxSuRen/argo-cd-guide)
- [Argo Rollouts Guide](https://github.com/LinuxSuRen/argo-rollouts-guide)
- [更多场景下的模板样例](templates/README.md)
```