---
title: "Tekton Pipelines: Cloud-Native CI/CD on Kubernetes with Tasks, Pipelines, and Triggers"
description: "Reference for Tekton CI/CD covering Tasks, TaskRuns, Pipelines, PipelineRuns, workspaces, results, triggers, catalog tasks, and Kubernetes-native pipeline execution with practical YAML examples."
url: https://agent-zone.ai/knowledge/cicd/tekton-pipelines/
section: knowledge
date: 2026-02-22
categories: ["cicd"]
tags: ["tekton","kubernetes","cicd","pipeline","cloud-native","tasks","triggers","catalog"]
skills: ["ci-pipeline-design","tekton-authoring","kubernetes-native-cicd"]
tools: ["tekton","kubectl","tkn","docker"]
levels: ["intermediate"]
word_count: 1299
formats:
  json: https://agent-zone.ai/knowledge/cicd/tekton-pipelines/index.json
  html: https://agent-zone.ai/knowledge/cicd/tekton-pipelines/?format=html
  api: https://api.agent-zone.ai/api/v1/knowledge/search?q=Tekton+Pipelines%3A+Cloud-Native+CI%2FCD+on+Kubernetes+with+Tasks%2C+Pipelines%2C+and+Triggers
---


# Tekton Pipelines

Tekton is a Kubernetes-native CI/CD framework. Every pipeline concept -- tasks, runs, triggers -- is a Kubernetes Custom Resource. Pipelines execute as pods. There is no central server, no UI-driven configuration, no special runtime. If you know Kubernetes, you know how to operate Tekton.

## Core Concepts

Tekton has four primary resources:

- **Task**: A sequence of steps that run in a single pod. Each step is a container.
- **TaskRun**: An instantiation of a Task with specific inputs. Creating a TaskRun executes the Task.
- **Pipeline**: An ordered collection of Tasks with dependencies, parameter passing, and conditional execution.
- **PipelineRun**: An instantiation of a Pipeline. Creating a PipelineRun executes the entire pipeline.

The separation between definition (Task/Pipeline) and execution (TaskRun/PipelineRun) means you define your CI/CD process once and trigger it many times with different inputs.

## Tasks

A Task defines what happens. Each step runs as a container in the same pod, sharing the pod's volumes and network:

```yaml
apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: build-go-app
spec:
  params:
    - name: package
      type: string
      description: Go package to build
    - name: output-binary
      type: string
      default: app
  workspaces:
    - name: source
      description: Source code checkout
  results:
    - name: binary-size
      description: Size of the compiled binary in bytes
  steps:
    - name: build
      image: golang:1.22
      workingDir: $(workspaces.source.path)
      script: |
        CGO_ENABLED=0 go build -o $(params.output-binary) $(params.package)
    - name: report-size
      image: alpine:3.19
      workingDir: $(workspaces.source.path)
      script: |
        SIZE=$(stat -c%s $(params.output-binary))
        echo "Binary size: $SIZE bytes"
        echo -n "$SIZE" > $(results.binary-size.path)
```

Key aspects of this Task:

- **params** are typed inputs. They support `string`, `array`, and `object` types. Default values are optional.
- **workspaces** are volume mounts shared across steps. The source code lives here.
- **results** are small outputs (max 4096 bytes) written to a file path that Tekton provides. Results can be consumed by subsequent Tasks in a Pipeline.
- **steps** execute sequentially within the pod. Each step is a container image. The `script` field replaces `command` and `args` when you need multi-line shell logic.

Steps share the pod filesystem. A file written in step 1 is visible in step 2 without any explicit passing mechanism, as long as both steps reference the same workspace or volume.

## TaskRuns

Execute a Task by creating a TaskRun:

```yaml
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: build-go-app-
spec:
  taskRef:
    name: build-go-app
  params:
    - name: package
      value: ./cmd/server
    - name: output-binary
      value: server
  workspaces:
    - name: source
      persistentVolumeClaim:
        claimName: my-source-pvc
```

`generateName` appends a random suffix, so each run gets a unique name. Workspaces bind to concrete storage: PersistentVolumeClaims, ConfigMaps, Secrets, or emptyDir volumes.

You can also embed a Task definition directly in a TaskRun using `taskSpec` instead of `taskRef`. This is useful for one-off tasks that do not merit a separate Task resource.

Check results after completion:

```bash
tkn taskrun describe build-go-app-abc12
# Or with kubectl:
kubectl get taskrun build-go-app-abc12 -o jsonpath='{.status.results}'
```

## Pipelines

A Pipeline chains Tasks together with dependency ordering, parameter passing, and result forwarding:

```yaml
apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: build-test-deploy
spec:
  params:
    - name: repo-url
      type: string
    - name: revision
      type: string
      default: main
    - name: image-name
      type: string
    - name: deploy-namespace
      type: string
      default: staging
  workspaces:
    - name: shared-workspace
    - name: docker-credentials
  tasks:
    - name: fetch-source
      taskRef:
        name: git-clone
      params:
        - name: url
          value: $(params.repo-url)
        - name: revision
          value: $(params.revision)
      workspaces:
        - name: output
          workspace: shared-workspace

    - name: run-tests
      taskRef:
        name: golang-test
      runAfter:
        - fetch-source
      params:
        - name: package
          value: ./...
      workspaces:
        - name: source
          workspace: shared-workspace

    - name: build-image
      taskRef:
        name: kaniko
      runAfter:
        - run-tests
      params:
        - name: IMAGE
          value: $(params.image-name):$(tasks.fetch-source.results.commit)
      workspaces:
        - name: source
          workspace: shared-workspace
        - name: dockerconfig
          workspace: docker-credentials

    - name: deploy
      taskRef:
        name: kubectl-apply
      runAfter:
        - build-image
      params:
        - name: namespace
          value: $(params.deploy-namespace)
        - name: image
          value: $(params.image-name):$(tasks.fetch-source.results.commit)
      workspaces:
        - name: manifest-dir
          workspace: shared-workspace
```

