Skip to content

Tekton CI/CD Pipeline

Build a real-world CI/CD pipeline that tests, builds, and deploys an application.

Time: ~20 minutes Difficulty: Advanced

  • A multi-stage pipeline: prepare source, test, build image, deploy
  • Kaniko: build container images without a Docker daemon
  • Inline task specs vs reusable Task references
  • Tekton Triggers: EventListener, TriggerTemplate, TriggerBinding
  • RBAC for pipeline service accounts
  • How Tekton and ArgoCD complement each other
  • Tekton Pipelines must be installed (from demo 30)
  • If not installed:
    Terminal window
    kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml

Navigate to the demo directory:

Terminal window
cd demos/tekton-cicd
Terminal window
kubectl apply -f manifests/namespace.yaml
kubectl apply -f manifests/rbac.yaml
Terminal window
kubectl apply -f manifests/sample-app.yaml
kubectl apply -f manifests/task-test.yaml
kubectl apply -f manifests/task-build.yaml
kubectl apply -f manifests/task-deploy.yaml
kubectl apply -f manifests/pipeline-cicd.yaml
Terminal window
kubectl create -f manifests/pipelinerun-cicd.yaml
Terminal window
# Watch pods spin up for each stage
kubectl get pods -n tekton-cicd-demo -w

In another terminal, follow the logs:

Terminal window
# Get the PipelineRun name
PR=$(kubectl get pipelineruns -n tekton-cicd-demo -o name | tail -1)
# Follow logs from all tasks
kubectl logs -n tekton-cicd-demo $PR --all-containers --prefix -f

Or use the Tekton Dashboard (if installed from demo 30):

Terminal window
kubectl port-forward svc/tekton-dashboard -n tekton-pipelines 9097:9097

Open http://localhost:9097 and navigate to PipelineRuns.

The build-and-deploy pipeline runs four stages in sequence:

prepare-source ──> test ──> build ──> deploy
StageWhat It Does
prepare-sourceFetches app source from a ConfigMap into the shared workspace
testValidates HTML structure and nginx config. Fails the pipeline if tests fail.
buildCreates a Dockerfile and builds the image with Kaniko (no Docker daemon)
deployCreates a Deployment and Service in the cluster using kubectl

After the pipeline completes:

Terminal window
kubectl get pods -l app=demo-app -n tekton-cicd-demo
kubectl port-forward svc/demo-app 8080:80 -n tekton-cicd-demo

Open http://localhost:8080. You should see “Built by Tekton”.

Triggers let external events (like a git push) start pipeline runs automatically.

Terminal window
kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
kubectl apply --filename https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
Terminal window
kubectl apply -f manifests/trigger.yaml
Terminal window
# The EventListener creates a Service
kubectl get svc -n tekton-cicd-demo -l eventlistener=github-listener
# Port-forward to it
kubectl port-forward svc/el-github-listener 8090:8080 -n tekton-cicd-demo &
# Simulate a webhook (sends a POST request)
curl -X POST http://localhost:8090 \
-H "Content-Type: application/json" \
-d '{"ref": "refs/heads/main"}'
# A new PipelineRun should be created
kubectl get pipelineruns -n tekton-cicd-demo

In production, you would configure a GitHub webhook to POST to the EventListener’s external URL.

manifests/
namespace.yaml # tekton-cicd-demo namespace
rbac.yaml # ServiceAccount + Role for deploying
sample-app.yaml # ConfigMap with app source (index.html, nginx.conf)
task-test.yaml # Validates HTML and nginx config
task-build.yaml # Builds container image with Kaniko
task-deploy.yaml # Deploys to K8s with kubectl
pipeline-cicd.yaml # Chains all tasks into a pipeline
pipelinerun-cicd.yaml # Runs the pipeline
trigger.yaml # EventListener + TriggerTemplate + TriggerBinding

Tekton + ArgoCD: the full GitOps picture

Developer pushes code
|
v
Tekton (CI): test ──> build ──> push image
|
v
ArgoCD (CD): detects new image ──> syncs to cluster

Tekton handles the build side (CI). ArgoCD handles the deploy side (CD). Together they form a complete GitOps pipeline where Git is the single source of truth.

  1. Break the tests and watch the pipeline fail:

    Terminal window
    kubectl patch configmap sample-app-source -n tekton-cicd-demo \
    --type=merge -p '{"data":{"index.html":"not html"}}'
    kubectl create -f manifests/pipelinerun-cicd.yaml
    # The test stage will fail, build and deploy will be skipped
  2. Fix the tests and re-run:

    Terminal window
    kubectl patch configmap sample-app-source -n tekton-cicd-demo \
    --type=merge -p '{"data":{"index.html":"<html><body><h1>Fixed!</h1></body></html>"}}'
    kubectl create -f manifests/pipelinerun-cicd.yaml
  3. List all pipeline runs with status:

    Terminal window
    kubectl get pipelineruns -n tekton-cicd-demo \
    -o custom-columns='NAME:.metadata.name,STATUS:.status.conditions[0].reason,STARTED:.status.startTime'
Terminal window
kubectl delete namespace tekton-cicd-demo
# Remove Tekton if done with both demos
kubectl delete -f https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml 2>/dev/null
kubectl delete -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml 2>/dev/null
kubectl delete -f https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml 2>/dev/null
kubectl delete -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml 2>/dev/null

See docs/deep-dive.md for a detailed explanation of Tekton Triggers interceptors, CEL filtering, pipeline-as-code, Tekton Chains for supply chain security, and comparison with GitHub Actions and Jenkins.

Move on to Microservices Platform to deploy a real-world multi-tier application.