Argo Workflows Labs
Hands-on labs for Argo Workflows (CAPA). All yaml lives in yaml/. Run everything from this directory.
Argo Workflows = container-native workflow engine for kubernetes. Each step runs as a pod. Workflows are a CRD (Workflow), reconciled by the workflow controller.
Lab 0: Setup
Using kind + the quick-start manifest (includes minio as the artifact repo, needed for lab 4).
kind create cluster
kubectl create namespace argo
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.5.10/quick-start-minimal.yaml
kubectl -n argo wait --for=condition=ready pod --all --timeout=180s
- Check https://github.com/argoproj/argo-workflows/releases for the latest version, 3.5.10 is just what I pinned
- Install the
argoCLI from the same releases page
UI:
kubectl -n argo port-forward svc/argo-server 2746:2746
- Browse to
https://localhost:2746(self signed cert, quick-start runs the server with--auth-mode=serverso no login)
Verify:
-
kubectl get pods -n argoshowsworkflow-controller,argo-server,minio,postgres -
argo versionworks - UI loads
Cleanup between labs: argo delete --all -n argo
Lab 1: Hello World
Goal: submit a single container workflow and read its logs.
argo submit -n argo --watch yaml/01-hello.yaml
argo list -n argo
argo logs -n argo @latest
generateNamegives each run a unique name (hello-xxxxx)entrypointpicks which template runs first@latest= most recent workflow
Try:
- Find the pod with
kubectl get pods -n argo. Why does it have 2 containers (mainandwait)? - View the workflow in the UI
-
kubectl get wf -n argoandkubectl get wf -n argo -o yaml(look atstatus.nodes) - Change the image/args and resubmit
Lab 2: Steps and Parameters
Goal: sequential vs. parallel steps, passing parameters.
argo submit -n argo --watch yaml/02-steps-params.yaml
argo submit -n argo --watch yaml/02-steps-params.yaml -p message=goodbye
- Outer list = sequential. Inner list = parallel
workflow.parameters.xare global,inputs.parameters.xare per template
Try:
- Confirm
parallel-aandparallel-bstart at the same time - Override the global param with
-p - Add a 4th group that depends on nothing else
Lab 3: DAGs
Goal: express dependencies as a graph instead of ordered steps.
argo submit -n argo --watch yaml/03-dag.yaml
- Diamond: A > (B, C) > D
- DAG tasks start as soon as their
dependenciesare done. Steps groups wait for the entire previous group
Try:
- Add
sleep 10to B only. Does C finish first? Does D wait? - Add task E that depends on C only. Does it wait for B?
- Make C fail (
exit 1). What happens to D? (look atfailFast) - Look at the graph in the UI
Lab 4: Outputs and Artifacts
Goal: pass data between steps.
argo submit -n argo --watch yaml/04-outputs-artifacts.yaml
argo logs -n argo @latest
- Output parameter: small value read from a file (
valueFrom.path). Stored in the workflow status - Artifact: a file/dir, stored in the artifact repo (minio here). For larger data
- Artifacts need an artifact repository configured, that is why we used quick-start
Try:
- Download the artifact from the UI
- Find the artifact in minio (
kubectl -n argo port-forward svc/minio 9001:9001, loginadmin/password) - What happens to the workflow if you remove the artifact repo config? (
kubectl get cm -n argo)
Lab 5: Loops and Conditionals
Goal: dynamic fan-out and branching.
argo submit -n argo --watch yaml/05-loops-conditionals.yaml
withItemscreates one pod per itemwhenevaluates an expression, skipped steps show asSkippedscripttemplates put stdout inoutputs.result
Try:
- Run it a few times. Does the branch change?
- Use
withParamwith a JSON list from a previous step instead ofwithItems - Limit parallelism with
spec.parallelism: 1
Lab 6: WorkflowTemplates
Goal: reuse templates across workflows.
kubectl apply -f yaml/06-workflow-template.yaml
argo template list -n argo
argo submit -n argo --watch yaml/06-use-template.yaml
WorkflowTemplate= namespaced and reusable.ClusterWorkflowTemplate= cluster widetemplateRefcalls a template from another WorkflowTemplate06-workflow-template.yamlis the template,06-use-template.yamlis a workflow that calls it
Try:
- Add
spec.entrypoint: greetto the template, then run it directly:argo submit -n argo --watch --from workflowtemplate/greeter -p name=bob - Convert it to a
ClusterWorkflowTemplate(templateRef.clusterScope: true)
Lab 7: CronWorkflows
Goal: run workflows on a schedule.
kubectl apply -f yaml/07-cron.yaml
argo cron list -n argo
# wait a couple minutes
argo list -n argo
- Same cron syntax as k8s CronJob
concurrencyPolicy: Allow / Forbid / Replace
Try:
-
argo cron suspend every-minute -n argothenresume - Set
concurrencyPolicy: Forbidand make the job sleep 90s. What happens? - Clean up:
argo cron delete every-minute -n argo
Lab 8: Retries and Exit Handlers
Goal: handle failure.
argo submit -n argo --watch yaml/08-retry-exit.yaml
argo get -n argo @latest
retryStrategy: limit, policy (Always,OnFailure,OnError), backoffonExittemplate always runs,workflow.statusis available in it
Try:
- Lower the retry limit to 1 until you get a failed workflow. Does the exit handler still run?
- Add
activeDeadlineSecondsto the template and a long sleep -
argo retry @latest -n argoon a failed workflow
Lab 9: Template Types
Goal: use each of the 7 template definition types. Files are in yaml/templates/.
Templates are either definitions (do work) or invocators (call other templates: steps and dag, labs 2/3).
kubectl apply -f yaml/templates/00-rbac.yaml # needed for resource + http
for f in yaml/templates/0[1-7]*.yaml; do argo submit -n argo --watch $f; done
| Type | What it does | File |
|---|---|---|
container | run one container | 01-container.yaml |
script | inline source, stdout in outputs.result | 02-script.yaml |
resource | create/patch/delete a k8s resource, no kubectl image | 03-resource.yaml |
suspend | pause until resumed or a duration passes | 04-suspend.yaml |
containerSet | multiple containers in one pod, with dependencies | 05-container-set.yaml |
http | HTTP request from the agent pod, no pod per step | 06-http.yaml |
data | source artifacts + transform with an expression | 07-data.yaml |
suspend(no duration):argo resume @latest -n argocontainerSetshares volumes, so no artifacts needed between containers. All containers in the set run in one podresourceandhttpneed RBAC for the SA (00-rbac.yaml), otherwise they fail with forbidden- (
pluginis an 8th, needs an executor plugin installed, skipped)
Try:
-
kubectl get cm -n argoafter the resource lab. Changeactiontodeleteand clean up - Count the pods for
05-container-setvs. the same thing as 3 separate steps - Make the http
successConditionfail (== 404) and look at the result - Add an
outputsto the http template and useresponse.body
Challenges
No solutions. Build these yourself:
- CI-like pipeline: clone > build > test > report, as a DAG, with the test step fanning out over 3 versions
- Use a shared volume (
volumeClaimTemplates) instead of artifacts to pass files between steps - Use
suspendto build a manual approval gate, resume withargo resume - Use a
resourcetemplate to create a k8s ConfigMap from a workflow - Create an ArgoCD
Applicationthat deploys aWorkflowTemplatefrom git (ties back to the earlier notes)
Cheatsheet
argo submit -n argo FILE [--watch] [-p k=v] [--from workflowtemplate/NAME]
argo list -n argo
argo get -n argo NAME|@latest
argo logs -n argo NAME|@latest [-f]
argo watch -n argo NAME|@latest
argo retry|stop|terminate|resubmit -n argo NAME
argo suspend|resume -n argo NAME
argo delete -n argo NAME | --all
argo template list|create|delete
argo cron list|create|suspend|resume|delete
argo lint FILE