Argo Workflows is a workflow orchestrator on Kubernetes, where job specifications are implemented as Kubernetes CRDs. It benefits from the power of Kubernetes to run parallel tasks in containers.
Argo Workflows is composed of two main components:
Argo Workflows offers the following CRDs:
GitHub webhooks can be integrated with Argo Workflows with the architecture below.
In this scenario, after a GitHub event is triggered:
Argo Workflows can be installed using Helm (see Argo Workflows Helm Chart).
For a minimal installation that will work with GitHub webhooks we can use the following Helm values:
workflow:
# create the default service account for workflows (with no rights)
serviceAccount:
create: true
controller:
workflowDefaults:
spec:
# associate a default service account to workflows
serviceAccountName: argo-workflow
# namespaces where the controller look for workflows
workflowNamespaces: ["workflows"]
workflowRestrictions:
# only processes Workflows using workflowTemplateRef, to prevent arbitrary worklow creation
templateReferencing: Secure
server:
authModes:
# required to authorize webhook events
- client
ingress:
enabled: true
# ✏️ configure your own ingress here
hosts: argo.xxx.com
Once the Workflows controller and the Argo server are installed, the next step is to manage permissions on the tool. Permissions in Argo server rely on the principle that all identities (users, external services, etc…) must eventually be mapped to a service account.
The rights this service account has on Kubernetes objects (expressed as Kubernetes RBAC) represent the permissions that mapped identities have.
External services can call the Argo server events API to trigger workflows in response to external events. They authenticate to the Argo server by passing the token of the service account they are bound to as a Bearer token in the Authorization header.
Unfortunately, some services like GitHub don’t allow to customize headers when sending webhooks. For these particular services, the permissions system is different and relies on a secret that defines the mapping between secrets used to sign webhooks and service accounts.
Therefore, in GitHub’s case, we need to:
1. Create a new service account for the service and a secret holding its token.
apiVersion: v1
kind: ServiceAccount
metadata:
name: github-webhook
namespace: workflows
annotations:
# Tells to the Argo Server which secret holds this service account's token
workflows.argoproj.io/service-account-token.name: github-webhook
---
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: github-webhook
annotations:
kubernetes.io/service-account.name: github-webhook
2. Create the necessary Kubernetes RBAC resources granting permissions to the service on Argo Workflows resources. In our case, we only require our ServiceAccount to be able to submit workflows.
# minimum role to submit Workflows from WorkflowTemplates
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: submit-workflow-template
namespace: workflows
rules:
- apiGroups: ["argoproj.io"]
resources: ["workfloweventbindings"]
verbs: ["list"]
- apiGroups: ["argoproj.io"]
resources: ["workflowtemplates"]
verbs: ["get"]
- apiGroups: ["argoproj.io"]
resources: ["workflows"]
verbs: ["create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: github-webhook
namespace: workflows
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: submit-workflow-template
subjects:
- kind: ServiceAccount
name: github-webhook
namespace: workflows
3. Finally, we need to tell ArgoCD which secrets hold the credentials for our GitHub webhook, as well as the necessary information to check the webhook signature. We can do this by creating the following argo-workflows-webhook-clients
secret
apiVersion: v1
kind: Secret
metadata:
# ⚠️ The Argo Server will specifically look for this secret
# Do not change its name!
name: argo-workflows-webhook-clients
namespace: workflows
stringData:
# The key in the secret must match the name of the service account we want to bind to this webhook
# The secret holds the credentials that are used for the signature of the webhook. The Argo Server also uses this signature to determine which secret key to look for.
github-webhook: |
type: github
secret: "MyV3rYS3cr€t"
The final step is to create the Workflow that will run our job and bind it to the GitHub webhook.
For that, we create a workflow WorkflowTemplate that will be reused by our WorkflowEventBinding for convenience. This template uses parameters that will be filled by the WorkflowEventBinding.
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: hello-world
spec:
entrypoint: whalesay
ttlStrategy:
# delete the workflow 1 week after it has been created if it failed
secondsAfterFailure: 604800
# delete the workflow 1 day after it has been created if it succeded
secondsAfterSuccess: 86400
templates:
- name: whalesay
inputs:
parameters:
- name: git_url
# this value will be filled by the WorkflowEventBinding
value: ""
- name: git_ref
# this value will be filled by the WorkflowEventBinding
value: ""
- name: head_commit
# this value will be filled by the WorkflowEventBinding
value: ""
container:
image: docker/whalesay
command: [cowsay]
args:
# input parameters are injected into the args of the job pod
- "hello world from /#"
Then, we can create our WorkflowEventBinding to trigger a job using the above template when an event is received:
apiVersion: argoproj.io/v1alpha1
kind: WorkflowEventBinding
metadata:
name: github-push-webhook
spec:
event:
# This selector matches github push event webhooks targeting the "hello-world" event
selector: discriminator == "hello-world" && metadata["x-github-event"] == ["push"]
submit:
workflowTemplateRef:
name: hello-world
arguments:
parameters:
- name: git_url
valueFrom:
event: payload.repository.clone_url
- name: git_ref
valueFrom:
event: payload.ref
- name: head_commit
valueFrom:
# expression can be used to retrieve information from the json payload that is sent
event: 'len(payload.commits) > 0 ? payload.commits[len(payload.commits) - 1].id : "null"'
That’s it, we can try to push a commit to a repository covered by the webhook to test the whole machinery!
GitHub recently added Rulesets to GitHub, that allow defining how people can interact with branches and tags in repositories. At the organization level, it can be used to enforce that specific workflows must pass before a pull request can be merged. However, Rulesets have several limitations compared to Argo Workflows.
Advantages
Drawbacks
Advantages
Drawbacks
pull_request
, pull_request_target
and merge_group
eventsArgo Workflows make it possible to go beyond the limits of GitHub Rulesets, to run workflows at the scale of an organization. However, it requires the management of a dedicated tool, and to write tasks with a different syntax to that of GitHub workflows.
It is especially interesting when you also want to use it for other use cases, for example, to enable users to run on-demand workflows with a user-friendly interface.