Tekton and Argo CD are powerful tools for achieving GitOps, but integrating them can feel like trying to get two highly opinionated chefs to collaborate on a single dish.
Let’s see what a typical GitOps flow looks like when these two are working together. Imagine you’ve just pushed a change to your application’s Kubernetes manifest repository.
apiVersion: v1
kind: Pod
metadata:
name: my-app-pod
labels:
app: my-app
spec:
containers:
- name: my-app-container
image: my-registry/my-app:v1.2.0 # <-- This tag just changed
Argo CD, constantly watching this repository, detects the change. Its job is to reconcile the desired state in Git with the actual state in your cluster.
# Argo CD's sync status in the UI might show:
# Application: my-app-sync
# Sync Status: OutOfSync
# Health: Healthy
But Argo CD isn’t just blindly applying changes. It’s configured to trigger a Tekton pipeline for the deployment. This Tekton pipeline is where the actual build, test, and potentially advanced deployment strategies (like canary or blue/green) happen.
# Your Argo CD Application manifest might look like this:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app-sync
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/your-org/your-app-manifests.git
targetRevision: HEAD
path: path/to/your/app/config
destination:
server: https://kubernetes.default.svc
namespace: my-app-namespace
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
# This is the key part: telling Argo CD to use Tekton
hooks:
- name: trigger-tekton-pipeline
events:
- SyncFail
- Synced
# This Argo CD hook will trigger a Kubernetes Job that in turn starts a Tekton PipelineRun
# You'll typically define this Job in your application's manifest repository
hookType: PostSync
sync:
resource: |
apiVersion: batch/v1
kind: Job
metadata:
name: trigger-tekton-deployment
spec:
template:
spec:
containers:
- name: trigger
image: bitnami/kubectl:latest # Or any image with kubectl
command: ["/bin/sh", "-c"]
args:
- |
set -e
echo "Triggering Tekton PipelineRun for deployment..."
# This kubectl command creates a PipelineRun that Tekton will pick up
kubectl apply -f - <<EOF
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: my-app-deploy-$(date +%Y%m%d%H%M%S)
namespace: tekton-pipelines # Your Tekton namespace
labels:
app: my-app
git-commit: $(GIT_COMMIT_SHA) # Assuming you can get this from Argo CD context
spec:
pipelineRef:
name: build-and-deploy-pipeline # The name of your Tekton pipeline
params:
- name: image-tag
value: "v1.2.0" # This would ideally be dynamic
workspaces:
- name: shared-data
volumeClaimTemplate:
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
restartPolicy: Never
backoffLimit: 4
The PostSync hook in Argo CD is crucial. When Argo CD successfully syncs your application’s manifests (or even if it fails, depending on your events configuration), it can trigger a Kubernetes Job. This Job then uses kubectl to create a PipelineRun in your Tekton namespace.
The Tekton PipelineRun is what kicks off your actual CI/CD process. It references a Pipeline that you’ve defined in Tekton. This Pipeline is a directed acyclic graph (DAG) of Tasks. Each Task performs a specific action, like checking out code, building a Docker image, running tests, or deploying to Kubernetes.
# Example Tekton Pipeline
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: build-and-deploy-pipeline
spec:
params:
- name: image-tag
description: The tag for the Docker image
type: string
tasks:
- name: clone-repo
taskRef:
name: git-clone
params:
- name: url
value: "https://github.com/your-org/your-app.git"
- name: revision
value: "main" # Or a specific commit SHA passed from Argo CD
workspaces:
- name: output
workspace: shared-data
- name: build-image
runAfter:
- clone-repo
taskRef:
name: buildah-build
params:
- name: IMAGE
value: "my-registry/my-app:$(params.image-tag)"
workspaces:
- name: source
workspace: shared-data
- name: deploy-app
runAfter:
- build-image
taskRef:
name: kubernetes-deploy
params:
- name: manifest-path
value: "path/to/your/app/config/deployment.yaml"
- name: image-tag
value: "$(params.image-tag)"
workspaces:
- name: manifest
workspace: shared-data
Here, the build-and-deploy-pipeline has three tasks: clone-repo (using a standard git-clone task), build-image (using a buildah-build task), and deploy-app (using a kubernetes-deploy task). Notice how runAfter ensures tasks execute in sequence, and workspaces (shared-data) allow data to be passed between them.
The deploy-app task would typically use kubectl apply or a similar tool to update your Kubernetes deployment with the new image tag. This is where Tekton directly interacts with your cluster to perform the deployment actions that Argo CD orchestrated.
The magic is in the interplay: Argo CD ensures your desired state in Git is reflected in the cluster, and it uses Tekton to perform the complex actions needed to get there. Tekton handles the how of the deployment (build, test, deploy), while Argo CD handles the what and when (syncing Git to cluster state).
When you configure Tekton tasks, you’re defining the exact commands and container images that execute your build and deploy logic. For instance, a buildah-build task might use buildah bud --tag $(params.IMAGE) $(workspaces.source.path) to build your container image. Similarly, a kubernetes-deploy task could use kubectl set image deployment/<your-deployment-name> <your-container-name>=$(params.IMAGE) -n <your-namespace> to update your deployment.
The key challenge and a common point of confusion is how to pass dynamic information, like the specific Git commit SHA or the image tag that Argo CD just synced, into your Tekton PipelineRun. The Job triggered by the Argo CD PostSync hook needs to inject this context. You might parse Argo CD’s internal state or use environment variables exposed to the Job to populate the PipelineRun’s params. For example, if your Application manifest has a way to expose the targetRevision to the Job’s environment, you could use that to set the revision parameter in the Tekton PipelineRun.
The next hurdle you’ll likely encounter is managing complex deployment strategies like blue/green or canary releases within your Tekton pipelines, which requires careful orchestration of Kubernetes resources and traffic management.