Argo Workflows 部署操作记录

本文记录我在个人 VM 上部署 Argo Workflows 的过程,是一份学习笔记。环境是两台 VirtualBox 虚拟机:102 运行 Harbor 和 PostgreSQL,118 运行 Kubernetes 集群。所有操作和命令均来自实际执行记录。

一、环境与架构

两台 VM,同一 Host-Only 网段 192.168.56.0/24

复制代码
  ┌─────────────────────────┐       ┌──────────────────────────────┐
  │  102: Harbor + PG       │       │  118: K8s v1.33.6 (sealos)   │
  │                         │       │                              │
  │  ┌─────────────────┐    │       │  namespace: argo             │
  │  │ Harbor :80       │◄───┼───────┤  ┌────────────────────────┐ │
  │  │ 镜像仓库          │    │ pull  │  │ argo-workflows-server  │ │
  │  └─────────────────┘    │       │  │ (ClusterIP :2746)       │ │
  │                         │       │  └───────────┬────────────┘ │
  │  ┌─────────────────┐    │       │              │              │
  │  │ PostgreSQL :5432 │◄───┼───────┤  ┌───────────▼────────────┐ │
  │  │ (argo DB)        │    │ 外部DB│  │ argo-workflows-ctrl    │ │
  │  └─────────────────┘    │       │  └────────────────────────┘ │
  └─────────────────────────┘       │                              │
                                    │  namespace: traefik          │
                                    │  ┌────────────────────────┐ │
                                    │  │ traefik (NodePort)      │ │
                                    │  │ 80→31112  443→31248    │ │
                                    │  └───────────┬────────────┘ │
                                    │              │              │
                                    │  Ingress: argo118.local     │
                                    │    → argo-workflows-server  │
                                    └──────────────────────────────┘
  • Kubernetes:sealos 部署的单节点集群 v1.33.6,containerd 运行时
  • Harbor(102):私有镜像仓库,我把 Argo 和 Traefik 的镜像先推到这儿,集群再从 102 拉
  • PostgreSQL(102):Argo 用它存工作流历史,102 上刚好有个 PG 容器在跑,直接复用
  • Traefik:Ingress Controller,负责把 http 请求转到 Argo Server
  • Argo Workflows:CNCF 工作流引擎,Helm Chart 部署

二、镜像准备

Argo 需要 4 个镜像,我先在能拉 quay.io 的机器上做 docker tag + push 到 102:

bash 复制代码
# 1. CLI 镜像(argo server 用)
docker tag quay.io/argoproj/argocli:latest \
  192.168.56.102/library/quay.io/argoproj/argocli:latest
docker push 192.168.56.102/library/quay.io/argoproj/argocli:latest

# 2. Executor 镜像(工作流 Pod 用)
docker tag quay.io/argoproj/argoexec:latest \
  192.168.56.102/library/quay.io/argoproj/argoexec:latest
docker push 192.168.56.102/library/quay.io/argoproj/argoexec:latest

# 3. Controller 镜像
docker tag quay.io/argoproj/workflow-controller:latest \
  192.168.56.102/library/quay.io/argoproj/workflow-controller:latest
docker push 192.168.56.102/library/quay.io/argoproj/workflow-controller:latest

# 4. kubectl 镜像(CRD upgrade job 用)
docker pull registry.k8s.io/kubectl:latest
docker tag registry.k8s.io/kubectl:latest \
  192.168.56.102/library/registry.k8s.io/kubectl:latest
docker push 192.168.56.102/library/registry.k8s.io/kubectl:latest

tag 的命名我保留了原始路径(quay.io/argoproj/),这样一眼就能看出镜像来源,后面升级也方便找。


三、数据库准备

102 上已经跑着一个 PostgreSQL 容器(pgvector 镜像),直接给它建个 argo 库就行:

bash 复制代码
docker run --name pgvector-pg18 \
  -e POSTGRES_PASSWORD=123456 \
  -e POSTGRES_USER=postgres \
  -e POSTGRES_DB=argo \
  -p 5432:5432 \
  --restart=always \
  -d pgvector/pgvector:pg18-trixie

在 k8s 侧建个 Secret 存数据库凭据:

bash 复制代码
kubectl create namespace argo

