OpenShift Pipelines: Complete Tekton CI/CD Guide
OpenShift Pipelines is a cloud-native, continuous integration and delivery (CI/CD) solution based on Kubernetes resources and Tekton. This comprehensive guide covers pipeline creation, task development, and production CI/CD patterns for OpenShift.
What is OpenShift Pipelines?
OpenShift Pipelines provides:
Key Features
- Kubernetes Native: Pipelines as Custom Resources
- Reusable Components: Tasks and pipelines as building blocks
- Serverless: No dedicated CI/CD server required
- Parallel Execution: Run tasks in parallel
- Extensibility: Custom tasks and resources
- Event-Driven: Webhook and event triggers
- Multi-Platform: Build for any platform
- GitOps Ready: Integration with ArgoCD and Flux
Architecture
┌─────────────────────────────────────────────────────────┐│ Tekton Components ││ ││ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ││ │ Pipeline │ │ Task │ │ Trigger │ ││ │ (CRD) │ │ (CRD) │ │ (CRD) │ ││ └──────────────┘ └──────────────┘ └──────────────┘ ││ ││ ┌──────────────┐ ┌──────────────┐ ││ │ PipelineRun │ │ TaskRun │ ││ │ (Runtime) │ │ (Runtime) │ ││ └──────────────┘ └──────────────┘ │└─────────────────────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────┐│ Kubernetes/OpenShift ││ ││ Each TaskRun creates a Pod with containers for steps │└─────────────────────────────────────────────────────────┘Installation
Install Operator
# Via OpenShift Console:# Operators → OperatorHub → Search "OpenShift Pipelines"# → Install → Subscribe
# Or via CLIcat <<EOF | oc apply -f -apiVersion: operators.coreos.com/v1alpha1kind: Subscriptionmetadata: name: openshift-pipelines-operator namespace: openshift-operatorsspec: channel: latest name: openshift-pipelines-operator-rh source: redhat-operators sourceNamespace: openshift-marketplaceEOF
# Verify installationoc get pods -n openshift-pipelinestkn versionInstall tkn CLI
# macOSbrew install tektoncd-cli
# Linuxwget https://github.com/tektoncd/cli/releases/download/v0.33.0/tkn_0.33.0_Linux_x86_64.tar.gztar xvzf tkn_0.33.0_Linux_x86_64.tar.gzsudo mv tkn /usr/local/bin/
# Windowschoco install tektoncd-cli
# Verifytkn versionCore Concepts
Task
apiVersion: tekton.dev/v1beta1kind: Taskmetadata: name: build-imagespec: params: - name: IMAGE type: string description: Image name with tag - name: CONTEXT type: string default: "." description: Build context directory
workspaces: - name: source description: Source code workspace
steps: - name: build-and-push image: gcr.io/kaniko-project/executor:latest command: - /kaniko/executor args: - --context=$(workspaces.source.path)/$(params.CONTEXT) - --dockerfile=$(workspaces.source.path)/$(params.CONTEXT)/Dockerfile - --destination=$(params.IMAGE) - --cache=true volumeMounts: - name: docker-config mountPath: /kaniko/.docker
volumes: - name: docker-config secret: secretName: docker-configClusterTask
apiVersion: tekton.dev/v1beta1kind: ClusterTaskmetadata: name: git-clonespec: params: - name: url type: string description: Repository URL - name: revision type: string default: main description: Git revision - name: subdirectory type: string default: "" description: Subdirectory inside workspace
workspaces: - name: output description: Clone destination
steps: - name: clone image: gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:latest script: | #!/bin/sh set -eu git clone $(params.url) $(workspaces.output.path)/$(params.subdirectory) cd $(workspaces.output.path)/$(params.subdirectory) git checkout $(params.revision)Pipeline
apiVersion: tekton.dev/v1beta1kind: Pipelinemetadata: name: build-and-deployspec: params: - name: APP_NAME type: string - name: GIT_REPO type: string - name: GIT_REVISION type: string default: main - name: IMAGE type: string - name: DEPLOYMENT_NAME type: string
workspaces: - name: shared-workspace - name: maven-settings
tasks: # Task 1: Clone repository - name: fetch-repository taskRef: name: git-clone kind: ClusterTask workspaces: - name: output workspace: shared-workspace params: - name: url value: $(params.GIT_REPO) - name: revision value: $(params.GIT_REVISION)
# Task 2: Run tests - name: run-tests taskRef: name: maven kind: ClusterTask runAfter: - fetch-repository workspaces: - name: source workspace: shared-workspace - name: maven-settings workspace: maven-settings params: - name: GOALS value: - clean - test
# Task 3: Build image - name: build-image taskRef: name: build-image runAfter: - run-tests workspaces: - name: source workspace: shared-workspace params: - name: IMAGE value: $(params.IMAGE)
# Task 4: Deploy - name: deploy taskRef: name: openshift-client kind: ClusterTask runAfter: - build-image params: - name: SCRIPT value: | oc set image deployment/$(params.DEPLOYMENT_NAME) \ $(params.APP_NAME)=$(params.IMAGE) oc rollout status deployment/$(params.DEPLOYMENT_NAME)PipelineRun
apiVersion: tekton.dev/v1beta1kind: PipelineRunmetadata: generateName: build-deploy-run-spec: pipelineRef: name: build-and-deploy
params: - name: APP_NAME value: myapp - name: GIT_REPO value: https://github.com/example/myapp - name: GIT_REVISION value: main - name: IMAGE value: image-registry.openshift-image-registry.svc:5000/myproject/myapp:latest - name: DEPLOYMENT_NAME value: myapp
workspaces: - name: shared-workspace volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi - name: maven-settings emptyDir: {}
timeouts: pipeline: 1h tasks: 30mCommon Tasks
Maven Build
apiVersion: tekton.dev/v1beta1kind: Taskmetadata: name: maven-buildspec: params: - name: GOALS type: array default: - package - name: MAVEN_IMAGE type: string default: gcr.io/cloud-builders/mvn:latest
workspaces: - name: source - name: maven-settings
steps: - name: mvn image: $(params.MAVEN_IMAGE) workingDir: $(workspaces.source.path) command: - /usr/bin/mvn args: - -s - $(workspaces.maven-settings.path)/settings.xml - $(params.GOALS) env: - name: MAVEN_OPTS value: "-Xmx1024m"NPM Build
apiVersion: tekton.dev/v1beta1kind: Taskmetadata: name: npm-buildspec: params: - name: NODE_VERSION type: string default: "18"
workspaces: - name: source
steps: - name: install image: node:$(params.NODE_VERSION) workingDir: $(workspaces.source.path) script: | #!/bin/sh npm ci
- name: test image: node:$(params.NODE_VERSION) workingDir: $(workspaces.source.path) script: | #!/bin/sh npm test
- name: build image: node:$(params.NODE_VERSION) workingDir: $(workspaces.source.path) script: | #!/bin/sh npm run buildSecurity Scan
apiVersion: tekton.dev/v1beta1kind: Taskmetadata: name: trivy-scanspec: params: - name: IMAGE type: string
steps: - name: scan image: aquasec/trivy:latest command: - trivy args: - image - --severity - HIGH,CRITICAL - --exit-code - "1" - $(params.IMAGE)Triggers
EventListener
apiVersion: triggers.tekton.dev/v1beta1kind: EventListenermetadata: name: github-listenerspec: serviceAccountName: pipeline triggers: - name: github-push interceptors: - ref: name: github params: - name: secretRef value: secretName: github-webhook-secret secretKey: secret - name: eventTypes value: - push bindings: - ref: github-binding template: ref: build-deploy-templateTriggerBinding
apiVersion: triggers.tekton.dev/v1beta1kind: TriggerBindingmetadata: name: github-bindingspec: params: - name: gitrevision value: $(body.head_commit.id) - name: gitrepositoryurl value: $(body.repository.url) - name: gitrepositoryname value: $(body.repository.name)TriggerTemplate
apiVersion: triggers.tekton.dev/v1beta1kind: TriggerTemplatemetadata: name: build-deploy-templatespec: params: - name: gitrevision - name: gitrepositoryurl - name: gitrepositoryname
resourcetemplates: - apiVersion: tekton.dev/v1beta1 kind: PipelineRun metadata: generateName: $(tt.params.gitrepositoryname)-run- spec: pipelineRef: name: build-and-deploy params: - name: GIT_REPO value: $(tt.params.gitrepositoryurl) - name: GIT_REVISION value: $(tt.params.gitrevision) - name: APP_NAME value: $(tt.params.gitrepositoryname) workspaces: - name: shared-workspace volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 1GiConfigure Webhook
# Get EventListener URLoc get route el-github-listener -o jsonpath='{.spec.host}'
# Configure in GitHub:# Settings → Webhooks → Add webhook# Payload URL: http://el-github-listener-myproject.apps.cluster.example.com# Content type: application/json# Secret: (from github-webhook-secret)# Events: Just the push eventWorkspaces
PersistentVolumeClaim
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: pipeline-workspacespec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi---# Use in PipelineRunworkspaces:- name: shared-workspace persistentVolumeClaim: claimName: pipeline-workspaceVolumeClaimTemplate
# Dynamic PVC creationworkspaces:- name: shared-workspace volumeClaimTemplate: spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: gp3-csiConfigMap/Secret
workspaces:- name: maven-settings configMap: name: maven-settings- name: docker-config secret: secretName: docker-credentialsComplete CI/CD Pipeline
apiVersion: tekton.dev/v1beta1kind: Pipelinemetadata: name: production-pipelinespec: params: - name: APP_NAME - name: GIT_REPO - name: GIT_REVISION default: main - name: IMAGE_REGISTRY - name: IMAGE_TAG default: latest
workspaces: - name: shared-workspace - name: docker-config
tasks: # 1. Clone source - name: clone taskRef: name: git-clone kind: ClusterTask workspaces: - name: output workspace: shared-workspace params: - name: url value: $(params.GIT_REPO) - name: revision value: $(params.GIT_REVISION)
# 2. Run unit tests - name: test taskRef: name: npm-build runAfter: [clone] workspaces: - name: source workspace: shared-workspace
# 3. Code analysis - name: sonar-scan taskRef: name: sonarqube-scanner kind: ClusterTask runAfter: [test] workspaces: - name: source workspace: shared-workspace params: - name: SONAR_HOST_URL value: https://sonarqube.example.com - name: SONAR_PROJECT_KEY value: $(params.APP_NAME)
# 4. Build container image - name: build taskRef: name: buildah kind: ClusterTask runAfter: [sonar-scan] workspaces: - name: source workspace: shared-workspace - name: dockerconfig workspace: docker-config params: - name: IMAGE value: $(params.IMAGE_REGISTRY)/$(params.APP_NAME):$(params.IMAGE_TAG) - name: TLSVERIFY value: "false"
# 5. Security scan - name: scan taskRef: name: trivy-scan runAfter: [build] params: - name: IMAGE value: $(params.IMAGE_REGISTRY)/$(params.APP_NAME):$(params.IMAGE_TAG)
# 6. Deploy to dev - name: deploy-dev taskRef: name: openshift-client kind: ClusterTask runAfter: [scan] params: - name: SCRIPT value: | oc project dev oc set image deployment/$(params.APP_NAME) \ $(params.APP_NAME)=$(params.IMAGE_REGISTRY)/$(params.APP_NAME):$(params.IMAGE_TAG) oc rollout status deployment/$(params.APP_NAME)
# 7. Integration tests - name: integration-test taskRef: name: curl kind: ClusterTask runAfter: [deploy-dev] params: - name: url value: http://$(params.APP_NAME).dev.svc:8080/health
# 8. Deploy to staging (manual approval would go here) - name: deploy-staging taskRef: name: openshift-client kind: ClusterTask runAfter: [integration-test] params: - name: SCRIPT value: | oc project staging oc set image deployment/$(params.APP_NAME) \ $(params.APP_NAME)=$(params.IMAGE_REGISTRY)/$(params.APP_NAME):$(params.IMAGE_TAG) oc rollout status deployment/$(params.APP_NAME)CLI Operations
# List pipelinestkn pipeline list
# Start pipelinetkn pipeline start build-and-deploy \ -p APP_NAME=myapp \ -p GIT_REPO=https://github.com/example/myapp \ -w name=shared-workspace,claimName=pipeline-workspace \ --showlog
# List runstkn pipelinerun list
# View logstkn pipelinerun logs -f <pipelinerun-name>
# Describe pipelinetkn pipeline describe build-and-deploy
# Delete pipeline runtkn pipelinerun delete <pipelinerun-name>
# Cancel running pipelinetkn pipelinerun cancel <pipelinerun-name>
# List taskstkn task listtkn clustertask list
# Start task directlytkn task start build-image \ -p IMAGE=myimage:latest \ -w name=source,claimName=source-pvc \ --showlogMonitoring
Pipeline Metrics
# ServiceMonitor for TektonapiVersion: monitoring.coreos.com/v1kind: ServiceMonitormetadata: name: tekton-pipelines-controller namespace: openshift-pipelinesspec: endpoints: - interval: 30s port: metrics selector: matchLabels: app: tekton-pipelines-controllerDashboard
# Install Tekton Dashboardoc apply -f https://github.com/tektoncd/dashboard/releases/latest/download/openshift-tekton-dashboard-release.yaml
# Expose dashboardoc expose svc tekton-dashboard -n openshift-pipelines
# Get URLoc get route tekton-dashboard -n openshift-pipelinesBest Practices
Resource Management
spec: steps: - name: build resources: requests: cpu: 500m memory: 1Gi limits: cpu: 1000m memory: 2GiTimeout Configuration
# Task timeoutspec: timeout: 30m
# Pipeline timeoutspec: timeouts: pipeline: 1h tasks: 30m finally: 15mResults
# Task with resultsspec: results: - name: image-digest description: Digest of the built image
steps: - name: build script: | # ... build steps ... echo -n $DIGEST | tee $(results.image-digest.path)
# Use in next task- name: deploy params: - name: IMAGE_DIGEST value: $(tasks.build.results.image-digest)Troubleshooting
# View pod logsoc logs -f <pipelinerun-pod>
# Describe PipelineRuntkn pipelinerun describe <name>
# Get eventsoc get events --sort-by='.lastTimestamp'
# Debug failed taskoc debug pod/<taskrun-pod>
# Clean up old runstkn pipelinerun delete --keep 5Conclusion
OpenShift Pipelines provides a powerful, Kubernetes-native CI/CD solution built on Tekton. Its declarative approach, reusable components, and deep OpenShift integration make it ideal for cloud-native application delivery pipelines.
Master OpenShift Pipelines with our training programs. Contact us for customized CI/CD training.