Build Your First Tekton CI/CD Pipeline: A Step‑by‑Step Guide
This tutorial walks you through creating a complete Tekton pipeline—from installing the git‑clone task and defining unit‑test, build‑push, and deployment tasks, to assembling them into a Pipeline, configuring secrets, and running a PipelineRun that uses commit IDs as image tags—complete with all necessary YAML and command examples.
In the previous article we installed Tekton and covered its theory; now we will practice by building our first pipeline.
The overall pipeline flow is simple and consists of four main tasks.
We use the
git-clonetask from Tekton Hub to pull the source code. It can be installed via
kubectlor the
tknclient.
<code>kubectl apply -f https://raw.githubusercontent.com/tektoncd/catalog/main/task/git-clone/0.5/git-clone.yaml</code> <code>tkn hub install task git-clone</code>After installation, verify the task:
<code># tkn hub install task git-clone
Task git-clone(0.5) installed in default namespace
# kubectl get task | grep git-clone
git-clone 54s</code>Test the task with a
TaskRunusing a public repository:
<code>apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
name: test-git-clone
namespace: default
spec:
workspaces:
- name: output
emptyDir: {}
params:
- name: url
value: "https://gitee.com/coolops/tekton-install.git"
- name: revision
value: "master"
- name: gitInitImage
value: "registry.cn-hangzhou.aliyuncs.com/coolops/tekton-git-init:v0.29"
taskRef:
name: git-clone</code>Running it pulls the code successfully.
Unit Test
The unit‑test task simply runs
go test ./...in a Go environment.
<code>go test ./...
ok devops-hello-world 0.313s
ok devops-hello-world/pkg (cached)</code> <code>apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: unit-test
spec:
workspaces:
- name: source
steps:
- name: unit-test
workingDir: $(workspaces.source.path)
image: golang:1.17.5
env:
- name: GOPROXY
value: https://goproxy.cn
command: ['go']
args:
- "test"
- "./..."</code>Build Image / Push
We use a multi‑stage build with Kaniko, so a single task handles both building and pushing the image.
<code>apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: build-push-image
spec:
params:
- name: pathToDockerfile
description: The path to the Dockerfile to build (relative to the context)
default: Dockerfile
- name: imageUrl
description: URL of the image repository
- name: imageTag
description: Tag to apply to the built image
default: latest
workspaces:
- name: source
- name: dockerconfig
mountPath: /kaniko/.docker
steps:
- name: build-and-push
image: registry.cn-hangzhou.aliyuncs.com/coolops/kaniko-executor:v1.5.0
workingDir: $(workspaces.source.path)
command: ['/kaniko/executor']
args:
- --dockerfile=$(params.pathToDockerfile)
- --destination=$(params.imageUrl):$(params.imageTag)
- --context=$(workspaces.source.path)</code>Create a Docker config secret for Kaniko:
<code>kubectl create secret docker-registry dockerhub \
--docker-server=https://index.docker.io/v1/ \
--docker-username=[USERNAME] \
--docker-password=[PASSWORD] \
--dry-run=client -o json | jq -r '.data.".dockerconfigjson"' | base64 -d > /tmp/config.json && \
kubectl create secret generic docker-config --from-file=/tmp/config.json && \
rm -f /tmp/config.json</code>If
jqis missing, install it:
<code>yum install jq -y</code>Deploy Application
Deploy the application using a Kubernetes
Deploymentvia
kubectl. Mount the kubeconfig as a secret.
<code>kubectl create secret generic kubernetes-config --from-file=/root/.kube/config</code> <code>apiVersion: tekton.dev/v1alpha1
kind: Task
metadata:
name: deploy-to-k8s
spec:
workspaces:
- name: source
- name: kubernetesconfig
mountPath: /root/.kube
params:
- name: pathToYamlFile
description: The path to the yaml file to deploy within the git source
default: deployment.yaml
- name: IMAGE
- name: TAG
steps:
- name: run-kubectl
image: registry.cn-hangzhou.aliyuncs.com/coolops/kubectl:1.19.16
workingDir: $(workspaces.source.path)
script: |
sed -i s#IMAGE#$(params.IMAGE)#g $(params.pathToYamlFile)
sed -i s#TAG#$(params.TAG)#g $(params.pathToYamlFile)
kubectl apply -f $(params.pathToYamlFile)</code>Combine into a Pipeline
All tasks are assembled into a
Pipelinewith required workspaces and parameters.
<code>apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: devops-hello-world-pipeline
spec:
workspaces:
- name: go-repo-pvc
- name: docker-config
- name: kubernetes-config
params:
- name: git_url
- name: revision
type: string
default: "master"
- name: gitInitImage
type: string
default: "registry.cn-hangzhou.aliyuncs.com/coolops/tekton-git-init:v0.29"
- name: pathToDockerfile
description: The path to the build context used by Kaniko
default: .
- name: imageUrl
description: Url of image repository
- name: imageTag
description: Tag to apply to the built image
default: latest
tasks:
- name: clone
taskRef:
name: git-clone
workspaces:
- name: output
workspace: go-repo-pvc
params:
- name: url
value: $(params.git_url)
- name: revision
value: $(params.revision)
- name: gitInitImage
value: $(params.gitInitImage)
- name: unit-test
taskRef:
name: unit-test
workspaces:
- name: source
workspace: go-repo-pvc
runAfter:
- clone
- name: build-push-image
taskRef:
name: build-push-image
params:
- name: pathToDockerfile
value: $(params.pathToDockerfile)
- name: imageUrl
value: $(params.imageUrl)
- name: imageTag
value: $(params.imageTag)
workspaces:
- name: source
workspace: go-repo-pvc
- name: dockerconfig
workspace: docker-config
runAfter:
- unit-test
- name: deploy-to-k8s
taskRef:
name: deploy-to-k8s
params:
- name: pathToYamlFile
value: deployment.yaml
- name: IMAGE
value: $(params.imageUrl)
- name: TAG
value: $(params.imageTag)
workspaces:
- name: source
workspace: go-repo-pvc
- name: kubernetesconfig
workspace: kubernetes-config
runAfter:
- build-push-image</code>Run Tests
Create the necessary secrets, service account, and role binding before running the pipeline.
<code>apiVersion: v1
kind: Secret
metadata:
name: gitlab-auth
annotations:
tekton.dev/git-0: https://gitee.com/
type: kubernetes.io/basic-auth
stringData:
username: xxxx
password: xxxx
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: tekton-build-sa
secrets:
- name: gitlab-auth
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: tekton-clusterrole-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: edit
subjects:
- kind: ServiceAccount
name: tekton-build-sa
namespace: default</code>Create a
PipelineRunwith parameters and workspaces:
<code>apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: devops-hello-world-pipeline-run
spec:
pipelineRef:
name: devops-hello-world-pipeline
params:
- name: revision
value: master
- name: git_url
value: https://gitee.com/coolops/devops-hello-world.git
- name: imageUrl
value: registry.cn-hangzhou.aliyuncs.com/coolops/devops-hello-world
- name: imageTag
value: latest
- name: pathToDockerfile
value: Dockerfile
workspaces:
- name: go-repo-pvc
volumeClaimTemplate:
spec:
accessModes: [ReadWriteOnce]
storageClassName: openebs-hostpath
resources:
requests:
storage: 1Gi
- name: docker-config
secret:
secretName: docker-config
- name: kubernetes-config
secret:
secretName: kubernetes-config
serviceAccountName: tekton-build-sa</code>The pipeline runs successfully in the Tekton Dashboard, and the application starts correctly.
To make the image tag dynamic, we use the commit ID output from the
git-clonetask.
<code>apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: devops-hello-world-pipeline
spec:
...
tasks:
- name: build-push-image
params:
- name: imageTag
value: $(tasks.clone.results.commit)
...
- name: deploy-to-k8s
params:
- name: TAG
value: $(tasks.clone.results.commit)
...</code>Running the updated pipeline results in images tagged with the latest commit ID.
The final commit ID can be viewed as shown.
Conclusion
The pipeline is straightforward, but debugging can be time‑consuming due to parameter passing; careful attention to task inputs and outputs is essential.
All code and YAML manifests are available at https://gitee.com/coolops/devops-hello-world for further exploration.
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.