`runAfter` defines execution order. Tasks without `runAfter` dependencies on each other run in parallel. `$(tasks.fetch-source.results.commit)` references a result from a previous task, which also creates an implicit dependency.

## PipelineRuns

Trigger a Pipeline by creating a PipelineRun:

```yaml
apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: build-test-deploy-
spec:
  pipelineRef:
    name: build-test-deploy
  params:
    - name: repo-url
      value: https://github.com/myorg/myapp.git
    - name: revision
      value: main
    - name: image-name
      value: registry.example.com/myapp
    - name: deploy-namespace
      value: staging
  workspaces:
    - name: shared-workspace
      volumeClaimTemplate:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 1Gi
    - name: docker-credentials
      secret:
        secretName: docker-registry-credentials
```

`volumeClaimTemplate` creates a new PVC for each PipelineRun. This gives each run isolated storage and cleans up automatically when the PipelineRun is deleted. Use this instead of a shared PVC to avoid conflicts between concurrent runs.

## Workspace Backing Types

Workspaces support multiple storage backends: `volumeClaimTemplate` (dynamic PVC per run), `persistentVolumeClaim` (existing PVC for shared caches), `secret` (for credentials), `configMap` (for configuration), and `emptyDir` (for scratch space). Within a Pipeline, multiple Tasks can reference the same workspace. Tekton ensures correct ordering based on `runAfter` declarations.

## Triggers

Tekton Triggers connect external events (webhooks from GitHub, GitLab, or any HTTP source) to PipelineRuns:

```yaml
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: github-listener
spec:
  serviceAccountName: tekton-triggers-sa
  triggers:
    - name: github-push
      interceptors:
        - ref:
            name: github
          params:
            - name: secretRef
              value:
                secretName: github-webhook-secret
                secretKey: token
            - name: eventTypes
              value: ["push"]
      bindings:
        - ref: github-push-binding
      template:
        ref: build-test-deploy-template
---
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: github-push-binding
spec:
  params:
    - name: repo-url
      value: $(body.repository.clone_url)
    - name: revision
      value: $(body.head_commit.id)
---
apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: build-test-deploy-template
spec:
  params:
    - name: repo-url
    - name: revision
  resourcetemplates:
    - apiVersion: tekton.dev/v1
      kind: PipelineRun
      metadata:
        generateName: triggered-build-
      spec:
        pipelineRef:
          name: build-test-deploy
        params:
          - name: repo-url
            value: $(tt.params.repo-url)
          - name: revision
            value: $(tt.params.revision)
          - name: image-name
            value: registry.example.com/myapp
        workspaces:
          - name: shared-workspace
            volumeClaimTemplate:
              spec:
                accessModes: ["ReadWriteOnce"]
                resources:
                  requests:
                    storage: 1Gi
          - name: docker-credentials
            secret:
              secretName: docker-registry-credentials
```

The EventListener creates a Kubernetes Service and Deployment that receives webhooks. The interceptor validates the webhook signature. TriggerBinding extracts parameters from the webhook payload. TriggerTemplate creates the PipelineRun with those parameters.

## Tekton Hub and Catalog Tasks

The Tekton Catalog (`hub.tekton.dev`) provides pre-built Tasks for common operations. Install them with the `tkn` CLI:

```bash
# Install git-clone task
tkn hub install task git-clone

# Install kaniko (container builds without Docker daemon)
tkn hub install task kaniko

# Install kubectl-actions
tkn hub install task kubernetes-actions

# List installed tasks
tkn task list
```

Catalog tasks follow standard conventions for params and workspaces. The `git-clone` task expects a `url` param and an `output` workspace. The `kaniko` task expects an `IMAGE` param and `source` workspace. Reference the Tekton Hub page for each task to see the full parameter list.

Pin catalog tasks to specific versions in production. The Hub hosts multiple versions, and upgrading should be deliberate:

```bash
tkn hub install task git-clone --version 0.9
```

## When Blocks and Conditional Execution

Run Tasks conditionally based on previous results or parameters:

```yaml
tasks:
  - name: deploy-production
    taskRef:
      name: kubectl-apply
    when:
      - input: $(params.target-env)
        operator: in
        values: ["production"]
      - input: $(tasks.run-tests.results.pass)
        operator: in
        values: ["true"]
    runAfter:
      - build-image
```

All `when` conditions must be true for the Task to execute. If any condition fails, the Task is skipped (not failed), and the Pipeline continues.

## Common Mistakes

1. **Using a shared PVC for concurrent PipelineRuns.** Two runs writing to the same PVC corrupt each other. Use `volumeClaimTemplate` to get a fresh PVC per run.
2. **Putting too much logic in a single Task.** A Task runs in one pod. If it fails, the entire pod restarts from step 1. Break large workflows into multiple Tasks so failures are recoverable at a finer granularity.
3. **Ignoring result size limits.** Results are capped at 4096 bytes. Passing a large JSON blob as a result silently truncates it. Use workspaces for anything larger than a version string or commit hash.
4. **Not setting resource requests on steps.** Each step is a container. Without resource requests, the Kubernetes scheduler may place pipeline pods on undersized nodes, causing OOM kills or CPU throttling.
5. **Forgetting to create the ServiceAccount for Triggers.** The EventListener needs a ServiceAccount with permissions to create PipelineRuns. Without it, webhooks arrive successfully but nothing happens, and the only evidence is in the EventListener pod logs.

