Tekton Lab - OpenShift Pipelines¶
60 min Intermediate
In this lab you'll use Red Hat OpenShift Pipelines, Red Hat's supported distribution of Tekton, to build a continuous integration pipeline. The pipeline clones the bootcamp's sample app from Git, builds a container image, pushes it to OpenShift's internal registry, and deploys it.
Prerequisites¶
- An OpenShift 4.16+ cluster with the Red Hat OpenShift Pipelines operator installed. If it isn't installed and you're a cluster administrator, see Install the operator. OpenShift Local and the Developer Sandbox can both run this lab.
- The
ocCLI, logged in to the cluster. -
The
tknCLI:Download the latest
tknarchive for your architecture from the Tekton CLI releases, extract it, and movetknonto yourPATH. You can also downloadtknfrom your cluster's web console, under the ? menu > Command Line Tools.With Chocolatey:
Check it works with
tkn version.
Install the operator¶
Skip this section if OpenShift Pipelines is already installed. Check with oc get csv -n openshift-operators | grep pipelines.
- Log in to the web console as a cluster administrator.
- Go to Operators > OperatorHub (Ecosystem > Software Catalog on OpenShift 4.20 and later).
- Search for Red Hat OpenShift Pipelines, then click Install and accept the defaults.
- Wait until the operator status shows Succeeded.
oc apply -f - <<'EOF'
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: openshift-pipelines-operator-rh
namespace: openshift-operators
spec:
channel: latest
name: openshift-pipelines-operator-rh
source: redhat-operators
sourceNamespace: openshift-marketplace
EOF
Wait for the operator, then for the Tekton components it installs:
Tekton concepts¶
| Resource | What it is |
|---|---|
| Step | A container that runs one command or script |
| Task | An ordered list of steps. Each Task run is one pod. |
| Pipeline | A graph of Tasks that run in sequence or in parallel |
| TaskRun / PipelineRun | One execution of a Task or Pipeline, with its parameter values, workspaces and logs |
| Workspace | Storage shared between Tasks, for example the cloned source code |
| Resolver | Fetches Task and Pipeline definitions from the cluster, a Git repo, a bundle or Artifact Hub |
Setup¶
OpenShift Pipelines automatically creates a pipeline ServiceAccount in every project. PipelineRuns use it, and it has permission to push to the project's image streams and to create Deployments.
Part 1: Your first Task¶
-
Save this Task as
hello-task.yaml: -
Create the Task and list the Tasks in your project:
-
Run it with
tkn, override the parameter, and stream the logs: -
tkncreated a TaskRun object for you. List the TaskRuns, then look at the pod that ran the step:
Part 2: A build-and-deploy Pipeline¶
Instead of writing every Task yourself, reuse the Tasks that OpenShift Pipelines ships in the openshift-pipelines namespace. Reference them with the cluster resolver:
This lab uses three of them:
| Task | Purpose | Key parameters |
|---|---|---|
git-clone | Clone a Git repository into a workspace | URL, REVISION |
buildah | Build an image from a Containerfile and push it | IMAGE, DOCKERFILE, CONTEXT |
openshift-client | Run oc commands | SCRIPT |
Coming from ClusterTasks?
Older tutorials use kind: ClusterTask references. OpenShift Pipelines 1.17 removed ClusterTasks. Use resolver: cluster, as shown below.
-
Save this Pipeline as
pipeline.yaml:pipeline.yamlapiVersion: tekton.dev/v1 kind: Pipeline metadata: name: build-and-deploy spec: params: - name: git-url type: string default: https://github.com/ibm-cloud-architecture/cloud-native-bootcamp.git - name: git-revision type: string default: main - name: context-dir type: string description: Directory in the repo that contains the Containerfile default: sample-app/greeting - name: app-name type: string default: greeting workspaces: - name: source tasks: - name: fetch-source taskRef: resolver: cluster params: - { name: kind, value: task } - { name: name, value: git-clone } - { name: namespace, value: openshift-pipelines } params: - { name: URL, value: $(params.git-url) } - { name: REVISION, value: $(params.git-revision) } workspaces: - { name: output, workspace: source } - name: build-image runAfter: [fetch-source] taskRef: resolver: cluster params: - { name: kind, value: task } - { name: name, value: buildah } - { name: namespace, value: openshift-pipelines } params: - name: IMAGE value: image-registry.openshift-image-registry.svc:5000/$(context.pipelineRun.namespace)/$(params.app-name):latest - { name: CONTEXT, value: $(params.context-dir) } - { name: DOCKERFILE, value: $(params.context-dir)/Containerfile } workspaces: - { name: source, workspace: source } - name: deploy runAfter: [build-image] taskRef: resolver: cluster params: - { name: kind, value: task } - { name: name, value: openshift-client } - { name: namespace, value: openshift-pipelines } params: - name: SCRIPT value: | IMAGE="$(tasks.build-image.results.IMAGE_URL)@$(tasks.build-image.results.IMAGE_DIGEST)" oc get deployment $(params.app-name) || \ oc create deployment $(params.app-name) --image="${IMAGE}" --port=8080 oc set image deployment/$(params.app-name) "*=${IMAGE}" oc rollout status deployment/$(params.app-name) --timeout=3m oc get service $(params.app-name) || oc expose deployment $(params.app-name) --port=8080 oc get route $(params.app-name) || oc expose service $(params.app-name)A few things to notice:
$(tasks.build-image.results.IMAGE_DIGEST)passes a result from one Task to another. Deploying by digest guarantees that every build rolls out, even though the tag (latest) stays the same.$(context.pipelineRun.namespace)resolves to the project the pipeline runs in.- The
deployscript is idempotent: it creates the Deployment, Service and Route on the first run and only updates the image afterwards.
-
Create the Pipeline and look at it:
-
Start a run. The
sourceworkspace gets a new 1 GiB PersistentVolumeClaim for each run, created from a volumeClaimTemplate: -
When the run succeeds, call the app:
Part 3: The web console¶
- In the web console, go to Pipelines and select the
tekton-labproject. - Open
build-and-deployto see the Tasks as a graph, and open a PipelineRun to see each Task's logs and duration. - Start another run from Actions > Start. Choose VolumeClaimTemplate for the
sourceworkspace. - Change the
GREETINGenvironment variable of the Deployment (oc set env deployment/greeting GREETING="Hello from the pipeline"), run the pipeline again, and check whether your setting survives the redeploy. Why does it?
Part 4 (optional): Build your own fork on every push¶
To run the pipeline automatically when code changes, it needs to be triggered by your Git provider.
- Fork the bootcamp repository on GitHub.
-
Save these Triggers resources as
triggers.yaml. They create an EventListener that receives GitHub push webhooks and starts a PipelineRun for the pushed commit:triggers.yamlapiVersion: triggers.tekton.dev/v1beta1 kind: TriggerBinding metadata: name: github-push spec: params: - name: git-url value: $(body.repository.clone_url) - name: git-revision value: $(body.after) --- apiVersion: triggers.tekton.dev/v1beta1 kind: TriggerTemplate metadata: name: build-and-deploy spec: params: - name: git-url - name: git-revision resourcetemplates: - apiVersion: tekton.dev/v1 kind: PipelineRun metadata: generateName: build-and-deploy- spec: pipelineRef: name: build-and-deploy params: - { name: git-url, value: $(tt.params.git-url) } - { name: git-revision, value: $(tt.params.git-revision) } workspaces: - name: source volumeClaimTemplate: spec: accessModes: [ReadWriteOnce] resources: requests: storage: 1Gi --- apiVersion: triggers.tekton.dev/v1beta1 kind: EventListener metadata: name: github-listener spec: serviceAccountName: pipeline triggers: - name: github-push interceptors: - ref: name: github params: - name: eventTypes value: ["push"] bindings: - ref: github-push template: ref: build-and-deploy -
Create the resources and expose the EventListener:
-
In your fork, open Settings > Webhooks > Add webhook. Set Payload URL to the URL above and Content type to
application/json, then save. Your cluster must be reachable from the internet, so this doesn't work with OpenShift Local. - Change the default message in
sample-app/greeting/main.go, then commit and push. A new PipelineRun starts automatically:tkn pipelinerun list.
Pipelines as Code
OpenShift Pipelines also includes Pipelines as Code. It keeps PipelineRun definitions in a .tekton/ directory of your repository, runs them on pushes and pull requests, and reports the results back to GitHub or GitLab. It's the recommended way to run CI on OpenShift.
Cleanup¶
What you learned¶
- Tekton building blocks: Steps, Tasks, Pipelines, runs, workspaces and results
- Reusing the Tasks that ship with OpenShift Pipelines through the cluster resolver
- Building and pushing images with buildah, and deploying by digest
- Triggering pipelines from Git events