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 kubectl configured
  • 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.