kubectl create secret generic argo-postgres-config \
  -n argo \
  --from-literal=username=postgres \
  --from-literal=password=123456

四、安装 Argo Workflows

4.1 下载 Chart

bash 复制代码
wget https://github.com/argoproj/argo-helm/releases/download/argo-workflows-1.0.14/argo-workflows-1.0.14.tgz
tar xzf argo-workflows-1.0.14.tgz

解压后是个 argo-workflows/ 目录,用本地路径安装,不依赖 Helm repo。

4.2 手动装 CRD

一开始让 Helm 自己的 CRD install job 跑,但发现那个 Job 偶尔不稳。后来注意到解压出来的 chart 目录里 files/crds/minimal/ 就有现成的 YAML,一行命令直接 apply 更方便:

bash 复制代码
cd argo-workflows/files/crds/minimal/
kubectl apply --server-side -f .

里面 8 个 CRD:Workflow、CronWorkflow、WorkflowTemplate、ClusterWorkflowTemplate 等。

4.3 Values 配置

yaml 复制代码
# argo-workflows-values.yaml
usePostgresql: false          # 不用 Helm 内建的 PG

persistence:
  archive: true               # 启用工作流归档
  postgresql:
    host: 192.168.56.102      # 连 102 上的 PG
    port: 5432
    database: argo
    tableName: argo_workflows
    userNameSecret:
      name: argo-postgres-config
      key: username
    passwordSecret:
      name: argo-postgres-config
      key: password

crds:
  install: false              # 前面手动 apply 过了,关掉 Helm 的 CRD Job
  upgradeJob:
    image:
      repository: 192.168.56.102/library/registry.k8s.io/kubectl

controller:
  image:
    registry: 192.168.56.102/library/quay.io
    tag: latest

executor:
  image:
    registry: 192.168.56.102/library/quay.io
    tag: latest

server:
  image:
    registry: 192.168.56.102/library/quay.io
    tag: latest

所有 image registry 都指向 102 的 Harbor。

4.4 安装

bash 复制代码
helm install argo-workflows ./argo-workflows \
  --namespace argo \
  --values argo-workflows-values.yaml

4.5 验证

bash 复制代码
kubectl get pods -n argo
# NAME                                                  READY   STATUS    RESTARTS   AGE
# argo-workflows-server-6b97579665-tnm9n                1/1     Running   0          3m
# argo-workflows-workflow-controller-7798db698f-9bkmq   1/1     Running   0          3m

五、Traefik 接入:一个 LoadBalancer 引发的排查

有了 Argo,还需要从浏览器访问它的 Web UI。选 Traefik 做 Ingress Controller。

5.1 初始配置

yaml 复制代码
# traefik-values.yaml
service:
  type: NodePort               # 裸金属环境,用 NodePort 暴露

image:
  registry: 192.168.56.102/library
  repository: traefik
  tag: v3.6.7
bash 复制代码
helm install traefik traefik/traefik \
  --namespace traefik \
  --values traefik-values.yaml

5.2 不对劲

检查 Service 状态:

bash 复制代码
kubectl get svc -n traefik
# NAME      TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
# traefik   LoadBalancer   10.99.241.28    <pending>     80:31112/TCP,443:31248/TCP   2m

TYPE 显示 LoadBalancer,EXTERNAL-IP 永远是 <pending> 可我 values 里明明写的 NodePort

5.3 排查过程

第一反应------是不是缺 MetalLB?不对,values 本身就指定了 NodePort,没有 LoadBalancer 控制器不应该影响 Service type 的判断。

helm template 渲染一下看看 chart 到底生成了什么:

bash 复制代码
helm template traefik traefik/traefik \
  --namespace traefik \
  --values traefik-values.yaml | grep -A10 "kind: Service"

输出:

yaml 复制代码
kind: Service
# ...
spec:
  type: LoadBalancer      # ← 还是 LoadBalancer!

values 文件没有生效。 说明 key 路径不对。

5.4 定位根因

直接看 chart 的默认 values:

bash 复制代码
helm show values traefik/traefik | grep -B15 "type: LoadBalancer"

关键片段:

yaml 复制代码
service:
  enabled: true
  spec:                     # ← 注意这一层
    type: LoadBalancer

