Deploy A Java Application to Openshift by Using Tekton Pipeline

Tekton is one of CI/CD tools that we can use for building and deploying application, it provides a lightweight yet powerful and flexible cloud native CI/CD. For this sample, i am planning to demonstrate a build and deployment for a java Spring Boot application into Openshift.

First we need to create two different Openshift Namespace,

oc new-project edwin-pipeline
oc new-project edwin-deploy

So lets start with creating a new PVC for storing our build artifacts. This PVC is going to be needed betweek Task, and we’ll store those artifact under a different folder based on Pipeline’s uid variable to prevent overlapping one and another.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: tekton-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 1Gi

And a pipeline YML file, for orchestrating our build and deployment steps.

apiVersion: tekton.dev/v1alpha1
kind: Pipeline
metadata:
  name: hello-world-java-build-and-deploy
spec:
  params:
    - name: uid
      description: the uid
  workspaces:
    - name: task-pvc
  tasks:
  - name: git-clone
    taskRef:
      name: git-clone
    params:
    - name: app-git
      value: https://github.com/edwin/spring-boot-hello-world
    - name: uid
      value: $(params.uid)
    workspaces:
    - name: task-pvc
      workspace: task-pvc
  - name: build
    taskRef:
      name: mvn
    runAfter: ["git-clone"]
    params:
    - name: goal
      value: "package"
    - name: uid
      value: $(params.uid)
    workspaces:
    - name: task-pvc
      workspace: task-pvc
  - name: test
    taskRef:
      name: mvn
    runAfter: ["build"]
    params:
    - name: goal
      value: "test"
    - name: uid
      value: $(params.uid)
    workspaces:
    - name: task-pvc
      workspace: task-pvc
  - name: integration-test
    taskRef:
      name: mvn
    runAfter: ["build"]
    params:
    - name: goal
      value: "test"
    - name: uid
      value: $(params.uid)
    workspaces:
    - name: task-pvc
      workspace: task-pvc      
  - name: deploy
    taskRef:
      name: deploy-and-clean
    runAfter: ["integration-test","test"]
    params:
    - name: uid
      value: $(params.uid)
    workspaces:
    - name: task-pvc
      workspace: task-pvc

Based on above Pipeline, we have several Tasks which are involved within it. Lets start with a Task to clone a code from Github.

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
spec:
  params:
    - name: app-git
      description: the git repo
    - name: uid
      description: uid
  workspaces:
    - name: task-pvc
      mountPath: /workspace/source 
  steps:
    - name: git-clone
      command: ["/bin/sh", "-c"]
      args:
        - | 
          set -e -o
          echo "git clone";
          mkdir /workspace/source/$(params.uid) && cd /workspace/source/$(params.uid);
          git clone $(params.app-git) /workspace/source/$(params.uid);
      image: image-registry.openshift-image-registry.svc:5000/openshift/jenkins-agent-maven

And a simple Maven build Task,

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: mvn
spec:
  params:
    - name: goal
      description: mvn goal
    - name: uid
      description: uid
  workspaces:
    - name: task-pvc
      mountPath: /workspace/source 
  steps:
    - name: mvn
      command: ["/bin/sh", "-c"]
      args:
        - | 
          set -e -o
          echo "mvn something";
          cd /workspace/source/$(params.uid);
          mvn $(params.goal) -Dmaven.repo.local=/workspace/source/m2;
      image: image-registry.openshift-image-registry.svc:5000/openshift/jenkins-agent-maven

The last task involved is a task to do deployment and removing build folder,

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: deploy-and-clean
spec:
  params:
    - name: uid
      description: uid
  workspaces:
    - name: task-pvc
      mountPath: /workspace/source 
  steps:
    - name: git-clone
      command: ["/bin/sh", "-c"]
      args:
        - | 
          set -e -o
          cd /workspace/source/$(params.uid) ;
          mkdir build-folder ;
          cp target/*.jar build-folder/ ;
          oc login --insecure-skip-tls-verify --token=my-openshift-token --server=https://api.my-openshift-url.com:6443 ;
          oc new-build  --name hello-world --binary=true -n edwin-deploy --image-stream=openjdk-11  || true ;
          oc start-build hello-world --from-dir=build-folder/. -n edwin-deploy --follow --wait ;
          oc new-app hello-world -n edwin-deploy || true ;
          oc expose svc/hello-world -n edwin-deploy || true ;
          cd / ;
          rm -Rf /workspace/source/$(params.uid) ;
      image: image-registry.openshift-image-registry.svc:5000/openshift/jenkins-agent-maven

And the last would be a PipelineRun yaml file for running the whole Pipeline,

apiVersion: tekton.dev/v1alpha1
kind: PipelineRun
metadata:
  generateName: hello-world-run
spec:
  params:
    - name: uid
      value: $(context.pipelineRun.uid)
  pipelineRef:
    name: hello-world-java-build-and-deploy
  workspaces:
    - name: task-pvc
      persistentVolumeClaim:
        claimName: tekton-pvc

And run it by using below command,

oc create -f 06.pipeline-run.yml -n edwin-pipeline

Code for this sample can be found on below Github link,

https://github.com/edwin/java-app-and-tekton-pipeline-sample

We are using UBI8 – OpenJDK11 for the base image that is going to be use for running our java apps. We can import it into our OCP cluster by using below command,

oc import-image openjdk-11 --from=registry.access.redhat.com/ubi8/openjdk-11 --confirm

Finally the result will looks like this,

Thanks

ps. Openshift version used is 4.8.2, and im using Openshift’s jenkins-agent-maven Image to do all build and deployments. Feel free to use other image in case needed.