How Tekton Orchestrates Cloud‑Native CI/CD Pipelines: A Deep Dive
This article explains Tekton’s core CRDs—Task, TaskRun, Pipeline, PipelineRun, PipelineResource, and Condition—how they are implemented on Kubernetes, how pipelines are built and executed, and how to manage secrets and service accounts for secure CI/CD workflows.
Understanding Tekton’s Core Concepts
Tekton is an open‑source cloud‑native CI/CD project that defines pipelines using Kubernetes Custom Resource Definitions (CRDs). The main CRDs are
Task,
TaskRun,
Pipeline,
PipelineRun,
PipelineResource, and
Condition.
Task : defines a build task composed of ordered steps, each executed in a container.
TaskRun : the actual execution of a
Task, creating a Pod with the required parameters.
Pipeline : a collection of
Tasks; the output of one can feed the input of the next.
PipelineRun : runs a
Pipelineby creating the corresponding
TaskRuns.
PipelineResource : defines external resources such as Git repositories or Docker images (deprecated in newer versions).
Condition : controls whether a
Taskruns based on a boolean check (also deprecated).
Tip : Both
PipelineResourceand
Conditionare deprecated but still appear in older Tekton versions.
The diagram shows that a pipeline consists of many tasks, each task contains multiple steps, and users can flexibly combine tasks to meet various requirements.
Implementation Details
After installing Tekton, two pods appear:
<code># kubectl get po -n tekton-pipelines
NAME READY STATUS RESTARTS AGE
tekton-pipelines-controller-xxxx 1/1 Running 0 2d22h
tekton-pipelines-webhook-xxxx 1/1 Running 0 2d22h</code>The controller pod runs the core logic. When it starts, it creates two controllers:
PipelineRunControllerand
TaskRunController. A simplified excerpt from
cmd/controller/main.goillustrates this:
<code>...
go func() {
log.Printf("Readiness and health check server listening on port %s", port)
log.Fatal(http.ListenAndServe(":"+port, mux))
}()
ctx = filteredinformerfactory.WithSelectors(ctx, v1beta1.ManagedByLabelKey)
sharedmain.MainWithConfig(ctx, ControllerLogKey, cfg,
taskrun.NewController(opts, clock.RealClock{}),
pipelinerun.NewController(opts, clock.RealClock{}),
)
...</code>The controllers are registered via
taskrun.NewControllerand
pipelinerun.NewController, and started with
sharedmain.MainWithConfigcalling
controller.StartAll.
PipelineRunControllerwatches
PipelineRunobjects, builds a directed acyclic graph (DAG) from the pipeline spec, and creates
TaskRuns for schedulable tasks. The logic lives in
pkg/reconciler/pipelinerun/pipelinerun.gounder the
reconcilemethod.
TaskRunControllerwatches
TaskRunobjects, converts each into a Pod (subject to
Conditionchecks), and lets Kubernetes schedule it. Its
reconcilemethod is in
pkg/reconciler/taskrun/taskrun.go.
OwnerReference links the objects: a
PipelineRunowns
TaskRuns, which own Pods; status changes propagate upward.
When a
TaskRunpod reaches the
Runningphase, the first step’s container is started by an
entrypointbinary. The binary runs only after Tekton injects annotations (via the Kubernetes Download API) as files into the step container, allowing the entrypoint to wait for previous steps to finish.
Overall Execution Flow
User creates a
PipelineRunresource.
PipelineRunControllerbuilds a DAG from the pipeline spec and creates
TaskRuns.
TaskRunControllerturns each
TaskRuninto a Pod (subject to
Condition).
The Pod runs each step defined in the task.
When the Pod completes, its status becomes
Completedand updates the
PipelineRunstatus.
PipelineResources (Deprecated)
Although deprecated,
PipelineResourceis still used in older versions to describe inputs such as Git URLs or Docker images. Example:
<code>apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
name: hello-world-resource
spec:
type: git
params:
- name: url
value: https://gitee.com/coolops/springboot-helloworld.git
</code>Tasks
A
Taskis a reusable template that can accept parameters, define resources, steps, workspaces, and results. Example task that builds a Maven project:
<code>apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: maven-build
spec:
resources:
inputs:
- name: repo
type: git
steps:
- name: build
image: maven:3.3-jdk-8
command:
- mvn
args:
- clean
- package
workingDir: /workspace/repo
</code>Task that builds and pushes a Docker image:
<code>apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-and-push-image
spec:
params:
- name: pathToDockerfile
type: string
default: /workspace/repo/Dockerfile
description: define Dockerfile path
- name: pathToContext
type: string
default: /workspace/repo
description: Docker build context
- name: imageRepo
type: string
default: registry.cn-hangzhou.aliyuncs.com
description: docker image repo
resources:
inputs:
- name: repo
type: git
outputs:
- name: builtImage
type: image
steps:
- name: build-image
image: docker:stable
script: |
#!/usr/bin/env sh
docker login $(params.imageRepo)
docker build -t $(resources.outputs.builtImage.url) -f $(params.pathToDockerfile) $(params.pathToContext)
docker push $(resources.outputs.builtImage.url)
volumeMounts:
- name: dockersock
mountPath: /var/run/docker.sock
volumes:
- name: dockersock
hostPath:
path: /var/run/docker.sock
</code>Steps can also specify a timeout:
<code>steps:
- name: sleep-then-timeout
image: ubuntu
script: |
#!/usr/bin/env bash
echo "I am supposed to sleep for 60 seconds!"
sleep 60
timeout: 5s
</code>TaskRuns
A
TaskRuninvokes a
Taskwith concrete parameters and resource bindings:
<code>apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: build-and-push-image
spec:
params:
- name: imageRepo
value: registry.cn-zhangjiakou.aliyuncs.com
taskRef:
name: build-and-push-image
resources:
inputs:
- name: repo
resourceRef:
name: hello-world-resource
outputs:
- name: builtImage
resourceRef:
name: hello-world-image
</code>Pipelines
A
Pipelineorchestrates multiple tasks. Example:
<code>apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: build-and-push-image
spec:
resources:
- name: repo
type: git
- name: builtImage
type: image
tasks:
- name: build-and-push-image
taskRef:
name: build-and-push-image
resources:
inputs:
- name: repo
resource: repo
outputs:
- name: builtImage
resource: builtImage
</code>Tasks can be ordered with
runAfteror linked via
from. Conditional execution uses
when(or the deprecated
condition).
<code>- name: test-app
taskRef:
name: make-test
resources:
inputs:
- name: workspace
resource: my-repo
- name: build-app
taskRef:
name: kaniko-build
runAfter:
- test-app
resources:
inputs:
- name: workspace
resource: my-repo
</code>PipelineRuns
A
PipelineRuntriggers a pipeline execution and binds resources. Example using
resourceSpec:
<code>apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: build-and-push-image
spec:
pipelineRef:
name: build-and-push-image
resources:
- name: repo
resourceSpec:
type: git
params:
- name: url
value: https://gitee.com/coolops/springboot-helloworld.git
- name: builtImage
resourceSpec:
type: image
params:
- name: url
value: registry.cn-hangzhou.aliyuncs.com/coolops/helloworld:latest
</code>Authentication Management
Tekton uses Kubernetes
Secrets referenced by a
ServiceAccountto provide credentials for Git and Docker registries. Each secret must carry a specific annotation, e.g.,
tekton.dev/git-0: https://github.comor
tekton.dev/docker-0: https://gcr.io. Supported secret types include
kubernetes.io/basic-auth,
kubernetes.io/ssh-auth, and
kubernetes.io/dockerconfigjson.
Example secret for Docker registry:
<code>apiVersion: v1
kind: Secret
metadata:
name: docker-registry-secret
annotations:
tekton.dev/docker-0: https://gcr.io
type: kubernetes.io/basic-auth
stringData:
username: <cleartext username>
password: <cleartext password>
</code>Corresponding ServiceAccount:
<code>apiVersion: v1
kind: ServiceAccount
metadata:
name: docker-registry-sa
secrets:
- name: docker-registry-secret
</code>Reference the ServiceAccount in a
PipelineRun:
<code>apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: demo-pipeline
namespace: default
spec:
serviceAccountName: docker-registry-sa
pipelineRef:
name: demo-pipeline
</code>When multiple accounts are needed, use
serviceAccountNamesto assign a specific ServiceAccount to each task:
<code>apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: demo-pipeline
namespace: default
spec:
serviceAccountNames:
- taskName: build-app
serviceAccountName: gitlab-sa
- taskName: push-image
serviceAccountName: docker-registry-sa
pipelineRef:
name: demo-pipeline
</code>References
1. https://www.infoq.cn/article/aRAYxTo19Bd6AVBmXFQz 2. https://cloudnative.to/blog/how-tekton-works/ 3. https://tekton.dev/
Ops Development Stories
Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.