Argo Workflows doesn’t just run containers; it orchestrates them, and Container Templates are the fundamental building blocks of that orchestration.
Imagine you’re building a complex machine with LEGOs. Each LEGO brick is a Container Template. You can have bricks for "build a wall," "attach a wheel," or "add a laser." In Argo, a Container Template defines a single container to be run as part of a workflow. It specifies the container image, command, arguments, environment variables, resource requests/limits, and other container-specific settings.
Here’s a basic Container Template defined in YAML:
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: simple-container-template
spec:
templates:
- name: hello-world
container:
image: alpine:latest
command: ["echo"]
args: ["Hello, Argo Workflows!"]
When this hello-world template is executed within an Argo Workflow, it will pull the alpine:latest Docker image, run the echo command with the argument "Hello, Argo Workflows!", and print the output. This is the simplest form of a task within Argo.
But Container Templates are more than just running a single command. They are the atomic units that get combined into larger, more complex workflows. You can chain them together, run them in parallel, or make decisions based on their outputs.
Let’s see how this looks in a real workflow. This workflow uses the hello-world template defined above:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: my-hello-workflow
spec:
entrypoint: hello-world # This points to the template name
templates:
- name: hello-world
container:
image: alpine:latest
command: ["echo"]
args: ["Hello, Argo Workflows!"]
When you submit this my-hello-workflow, Argo Workflows will execute the hello-world template. The output will be visible in the Argo UI or via argo logs my-hello-workflow.
The power comes when you start connecting these. You can define multiple Container Templates and specify how they depend on each other.
Consider a workflow with two steps: first, print "Hello," and second, print "World!":
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: chained-hello-world
spec:
entrypoint: main
templates:
- name: say-hello
container:
image: alpine:latest
command: ["echo"]
args: ["Hello,"]
- name: say-world
container:
image: alpine:latest
command: ["echo"]
args: ["World!"]
- name: main
steps:
- - name: hello-step
template: say-hello
- name: world-step
template: say-world
In this example, the main template defines a sequence of steps. The hello-step runs the say-hello template, and then world-step runs the say-world template. Notice how steps is used to define a DAG (Directed Acyclic Graph) of tasks. Even though they are defined sequentially in the YAML, Argo will execute them as independent tasks within the main template’s steps.
What’s often overlooked is how Container Templates can be parameterized. This means you can pass dynamic values into your templates when you run a workflow. This makes your templates reusable and adaptable.
Let’s modify the hello-world template to accept a name as a parameter:
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: parameterized-hello
spec:
templates:
- name: greet
inputs:
parameters:
- name: name # Define an input parameter named 'name'
container:
image: alpine:latest
command: ["echo"]
args: ["Hello, {{inputs.parameters.name}}!"] # Use the parameter here
Now, when you create a Workflow that uses this parameterized-hello template, you can provide a value for name:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
name: custom-greeting
spec:
entrypoint: greet # This refers to the 'greet' template within the WorkflowTemplate
templates:
- name: greet # This template definition comes from the WorkflowTemplate
inputs:
parameters:
- name: name
container:
image: alpine:latest
command: ["echo"]
args: ["Hello, {{inputs.parameters.name}}!"]
arguments:
parameters:
- name: name
value: "Argo User"
Here, the arguments section of the Workflow passes "Argo User" to the name parameter of the greet template. The output will be "Hello, Argo User!". This ability to parameterize Container Templates is crucial for building flexible and dynamic workflows.
You can also define environment variables within a Container Template, which are often used to pass configuration or secrets to your application running inside the container. For example:
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: env-var-example
spec:
templates:
- name: process-data
container:
image: ubuntu:latest
command: ["bash", "-c"]
args: ["echo $MY_MESSAGE; echo $ANOTHER_VAR"]
env:
- name: MY_MESSAGE # Define an environment variable
value: "This is a message from the workflow!"
- name: ANOTHER_VAR # Another environment variable
value: "42"
This template will execute a bash script that prints the values of two environment variables, MY_MESSAGE and ANOTHER_VAR, which are defined directly within the Container Template.
The system is designed to be extensible. While Container Templates are the most common, Argo Workflows also supports other template types like Script templates (for running inline scripts without a separate container image), Resource templates (for managing Kubernetes resources), and DAG templates (for complex dependency graphs). However, the container template is the bedrock, the fundamental unit of execution.
When you’re defining resource requests and limits for your containers, these are also specified within the container block of a Container Template. This ensures that your workflow tasks get the CPU and memory they need and don’t consume more than allocated, preventing noisy neighbor issues.
container:
image: busybox
command: ["sh", "-c", "sleep 10"]
resources:
requests:
cpu: "100m" # Request 100 millicores of CPU
memory: "128Mi" # Request 128 MiB of memory
limits:
cpu: "200m" # Limit to 200 millicores of CPU
memory: "256Mi" # Limit to 256 MiB of memory
These resource specifications are vital for stable, predictable execution, especially in shared cluster environments.
Ultimately, Container Templates are the discrete, executable units that Argo Workflows stitches together to form powerful, automated pipelines. Their ability to be parameterized, configured with environment variables, and managed with resource constraints makes them incredibly versatile.
The next logical step after mastering Container Templates is to explore how to combine them into more complex workflow structures like DAGs and Step-based workflows.