Argo Workflows es un motor de flujos de trabajo nativo de Kubernetes: cada paso de un workflow se ejecuta como un pod, y las dependencias entre pasos se declaran en YAML como una secuencia o como un grafo acíclico dirigido (DAG). Se usa para pipelines de datos, entrenamiento de modelos, tareas de mantenimiento y CI. En este tutorial instalarás Argo Workflows y su CLI, configurarás los permisos que necesitan los workflows y crearás workflows secuenciales, un DAG, una plantilla reutilizable y un CronWorkflow.

Requisitos previos

  • Un clúster de Kubernetes 1.28 o superior con al menos 2 GB de RAM libres, por ejemplo k3s en un VPS de CubePath o kind en tu equipo.
  • kubectl configurado con permisos de administrador del clúster, en Ubuntu 24.04 LTS o similar.
  • curl instalado.

Paso 1: Instalar Argo Workflows en el clúster

Argo Workflows se instala en su propio namespace con un único manifiesto publicado en cada release. Obtén la última versión estable desde la API de GitHub:

ARGO_VERSION=$(curl -fsSL https://api.github.com/repos/argoproj/argo-workflows/releases/latest | grep -Po '"tag_name": "\K[^"]+')
echo "$ARGO_VERSION"
v3.7.2

Crea el namespace y aplica el manifiesto. La opción --server-side evita el error de tamaño de anotación que dan los CRD grandes con kubectl apply clásico:

kubectl create namespace argo
kubectl apply -n argo --server-side -f "https://github.com/argoproj/argo-workflows/releases/download/${ARGO_VERSION}/install.yaml"

Espera a que el controlador y el servidor estén listos:

kubectl -n argo rollout status deployment/workflow-controller
kubectl -n argo rollout status deployment/argo-server
kubectl -n argo get pods
NAME                                   READY   STATUS    RESTARTS   AGE
argo-server-6c8d9f7b5-xk2lp            1/1     Running   0          60s
workflow-controller-7d9c6b8f4d-q8t5m   1/1     Running   0          60s

El workflow-controller vigila los objetos Workflow y crea los pods de cada paso; argo-server sirve la API y la interfaz web.

Paso 2: Instalar la CLI de Argo

La CLI argo permite enviar, seguir y depurar workflows. Usa la misma versión que el servidor:

curl -fsSLO "https://github.com/argoproj/argo-workflows/releases/download/${ARGO_VERSION}/argo-linux-amd64.gz"
gunzip argo-linux-amd64.gz
sudo install -m 0755 argo-linux-amd64 /usr/local/bin/argo
argo version --short
argo: v3.7.2

En servidores ARM64 descarga argo-linux-arm64.gz. La CLI usa tu kubeconfig para hablar con el clúster, así que no necesita configuración adicional.

Paso 3: Configurar la cuenta de servicio de los workflows

Cada pod de un workflow incluye un contenedor auxiliar (el executor) que informa al controlador de los resultados de cada paso creando objetos WorkflowTaskResult. La cuenta de servicio default no tiene ese permiso, así que crea una específica con el mínimo necesario:

nano argo-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: argo-workflow
  namespace: argo
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: executor
  namespace: argo
rules:
  - apiGroups:
      - argoproj.io
    resources:
      - workflowtaskresults
    verbs:
      - create
      - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: argo-workflow-executor
  namespace: argo
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: executor
subjects:
  - kind: ServiceAccount
    name: argo-workflow
    namespace: argo
kubectl apply -f argo-rbac.yaml

Si un paso necesita hacer algo más en el clúster (por ejemplo, ejecutar kubectl apply), añade esos permisos a una cuenta de servicio propia para ese workflow, no a esta.

Paso 4: Ejecutar un primer workflow

Un Workflow define un entrypoint y una lista de templates. El template más simple es un contenedor. Este recibe un parámetro con valor por defecto:

nano hola.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: hola-
spec:
  serviceAccountName: argo-workflow
  entrypoint: saludar
  arguments:
    parameters:
      - name: mensaje
        value: Hola desde Argo Workflows
  templates:
    - name: saludar
      inputs:
        parameters:
          - name: mensaje
      container:
        image: alpine:3.20
        command: [echo]
        args: ["{{inputs.parameters.mensaje}}"]

generateName hace que cada ejecución tenga un nombre único. Envía el workflow y sigue su progreso con --watch:

argo submit -n argo --watch hola.yaml -p mensaje="Mi primer workflow"
Name:                hola-7bq2x
Namespace:           argo
ServiceAccount:      argo-workflow
Status:              Succeeded
Duration:            12 seconds

STEP           TEMPLATE  PODNAME     DURATION  MESSAGE
 ✔ hola-7bq2x  saludar   hola-7bq2x  8s

Consulta la salida del paso. @latest se refiere al último workflow enviado:

argo logs -n argo @latest
hola-7bq2x: Mi primer workflow

Paso 5: Encadenar pasos y pasar parámetros

La forma steps ejecuta grupos de pasos en orden. Cada elemento de la lista externa es un grupo que empieza cuando termina el anterior; los pasos dentro del mismo grupo se ejecutan en paralelo. Un paso puede exportar un parámetro de salida leyendo un archivo de su contenedor:

nano pasos.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: pasos-
spec:
  serviceAccountName: argo-workflow
  entrypoint: principal
  templates:
    - name: principal
      steps:
        - - name: generar
            template: generar-numero
        - - name: mostrar
            template: mostrar-numero
            arguments:
              parameters:
                - name: numero
                  value: "{{steps.generar.outputs.parameters.numero}}"

    - name: generar-numero
      script:
        image: python:3.12-alpine
        command: [python]
        source: |
          import random
          with open("/tmp/numero.txt", "w") as f:
              f.write(str(random.randint(1, 100)))
      outputs:
        parameters:
          - name: numero
            valueFrom:
              path: /tmp/numero.txt

    - name: mostrar-numero
      inputs:
        parameters:
          - name: numero
      container:
        image: alpine:3.20
        command: [sh, -c]
        args: ["echo El número generado es {{inputs.parameters.numero}}"]

El template de tipo script permite escribir el código directamente en el YAML. Ejecuta el workflow y revisa los logs:

argo submit -n argo --watch pasos.yaml
argo logs -n argo @latest
pasos-m4k8d-mostrar-numero-2214986710: El número generado es 42

Paso 6: Definir dependencias con un DAG

Cuando las dependencias no son una secuencia simple, usa un template dag. Cada tarea declara de qué tareas depende y Argo ejecuta en paralelo todo lo que puede. Este ejemplo tiene forma de rombo: preparar se ejecuta primero, procesar-a y procesar-b en paralelo, y combinar al final:

nano dag.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: dag-
spec:
  serviceAccountName: argo-workflow
  entrypoint: rombo
  templates:
    - name: rombo
      dag:
        tasks:
          - name: preparar
            template: tarea
            arguments:
              parameters: [{name: nombre, value: preparar}]
          - name: procesar-a
            dependencies: [preparar]
            template: tarea
            arguments:
              parameters: [{name: nombre, value: procesar-a}]
          - name: procesar-b
            dependencies: [preparar]
            template: tarea
            arguments:
              parameters: [{name: nombre, value: procesar-b}]
          - name: combinar
            dependencies: [procesar-a, procesar-b]
            template: tarea
            arguments:
              parameters: [{name: nombre, value: combinar}]

    - name: tarea
      inputs:
        parameters:
          - name: nombre
      retryStrategy:
        limit: "2"
        retryPolicy: OnFailure
      container:
        image: alpine:3.20
        command: [sh, -c]
        args: ["echo Ejecutando {{inputs.parameters.nombre}}; sleep 5"]

retryStrategy reintenta hasta dos veces una tarea que falle, algo habitual en pasos que dependen de servicios externos. Ejecuta el DAG:

argo submit -n argo --watch dag.yaml
STEP             TEMPLATE  PODNAME                     DURATION  MESSAGE
 ✔ dag-5vzqp     rombo
 ├─✔ preparar    tarea     dag-5vzqp-tarea-2749512311  8s
 ├─✔ procesar-a  tarea     dag-5vzqp-tarea-1422918442  8s
 ├─✔ procesar-b  tarea     dag-5vzqp-tarea-1406140823  8s
 └─✔ combinar    tarea     dag-5vzqp-tarea-3011262084  8s

Para ver el grafo, abre la interfaz web (paso 9): procesar-a y procesar-b aparecen en paralelo.

Paso 7: Reutilizar la lógica con WorkflowTemplate

Un WorkflowTemplate guarda un workflow en el clúster para lanzarlo tantas veces como quieras, desde la CLI, la interfaz web o un CronWorkflow. Crea una plantilla con un parámetro obligatorio:

nano plantilla-informe.yaml
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: informe
spec:
  serviceAccountName: argo-workflow
  entrypoint: generar
  arguments:
    parameters:
      - name: entorno
  ttlStrategy:
    secondsAfterCompletion: 86400
  podGC:
    strategy: OnPodSuccess
  templates:
    - name: generar
      inputs:
        parameters:
          - name: entorno
      container:
        image: alpine:3.20
        command: [sh, -c]
        args: ["echo Generando informe de {{inputs.parameters.entorno}} el $(date -u +%F)"]

ttlStrategy borra el workflow un día después de terminar y podGC elimina los pods que terminan bien, para que las ejecuciones recurrentes no llenen el clúster de objetos. Registra la plantilla y lánzala:

argo template create -n argo plantilla-informe.yaml
argo submit -n argo --from workflowtemplate/informe -p entorno=produccion --watch
argo template list -n argo
NAME
informe

Paso 8: Programar ejecuciones con CronWorkflow

Un CronWorkflow lanza un workflow según una expresión cron, igual que un CronJob de Kubernetes. En lugar de repetir la definición, referencia la plantilla del paso anterior:

nano cron-informe.yaml
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
  name: informe-diario
spec:
  schedules:
    - "0 6 * * *"
  timezone: Europe/Madrid
  concurrencyPolicy: Forbid
  startingDeadlineSeconds: 300
  successfulJobsHistoryLimit: 3
  failedJobsHistoryLimit: 5
  workflowSpec:
    workflowTemplateRef:
      name: informe
    arguments:
      parameters:
        - name: entorno
          value: produccion

La ejecución es a las 6:00 hora de Madrid. concurrencyPolicy: Forbid evita que empiece una ejecución si la anterior sigue en marcha, y los límites de historial conservan solo las últimas ejecuciones.

Crea el CronWorkflow y, para probarlo sin esperar a la hora programada, lanza una ejecución manual:

argo cron create -n argo cron-informe.yaml
argo cron list -n argo
argo submit -n argo --from cronwf/informe-diario --watch

argo cron list muestra el CronWorkflow con su próxima ejecución, y la ejecución manual crea un workflow normal con el nombre informe-diario- seguido de un sufijo.

Para pausar las ejecuciones sin borrarlo, usa argo cron suspend -n argo informe-diario y argo cron resume para reanudarlas.

Paso 9: Acceder a la interfaz web

argo-server escucha en el puerto 2746 con HTTPS y un certificado autofirmado. Redirige el puerto a tu máquina:

kubectl -n argo port-forward svc/argo-server 2746:2746

Abre https://localhost:2746 y acepta el aviso del certificado. Por defecto el servidor usa el modo de autenticación client, que pide un token de Kubernetes. Genera uno de corta duración para una cuenta de servicio con permisos de lectura sobre los workflows, o bien, solo en un clúster local de pruebas, cambia al modo server, en el que la interfaz usa la cuenta de servicio del propio servidor:

kubectl -n argo patch deployment argo-server --type=json \
  -p='[{"op":"replace","path":"/spec/template/spec/containers/0/args","value":["server","--auth-mode=server"]}]'

Paso 10: Guardar artefactos (opcional)

Para pasar archivos entre pasos (no solo parámetros) o conservar resultados, Argo necesita un repositorio de artefactos compatible con S3. Se configura con un ConfigMap en el namespace de los workflows. Primero guarda las credenciales en un Secret:

kubectl -n argo create secret generic s3-credenciales \
  --from-literal=accessKey=your_access_key \
  --from-literal=secretKey=your_secret_key
nano artifact-repo.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: artifact-repositories
  namespace: argo
  annotations:
    workflows.argoproj.io/default-artifact-repository: default-v1
data:
  default-v1: |
    s3:
      bucket: your_bucket
      endpoint: your_s3_endpoint
      insecure: false
      accessKeySecret:
        name: s3-credenciales
        key: accessKey
      secretKeySecret:
        name: s3-credenciales
        key: secretKey
kubectl apply -f artifact-repo.yaml

Sustituye your_bucket y your_s3_endpoint (por ejemplo s3.example.com, sin https://). Con esto, un template puede declarar outputs.artifacts con la ruta de un archivo, y otro paso puede recibirlo en inputs.artifacts, igual que con los parámetros del paso 5.

Solución de problemas

workflowtaskresults.argoproj.io is forbidden: el workflow se ejecuta con una cuenta de servicio sin el Role executor. Comprueba que spec.serviceAccountName es argo-workflow o concede ese Role a la cuenta que uses.

El workflow se queda en Pending: normalmente el pod no se puede programar por falta de recursos o por una cuota. Revisa los eventos:

kubectl -n argo get events --sort-by=.lastTimestamp | tail -n 20
kubectl -n argo describe resourcequota

Ver y relanzar workflows fallidos:

argo list -n argo --status Failed
argo get -n argo nombre-del-workflow
argo retry -n argo nombre-del-workflow

argo get muestra en la columna MESSAGE el motivo del fallo de cada paso, y argo retry vuelve a ejecutar solo los pasos que fallaron.

Conclusión

Has instalado Argo Workflows y su CLI, configurado una cuenta de servicio con los permisos mínimos y creado workflows secuenciales, un DAG con reintentos, una plantilla reutilizable y una ejecución programada. Como siguientes pasos, puedes configurar SSO para la interfaz web, añadir Argo Events para lanzar workflows a partir de webhooks o mensajes, o combinarlo con Argo CD para que los workflows y plantillas se desplieguen desde Git.