All Articles

How to Set Up Tekton Pipelines on Kubernetes from Scratch in 2026

Step-by-step guide to installing Tekton on Kubernetes and building your first CI/CD pipeline — Tasks, Pipelines, Triggers, and Dashboard with practical examples.

DevOpsBoysMar 25, 20266 min read
Share:Tweet

Tekton is a Kubernetes-native CI/CD framework. Unlike Jenkins or GitHub Actions, Tekton runs pipelines as Kubernetes pods — every task is a container, every pipeline is a set of Kubernetes resources. No external CI server, no shared runners, no vendor lock-in.

Here is how to set it up from zero and build a real CI/CD pipeline.

What You Will Build

By the end of this guide, you will have:

  • Tekton Pipelines installed on your cluster
  • A Task that clones a Git repo and runs tests
  • A Pipeline that builds a Docker image and pushes it to a registry
  • Tekton Triggers to auto-run pipelines on Git push
  • Tekton Dashboard for a visual overview

Prerequisites

  • A Kubernetes cluster (1.27+) — DigitalOcean's DOKS or any managed cluster works
  • kubectl configured and connected
  • A container registry (Docker Hub, GHCR, or your private registry)

Step 1: Install Tekton Pipelines

bash
# Install the latest Tekton Pipelines release
kubectl apply --filename https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml
 
# Verify the installation
kubectl get pods -n tekton-pipelines --watch

Wait until all pods are Running:

NAME                                           READY   STATUS
tekton-pipelines-controller-7b8d7b5c5f-x9k2l  1/1     Running
tekton-pipelines-webhook-6c4f7b8d9-m3n7j       1/1     Running

Step 2: Install the Tekton CLI

The tkn CLI makes it easy to interact with Tekton resources:

bash
# macOS
brew install tektoncd-cli
 
# Linux
curl -LO https://github.com/tektoncd/cli/releases/latest/download/tkn_Linux_x86_64.tar.gz
tar xvzf tkn_Linux_x86_64.tar.gz -C /usr/local/bin tkn
 
# Verify
tkn version

Step 3: Create Your First Task

A Task is the smallest unit of work in Tekton — it runs one or more steps in a pod:

yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: hello-world
spec:
  steps:
    - name: say-hello
      image: alpine:3.19
      script: |
        echo "Hello from Tekton!"
        echo "Running on Kubernetes as a pod"
        date

Apply and run it:

bash
kubectl apply -f hello-task.yaml
 
# Create a TaskRun to execute it
tkn task start hello-world --showlog

You should see the output directly in your terminal. Every TaskRun creates a pod — you can inspect it with kubectl get pods.

Step 4: Clone and Test a Repository

Now build a useful Task that clones a Git repo and runs tests:

yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: clone-and-test
spec:
  params:
    - name: repo-url
      type: string
      description: Git repository URL
    - name: branch
      type: string
      default: main
  workspaces:
    - name: source
      description: Workspace to clone the repo into
  steps:
    - name: clone
      image: alpine/git:2.43.0
      script: |
        git clone -b $(params.branch) $(params.repo-url) $(workspaces.source.path)/repo
        cd $(workspaces.source.path)/repo
        echo "Cloned $(git rev-parse --short HEAD)"
 
    - name: test
      image: node:20-alpine
      workingDir: $(workspaces.source.path)/repo
      script: |
        npm ci
        npm test

Steps run sequentially in the same pod, sharing the workspace volume.

Step 5: Build a Complete Pipeline

A Pipeline chains multiple Tasks together. Here is a full CI/CD pipeline:

yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: build-and-push
spec:
  params:
    - name: repo-url
      type: string
    - name: image-name
      type: string
    - name: image-tag
      type: string
      default: latest
  workspaces:
    - name: shared-workspace
    - name: docker-credentials
 
  tasks:
    - name: fetch-source
      taskRef:
        name: git-clone
        kind: ClusterTask
      workspaces:
        - name: output
          workspace: shared-workspace
      params:
        - name: url
          value: $(params.repo-url)
 
    - name: run-tests
      runAfter: ["fetch-source"]
      taskRef:
        name: run-tests
      workspaces:
        - name: source
          workspace: shared-workspace
 
    - name: build-and-push
      runAfter: ["run-tests"]
      taskRef:
        name: kaniko-build
      workspaces:
        - name: source
          workspace: shared-workspace
        - name: dockerconfig
          workspace: docker-credentials
      params:
        - name: IMAGE
          value: $(params.image-name):$(params.image-tag)

Create the supporting Tasks:

yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: run-tests
spec:
  workspaces:
    - name: source
  steps:
    - name: test
      image: node:20-alpine
      workingDir: $(workspaces.source.path)
      script: |
        if [ -f package.json ]; then
          npm ci
          npm test
        elif [ -f requirements.txt ]; then
          pip install -r requirements.txt
          pytest
        elif [ -f go.mod ]; then
          go test ./...
        fi
---
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: kaniko-build
spec:
  params:
    - name: IMAGE
      type: string
  workspaces:
    - name: source
    - name: dockerconfig
  steps:
    - name: build-and-push
      image: gcr.io/kaniko-project/executor:latest
      args:
        - --dockerfile=$(workspaces.source.path)/Dockerfile
        - --destination=$(params.IMAGE)
        - --context=$(workspaces.source.path)
        - --cache=true
      env:
        - name: DOCKER_CONFIG
          value: $(workspaces.dockerconfig.path)