Traefik chart 40.2.0 的 service type 配置路径是 service.spec.type,不是 service.type 老版本 chart(34.x 之前)用的是 service.type,新版本把 Service 相关配置收敛到了 service.spec 下。

5.5 修复

diff 复制代码
 service:
-  type: NodePort
+  spec:
+    type: NodePort

 image:
   registry: 192.168.56.102/library
bash 复制代码
helm upgrade traefik traefik/traefik \
  -n traefik \
  --values traefik-values.yaml

再检查:

bash 复制代码
kubectl get svc -n traefik
# NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
# traefik   NodePort   10.99.241.28    <none>        80:31112/TCP,443:31248/TCP   10s

5.6 配置 Ingress

Traefik 就绪后,创建 Ingress 把外部请求转到 Argo Server:

yaml 复制代码
# argo-workflows-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argo-workflows-ingress
  namespace: argo
  annotations:
    kubernetes.io/ingress.class: "traefik"
    traefik.ingress.kubernetes.io/router.entrypoints: "web"
spec:
  rules:
  - host: argo118.local
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argo-workflows-server
            port:
              number: 2746
bash 复制代码
kubectl apply -f argo-workflows-ingress.yaml

本机 /etc/hosts 加上:

复制代码
192.168.56.118  argo118.local

浏览器访问 http://argo118.local:31112,看到 Argo UI。

5.7 获取登录 Token

Argo Server 默认开启了 server 认证模式,打开 UI 后会先看到一个登录页要求填 Bearer Token。Token 就在集群里,一行命令取出来:

bash 复制代码
TOKEN="Bearer $(kubectl get secret argo-workflows-server-token \
  -n argo -o jsonpath='{.data.token}' | base64 --decode)"
echo $TOKEN

把输出的 Token 粘贴到登录页的输入框,点 Login 就进去了。这个 Secret 是 Helm 部署时自动为 argo-workflows-server ServiceAccount 创建的,不需要手动建。


六、Demo 验证

下面用 argo submit 提交工作流,这个命令走的是 kubeconfig 直连 kube-apiserver,不需要上面那个 Token。

装个 Argo CLI:

bash 复制代码
curl -sLO https://github.com/argoproj/argo-workflows/releases/latest/download/argo-linux-amd64.gz
gunzip argo-linux-amd64.gz
chmod +x argo-linux-amd64
sudo mv argo-linux-amd64 /usr/local/bin/argo

提一个 hello-world 工作流试试:

bash 复制代码
argo submit -n argo --watch - <<EOF
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: hello-world-
spec:
  entrypoint: main
  templates:
  - name: main
    container:
      image: alpine:latest
      command: [echo]
      args: ["Hello Argo Workflows!"]
EOF

整个链路:argo submit → controller 调度 → Pod 执行 → echo 输出 → PG 归档 → UI 可查。打开 Argo UI 能看到执行历史和日志,说明全链路通了。


七、踩坑记录 & 下一步

7.1 Ingress YAML 写错了

回看实际部署的 Ingress,hosthttp 被写成了两个独立的 rule:

yaml 复制代码
spec:
  rules:
  - host: argo118.local          # rule 1: 只有 host,无 http
  - http:                        # rule 2: 只有 http,无 host(匹配所有)
      paths:
      - ...

应该是合并成一个 rule 才对。虽然目前能访问(第二个 rule 匹配所有 host 兜底了),但后面得改回来。

7.2 serversscheme: https 可能多余

Argo Server 默认在 2746 跑的是 HTTP。我的 Ingress 里加了 traefik.ingress.kubernetes.io/service.serversscheme: "https",这会让 Traefik 尝试用 HTTPS 连后端。目前没出问题,但如果遇到 502 就先排查这个 annotation。

7.3 接下来可以试试

  • 配一下 Argo UI 的登录认证(目前裸奔)
  • 把镜像 tag 从 latest 固定到具体版本号
  • 用 Traefik 原生的 IngressRoute CRD 替代标准 Ingress
  • 写个带步骤依赖的 DAG 工作流跑跑看

操作记录于 2026-06-07 | sealos k8s v1.33.6 + Harbor v2.14.2 + Traefik v3.6.7