Tekton is a Kubernetes-native CI/CD framework that models each stage of a pipeline as a custom resource, making pipelines portable, reproducible, and version-controlled alongside application code. On RHEL 8 with a running Kubernetes cluster, Tekton integrates directly with kubectl and requires no separate CI server to manage. This tutorial covers installing the Tekton Pipelines CRDs, writing a Task and Pipeline that build and test a container image, running a PipelineRun, deploying the Tekton Dashboard for visibility, and configuring Tekton Triggers to fire pipeline runs automatically on Git webhook events.
Prerequisites
- RHEL 8 server with a running Kubernetes cluster (kubeadm, k3s, or minikube) and
kubectlconfigured - At least 2 worker nodes with 2 vCPU and 4 GB RAM each
- A container registry reachable from the cluster (Docker Hub, Quay, or a local registry)
- Outbound internet access to pull Tekton release manifests from GitHub
Step 1 — Install Tekton Pipelines
Apply the Tekton Pipelines release manifest to your cluster. This installs the CRDs and the Tekton controller in the tekton-pipelines namespace.
# Install the latest stable Tekton Pipelines release
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
# Wait for the Tekton controller and webhook pods to become Ready
kubectl wait --for=condition=Ready pod
--selector=app.kubernetes.io/part-of=tekton-pipelines
-n tekton-pipelines
--timeout=120s
# Verify all Tekton pods are running
kubectl get pods -n tekton-pipelines
# List the installed CRDs
kubectl get crds | grep tekton
Step 2 — Write a Tekton Task
A Task is the basic unit of work in Tekton. Create a task that clones a Git repository and runs the project tests using a Python image.
kubectl apply -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: Task
metadata:
name: run-tests
namespace: default
spec:
params:
- name: repo-url
type: string
description: Git repository URL
- name: revision
type: string
default: main
workspaces:
- name: source
steps:
- name: clone
image: alpine/git:latest
script: |
git clone $(params.repo-url) /workspace/source
cd /workspace/source
git checkout $(params.revision)
- name: test
image: python:3.11-slim
workingDir: /workspace/source
script: |
pip install --quiet -r requirements.txt
python -m pytest tests/ -v
EOF
# Verify the task was created
kubectl get task run-tests
Step 3 — Write a Pipeline Chaining Multiple Tasks
A Pipeline orchestrates tasks and defines their execution order. Create a pipeline that clones the repo, runs tests, and then builds a container image with Kaniko.
kubectl apply -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
name: build-and-test
namespace: default
spec:
params:
- name: repo-url
type: string
- name: image-name
type: string
- name: revision
type: string
default: main
workspaces:
- name: shared-workspace
tasks:
- name: test
taskRef:
name: run-tests
params:
- name: repo-url
value: $(params.repo-url)
- name: revision
value: $(params.revision)
workspaces:
- name: source
workspace: shared-workspace
- name: build-image
runAfter: [test]
taskRef:
resolver: cluster
params:
- name: kind
value: task
- name: name
value: kaniko
- name: namespace
value: default
params:
- name: IMAGE
value: $(params.image-name)
workspaces:
- name: source
workspace: shared-workspace
EOF
kubectl get pipeline build-and-test
Step 4 — Create and Monitor a PipelineRun
A PipelineRun instantiates a pipeline with concrete parameter values and triggers execution. Use kubectl and the Tekton CLI (tkn) to monitor progress.
# Install the Tekton CLI (tkn) on RHEL 8
sudo dnf install -y https://github.com/tektoncd/cli/releases/download/v0.37.0/tektoncd-cli-0.37.0_Linux-64bit.rpm
# Create a PersistentVolumeClaim for the shared workspace
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pipeline-workspace-pvc
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 1Gi
EOF
# Trigger a PipelineRun
kubectl create -f - <<'EOF'
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: build-and-test-run-
namespace: default
spec:
pipelineRef:
name: build-and-test
params:
- name: repo-url
value: https://github.com/your-org/your-app.git
- name: image-name
value: docker.io/youruser/yourapp:latest
workspaces:
- name: shared-workspace
persistentVolumeClaim:
claimName: pipeline-workspace-pvc
EOF
# Follow the logs in real time
tkn pipelinerun logs --last -f
# List all PipelineRuns and their status
tkn pipelinerun list
Step 5 — Install the Tekton Dashboard
The Tekton Dashboard provides a browser-based UI for viewing task runs, pipeline runs, and logs without leaving your cluster.
# Install Tekton Dashboard (read-only mode)
kubectl apply -f https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
# Wait for the dashboard pod to become Ready
kubectl wait --for=condition=Ready pod
--selector=app=tekton-dashboard
-n tekton-pipelines
--timeout=90s
# Access the dashboard via port-forward
kubectl port-forward -n tekton-pipelines service/tekton-dashboard 9097:9097 &
echo "Tekton Dashboard: http://localhost:9097"
# Or expose via NodePort for remote access
kubectl patch service tekton-dashboard -n tekton-pipelines
-p '{"spec":{"type":"NodePort"}}'
kubectl get service tekton-dashboard -n tekton-pipelines
Step 6 — Configure Tekton Triggers for Webhook-Based Pipelines
Tekton Triggers lets you start a PipelineRun automatically when a Git push or pull-request event arrives, completing the CI loop without manual intervention.
# Install Tekton Triggers
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/release.yaml
kubectl apply -f https://storage.googleapis.com/tekton-releases/triggers/latest/interceptors.yaml
# Wait for triggers components
kubectl wait --for=condition=Ready pod
--selector=app.kubernetes.io/part-of=tekton-triggers
-n tekton-pipelines --timeout=120s
# Create a TriggerTemplate and EventListener
kubectl apply -f - <<'EOF'
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: pipeline-trigger-template
spec:
params:
- name: git-repo-url
- name: git-revision
resourcetemplates:
- apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
generateName: triggered-run-
spec:
pipelineRef:
name: build-and-test
params:
- name: repo-url
value: $(tt.params.git-repo-url)
- name: revision
value: $(tt.params.git-revision)
- name: image-name
value: docker.io/youruser/yourapp:$(tt.params.git-revision)
workspaces:
- name: shared-workspace
persistentVolumeClaim:
claimName: pipeline-workspace-pvc
---
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
name: github-listener
spec:
triggers:
- name: github-push
interceptors:
- ref:
name: github
params:
- name: eventTypes
value: [push]
bindings:
- ref: github-push-binding
template:
ref: pipeline-trigger-template
EOF
# Expose the EventListener so GitHub can reach it
kubectl expose service el-github-listener --type=NodePort --port=8080 --name=el-github-listener-external
kubectl get service el-github-listener-external
Conclusion
You now have a complete Tekton CI/CD pipeline running on Kubernetes on RHEL 8, with Tasks that clone and test code, a Pipeline that chains them with a Kaniko image build, and Tekton Triggers that fire PipelineRuns automatically on GitHub push events. The Tekton Dashboard gives your team real-time visibility into every run without needing access to kubectl. Because every Tekton resource is a Kubernetes custom resource, your entire pipeline definition lives in version-controlled YAML alongside your application code.
Next steps: Caching Dependencies in Tekton Pipelines for Faster Builds, Using Tekton Chains for Supply Chain Security on RHEL 8, and Migrating Jenkins Pipelines to Tekton.