Step 6: Run the Pipeline

First, create the registry credentials secret:

bash
kubectl create secret docker-registry docker-creds \
  --docker-server=ghcr.io \
  --docker-username=YOUR_USERNAME \
  --docker-password=YOUR_TOKEN

Now run the pipeline:

yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: build-and-push-run-
spec:
  pipelineRef:
    name: build-and-push
  params:
    - name: repo-url
      value: https://github.com/your-org/your-app.git
    - name: image-name
      value: ghcr.io/your-org/your-app
    - name: image-tag
      value: v1.0.0
  workspaces:
    - name: shared-workspace
      volumeClaimTemplate:
        spec:
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 1Gi
    - name: docker-credentials
      secret:
        secretName: docker-creds
bash
kubectl create -f pipeline-run.yaml
 
# Watch the progress
tkn pipelinerun list
tkn pipelinerun logs build-and-push-run-xxxxx -f

Step 7: Set Up Triggers (Auto-Run on Git Push)

Install Tekton Triggers:

bash
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

Create a TriggerTemplate and EventListener:

yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: build-trigger-template
spec:
  params:
    - name: git-repo-url
    - name: git-revision
  resourcetemplates:
    - apiVersion: tekton.dev/v1
      kind: PipelineRun
      metadata:
        generateName: triggered-build-
      spec:
        pipelineRef:
          name: build-and-push
        params:
          - name: repo-url
            value: $(tt.params.git-repo-url)
          - name: image-tag
            value: $(tt.params.git-revision)
          - name: image-name
            value: ghcr.io/your-org/your-app
        workspaces:
          - name: shared-workspace
            volumeClaimTemplate:
              spec:
                accessModes: ["ReadWriteOnce"]
                resources:
                  requests:
                    storage: 1Gi
          - name: docker-credentials
            secret:
              secretName: docker-creds
---
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: github-push-binding
spec:
  params:
    - name: git-repo-url
      value: $(body.repository.clone_url)
    - name: git-revision
      value: $(body.after)
---
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: github-listener
spec:
  serviceAccountName: tekton-triggers-sa
  triggers:
    - name: github-push
      bindings:
        - ref: github-push-binding
      template:
        ref: build-trigger-template

Expose the EventListener and configure a GitHub webhook to send push events to it.

bash
# Check the EventListener service
kubectl get svc el-github-listener
 
# Expose it (in production, use an Ingress)
kubectl port-forward svc/el-github-listener 8080

Step 8: Install the Dashboard

bash
kubectl apply --filename https://storage.googleapis.com/tekton-releases/dashboard/latest/release.yaml
 
# Access it
kubectl port-forward -n tekton-pipelines svc/tekton-dashboard 9097:9097

Open http://localhost:9097 to see all your PipelineRuns, TaskRuns, and logs in a web UI.

Production Tips

1. Use resource limits on Tasks. Tekton creates pods for every TaskRun. Without limits, a misbehaving step can consume all node resources:

yaml
steps:
  - name: build
    image: node:20-alpine
    resources:
      requests:
        cpu: 500m
        memory: 512Mi
      limits:
        cpu: "2"
        memory: 2Gi

2. Enable pipeline-level timeouts. Prevent stuck pipelines from running forever:

yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
spec:
  timeouts:
    pipeline: 1h
    tasks: 30m

3. Use finally tasks for cleanup. Run cleanup steps regardless of pipeline success or failure:

yaml
spec:
  tasks:
    - name: build
      # ...
  finally:
    - name: cleanup
      taskRef:
        name: cleanup-workspace
    - name: notify
      taskRef:
        name: slack-notify

4. Cache build layers. Use Kaniko's --cache=true flag and a persistent volume to cache Docker layers between builds.

5. Set up RBAC. Create dedicated ServiceAccounts for pipelines with minimal permissions:

bash
kubectl create sa tekton-pipeline-sa
kubectl create rolebinding tekton-pipeline-rb \
  --clusterrole=edit \
  --serviceaccount=default:tekton-pipeline-sa

Tekton vs Other CI/CD Tools

FeatureTektonGitHub ActionsJenkinsArgo Workflows
Runs onKubernetes nativeGitHub hostedSelf-hosted serverKubernetes native
ConfigurationYAML CRDsYAML filesGroovy/YAMLYAML CRDs
ScalingK8s pod scalingGitHub managesManual agentsK8s pod scaling
Vendor lock-inNoneGitHubNoneNone
Learning curveSteepLowMediumMedium
Event triggersBuilt-inBuilt-inPluginsSeparate (Argo Events)

Tekton's strength is its Kubernetes-native design — if you are already running everything on Kubernetes, your CI/CD should run there too.

For comprehensive CI/CD and Kubernetes learning, the hands-on courses at KodeKloud cover pipeline design, Tekton, and GitOps patterns. And if you need a cluster to set up Tekton, DigitalOcean's managed Kubernetes gives you a production-ready environment in minutes.

Wrapping Up

Tekton gives you full control over your CI/CD pipeline using Kubernetes primitives. Every task is a pod, every pipeline is a set of CRDs, and everything is managed by the same tools you use for your applications.

The learning curve is steeper than GitHub Actions, but the payoff is complete portability and no vendor lock-in. If your infrastructure is on Kubernetes, Tekton is the CI/CD system that fits naturally.

Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments