This article is part 1 of the series where we will build a pipeline to build and deploy an application on OpenShift.
In Part 1, we will build a pipeline that will fetch the code from the GitHub repository, build an image, and deploy it on OpenShift & In Part 2 we will automate the triggering of the pipeline using Tekton Triggers on a GitHub Event.
We will be using an existing application created by alexdevero which is a meme generator.
I have forked this and modified it so that it can be dockerized and deployed on a cluster. You can get it from sm43/react-meme-generator-ts.
- Kubernetes Cluster
I will be using an OpenShift Cluster. You can get one from https://try.openshift.com or install an OpenShift Cluster on your local machine i.e CRC.
You can use any Kubernetes cluster for installing, running, and managing the pipeline using UI which we will see in a bit.
CLI to access the cluster.
Tetkon CLI to interact with Tekton resource.
Let’s get started.
Login into you OpenShift Cluster and install
RedHat OpenShift Pipeline Operator from Operator Hub.
Once Installed you can go and check-in
openshift-pipelines namespace that the Pipelines and Triggers are deployed as Pods.
Now, let's clone the repository which has the application and the deployment files.
git clone https://github.com/SM43/react-meme-generator-ts.gitcd react-meme-generator-ts/
Let’s understand what we are going to do. So, we have an App which is a meme generator developed in react. There is Dockerfile which will be used to create a docker image from the code.
You can also create an image and run locally using docker/podman.
podman build -t meme-generator . && \
podman run --rm -p 8080:8080 localhost/meme-generator
Once the image is built and committed, access the application at http://localhost:8080.
Now, we have dockerfile to create a image, we will use this in our pipeline.
Our pipeline looks as below
- name: repository
- name: image
- name: manifest-dir
- name: deployment-name
- name: shared-workspace
- name: fetch-repository
- name: output
- name: url
- name: subdirectory
- name: deleteExisting
- name: build-image
- name: source
- name: IMAGE
- name: TLSVERIFY
- name: deploy
- name: source
- name: new-image
- name: deployment-name
There are 3 stages:
1. fetch-repository which uses
git-clone task and clone the repository in the workspace. In this stage, we pass git URL to the task and the pvc (workspace) where the repository will be cloned. This same workspace will be used by next Task to access the code.
2. build-image which uses
buildah task to create an docker image from the code cloned in workspace and push the image to the registry. In this stage we pass the workspace where the code is cloned and the registry+image reference where the image will be pushed.
3. deploy which uses the
oc-apply-deployment task to deploy the image used to the registry using the
manifest files in the repository. We pass the image name, deployment-name and workspace where the code is cloned. By default the task will look for manifestin
k8s directory which is there in the repository.
If we have a directory with different name then we can pass the name as a param to the Task.
kubectl apply -f \
kubectl apply -f \
Check the installed Tasks using the below command
> ~ > tkn task ls
NAME DESCRIPTION AGE
buildah Buildah task builds... 7 seconds ago
git-clone These Tasks are Git... 12 seconds ago
The third task is a custom task created, you can use any other task from the catalog as per your wish.
Make sure you are in the
pipeline directory has 4 files :
- First will create a PVC which will be used as a workspace for cloning the repository and then the other Tasks will access this workspace.
- Second will install the Task which deploys the image using the manifest in
k8s directory. If the image is changed then it will patch the existing deployment with the new image.
- Third will install the Pipeline.
- Fourth will create a new instance of PipelineRun which executes the pipeline.
If you take a look at the PipelineRun, you would be able to see that it has params to mention the GitHub URL, the image name, the deployment name.
You can edit as you want.
Apply the files using the below command:
kubectl apply -f pipeline/
Check the installed pipeline using
> ~ > tkn p ls
NAME AGE LAST RUN STARTED DURATION STATUS
build-and-deploy 7 seconds ago --- --- --- ---
Check the PipelineRun started
> ~ > tkn pr ls
NAME STARTED DURATION STATUS
build-and-deploy-run 10 seconds ago --- Running
We are using the OpenShift Internal Registry to push the Image. If you see in PipelineRun, the image mentioned is
This is configured for the default namespace. If you are in a different namespace make sure you replace
default with the namespace you are in.
You can also use an external registry like DockerHub or Quay to push the Image. You need to create a registry secret and give permission to
pipeline the service account to access that secret with permission to pull and push.
pipeline service account is created when we install Pipelines using the Operator from Operator Hub.
You can check out the progress of Pipeline from the OpenShift Console, going to
Developer tab and clicking on
You can also check the logs from the command line using tkn.
tkn pr ls
This will list the PipelineRuns.
To follow the logs, use the below command
tkn pr logs -f build-and-deploy-run
In k8s, there 3 files deployment, service, and route. In the final stage of the pipeline, the task will apply these files and create a deployment for the application, will expose the app using a NodePort Service, and create a route to access the app.
Once the pipeline is completed, you would be able to see a pod created in
Topology. Click on the pod and use the route created to access the Application.
We have successfully created a Pipeline that builds an image and deploys it on the Cluster. Currently, we are manually invoking the Pipeline, in the next article, we will configure Tekton Trigger which will trigger the Pipeline on a GitHub Event for ex. after a pull request is merged the Pipeline will start and deploy the new changes on the Cluster.
Part 2 coming soon... :)