Workspaces

This chapter build is in progress, expect to change and not working as expected

At the end of this chapter you will be able to :

  • Understand what is a Workspaces ?

  • Mount ConfigMap based configurations as Workspace

  • Mount a PersistenceVolume as Workspace

  • Share and Cache build artifacts

  • Use workspace in TaskRun

  • Use workspace in PipelineRun

If you are not in tutorial chapter folder, then navigate to the folder:

cd $TUTORIAL_HOME/workspaces

Why Workspace ?

In many partical usecases of Pipelines it becomes cricual for you to share the filsystem with between Tasks and between Steps. The filesystem could be typically hold a clone github repostiory, a ConfigMap or a secret.

Tekton workspace a technique by which the Task step and Pipeline task can share a common filesystem. This helps Pipelines to pick up changes form one task to another task in the Pipeline workflow.

Overview

As part of workspaces exercies, we will be building the Java application Apache Maven. Using Java Application usecase allows us to explore all possible applications of workspaces:

  • Mount ConfigMap based configurations as Workspace

  • Mount a PersistenceVolume as Workspace

  • Share and Cache build artifacts

Prepare for using workspaces

All exercises of this chapter will be done a namesapace workspace-auth-demo, lets create and switch to the workspace-auth-demo namespace.

kubectl create ns workspace-auth-demo
kubectl config set-context --current --namespace workspace-auth-demo

As part of this exercise we will need to install the following external tasks to be installed in the namespace:

Check if all the tasks are available:

tkn task ls

The command should show an output like:

NAME               DESCRIPTION              AGE
buildah            Buildah task builds...   11 hours ago
git-clone          These Tasks are Git...   11 hours ago
kn                 This Task performs ...   9 minutes ago
list-directory     Simple directory li...   11 hours ago
maven              This Task can be us...   11 hours ago

Deploy Nexus

To show maven artifact caching and using customized maven settings.xml we will deploy Sonatype Nexus to the cluster:

oc apply -n workspace-auth-demo \
  -f $TUTORIAL_HOME/install/utils/nexus.yaml

Wait for the nexus3 pod to come up before proceeding further with exercises:

watch oc -n workspace-auth-demo get pods,svc

A sucessfully running nexus3 pod should show the following services and pods:

NAME                         READY   STATUS    RESTARTS   AGE
pod/nexus-75fff8bbbd-cmlxs   1/1     Running   0          3m25s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/nexus        NodePort    10.100.205.22   <none>        8081:31743/TCP   3m25s

The nexus maven repository could be opened using the url:

$(minikube service nexus -n workspace-auth-demo)

In OpenShift,we can use routes to expose the service if we need to access it from outside,by:

oc expose svc -n workspace-auth-demo nexus

Create maven-settings ConfigMap

For us to mount the maven settings.xml, we will create ConfigMap holding the custom maven settings.xml:

oc create -n workspace-auth-demo cm maven-settings \
  --from-file=settings.xml=$TUTORIAL_HOME/workspaces/maven-settings.xml
configmap/maven-settings created

You can check the ConfigMap contents using the command:

oc get -n workspace-auth-demo cm maven-settings -oyaml \
  | yq r - data['settings.xml']

The output of the above command should be same as in maven-settings.xml.

Before we create our pipeline ensure that the kubernetes cluster has a default storage class defined:

Deploy Knative Serving

As we will be deploying a Knative serverless application as part of the pipeline, that we will be running later in this chapter, lets deploy Knative to the cluster:

  • Minikube

  • OpenShift

Do it only once per cluster
$TUTORIAL_HOME/bin/enable_knative.sh

Wait for the serving deployment to complete without errors.

OpenShift users can install Knative i.e OpenShift Serverless using its Operators.

Check Default Storage Class

oc get sc
  • Kubernetes

  • OpenShift

In minkube cluster it should show an output like:

NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           false                  9h

An example default storage class in Google Cloud:

NAME                 PROVISIONER            RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
standard (default)   kubernetes.io/gce-pd   Delete          WaitForFirstConsumer   true                   2d3h
  • If you dont have one please check Kubernetes Docs on how to have one configured.

  • In OpenShift cluster the default storage class varies based on the underlying cloud platform. Refer to OpenShift Documentation to know more.

Create PVC

Create the PVC tekton-tutorial-sources, which we will use as part of the exercises in this chapter and the upcoming ones.

oc apply -n workspace-auth-demo -f $TUTORIAL_HOME/workspaces/sources-pvc.yaml

Java Application Pipeline

The Java Application build pipeline will,

  • Git clone using git-clone task, the https://github.com/redhat-scholars/tekton-tutorial-greeter repo and build the springboot application

  • Will use maven task, maven task require two workspaces one for source and other for maven-settings

  • Build the container image using the buildah task and push to the internal container registry

  • Finally deploy the application onto Kubernetes using openshift-client task

Using PVC As Workspace

As part of this exercise we will use PersitenceVolume(PV) and PersistenceVolumeClaim(PVC) as Tekton workspace.

Git Clone TaskRun

Since we will be using the same git repo for all the exercises, lets clone it. As git clone task requires output workspace, we will attach a PersistenceVolumeClaim to it.

Since the cluster as default Storage Class, just specifying the PersistenceVolumeClaim will bind the PVC automatically to underlying storage. We will use the PVC tekton-tutorial-sources that we created earlier.

Let us run the git-clone Task with the TaskRun definition as shown below:

apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
  genrateName: git-clone- (1)
  labels: (2)
    tekton.dev/task: git-clone
spec:
  taskRef:
    name: git-clone
  params: (3)
    - name: url
      value: https://github.com/redhat-scholars/tekton-tutorial-greeter
    - name: revision
      value: staging
  workspaces: (4)
    - name: output
      persistentVolumeClaim:
        claimName: tekton-tutorial-sources
1 As its required have unqiue name for each TaskRun we use create, as that will have new names genrated using generateName prefix
2 Just marking this TaskRun as part of git-clone Task
3 The GitHub Url and revision to use, for more details check the Task
4 Setting the workspace output mapped to PVC tekton-tutorial-sources
  • tkn

  • kubectl

tkn task start git-clone \
  --namespace=workspace-auth-demo \
  --param url=https://github.com/redhat-scholars/tekton-tutorial-greeter \
  --param revision=staging \
  --workspace name=output,claimName=tekton-tutorial-sources \
  --use-param-defaults \(1)
  --showlog
1 Makes the tkn CLI to use the default values from the task definiton without prompting for values

The workspaces can be PVC or ConfigMap, Secret or emptyDir. The pattern to specify them are as follows:

  • PVC

    • name=my-pvc,claimName=pvc1[,subPath=dir]

  • Secret

    • name=my-secret,secret=secret-name

  • Secret

    • name=my-config,config=rpg[,item=ultimav=1]

  • emptyDir

    • name=my-empty-dir,emptyDir=""

kubectl create -n workspace-auth-demo -f git-clone-taskrun.yaml

View the task run logs using,

tkn tr logs -f -a $(tkn tr ls -n workspace-auth-demo | awk 'NR==2{print $1}')

It will take few minutes for the TaskRun to start.

Watch the status of the Task run using:

tkn tr ls

You can also check the PVC is bound, as the git-clone-task output workspace is bound to it:

NAME                      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
tekton-tutorial-sources   Bound    pvc-48aa86ae-ec20-4f0c-a2d0-65d906d41bed   1Gi        RWO            standard       6s

A successful git-clone TaskRun will show the following output:

[clone] + CHECKOUT_DIR=/workspace/output/
[clone] + '[[' false '==' true ]]
[clone] + test -z
[clone] + test -z
[clone] + test -z
[clone] + /ko-app/git-init -url https://github.com/redhat-scholars/tekton-tutorial-greeter -revision staging -refspec  -path /workspace/output/ '-sslVerify=true' '-submodules=true' -depth 1
[clone] {"level":"info","ts":1595778607.616774,"caller":"git/git.go:139","msg":"Successfully cloned https://github.com/redhat-scholars/tekton-tutorial-greeter @ 2e3336657cc1bbf22e3db183a517dcb0a62207b9 (grafted, HEAD, origin/staging) in path /workspace/output/"}
[clone] {"level":"info","ts":1595778607.6473103,"caller":"git/git.go:180","msg":"Successfully initialized and updated submodules in path /workspace/output/"}
[clone] + cd /workspace/output/
[clone] + git rev-parse+ tr -d '\n'
[clone]  HEAD
[clone] + RESULT_SHA=2e3336657cc1bbf22e3db183a517dcb0a62207b9
[clone] + EXIT_CODE=0
[clone] + '[' 0 '!=' 0 ]
[clone] + echo -n 2e3336657cc1bbf22e3db183a517dcb0a62207b9

List Directory TaskRun

As explained in the overview one of the advantages of the workspaces is that it can be shared, lets run a simple list-directory Task to verify the same:

apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
  generateName: list-directory-
  labels:
    tekton.dev/task: list-directory
spec:
  taskRef:
    name: list-directory
  workspaces: (1)
    - name: directory
      persistentVolumeClaim:
        claimName: tekton-tutorial-sources
1 Notice that we bind the same PVC to workspace directory parameter of the list-directory.
  • tkn

  • kubectl

tkn task start list-directory \
  --namespace=workspace-auth-demo \
  --workspace name=directory,claimName=tekton-tutorial-sources \
  --use-param-defaults \
  --showlog
kubectl create -n workspace-auth-demo -f list-dir-taskrun.yaml
taskrun.tekton.dev/list-directory-mbkvl created

If all went well the list directory should show the directory listing of https://github.com/redhat-scholars/tekton-tutorial-greeter.

[list-directory] total 44
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 07:46 springboot
[list-directory] -rw-r--r--    1 root     root           515 Aug 17 07:46 settings.xml
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 07:46 quarkus
[list-directory] -rw-r--r--    1 root     root           926 Aug 17 07:46 pom.xml
[list-directory] -rwxr-xr-x    1 root     root          6607 Aug 17 07:46 mvnw.cmd
[list-directory] -rwxr-xr-x    1 root     root         10069 Aug 17 07:46 mvnw
[list-directory] drwxr-xr-x    2 root     root          4096 Aug 17 07:46 k8s
[list-directory] -rw-r--r--    1 root     root           596 Aug 17 07:46 README.md

[show-readme] # Tekton Greeter
[show-readme]
[show-readme] Project used as part of [Tekton Tutorial](https://dn.dev/tekton-tutorial) execersies.
[show-readme]
[show-readme] The application has one simple REST api at URI `/` that says "Meeow from Tekton 😺 !! 🚀".
[show-readme]
[show-readme] ## Quarkus
[show-readme]
[show-readme] [Quarkus](./quarkus)
[show-readme]
[show-readme] ### Building locally
[show-readme]
[show-readme] ```shell
[show-readme] ./mvnw clean package -pl quarkus
[show-readme] ```
[show-readme]
[show-readme] ### Running locally
[show-readme]
[show-readme] ```shell
[show-readme] java -jar quarkus/target/quarkus-app/quarkus-run.jar
[show-readme] ```
[show-readme]
[show-readme] ## SpringBoot
[show-readme]
[show-readme] [SpringBoot](./quarkus)
[show-readme]
[show-readme] ### Building locally
[show-readme]
[show-readme] ```shell
[show-readme] ./mvnw clean package -pl springboot
[show-readme] ```
[show-readme]
[show-readme] ### Running locally
[show-readme]
[show-readme] ```shell
[show-readme] java -jar springboot/target/tekton-springboot-greeter.jar
[show-readme] ```

Points to Ponder

  • What is a workspace

  • How to bind a workspace to a TaskRun using PVC

  • How to share the workaapce across multiple TaskRuns

Using ConfigMap as Workspace

As part of this exercise we will use and configure Tekton workspace with ConfigMap.

Run maven Task

In this exercise, we will use maven-settings ConfigMap that we created earlier as one of workspace parameter maven-settings and for the source workspace paramter we use the tekton-tutorial-sources PVC.

Let run the maven task to build the tekton-greeter project we cloned earlier.

apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
  generateName: maven-build-
  labels:
    tekton.dev/task: maven
spec:
  taskRef:
    name: maven
  params:
    - name: GOALS (1)
      value:
        - -B
        - -pl
        - springboot
        - -DskipTests
        - clean
        - package
  workspaces:
    - name: maven-settings
      configmap: (2)
        name: maven-settings
    - name: source
      persistentVolumeClaim: (3)
        claimName: tekton-tutorial-sources
1 Specifying the maven goals to be run as a part of the build
2 Configure the maven-settings configmap to be used for maven-settings workspace
3 Configure the tekton-tutorial-sources PVC to be used for source workspace
  • tkn

  • kubectl

tkn task start maven \
  --namespace=workspace-auth-demo \
  --param GOALS='-pl,springboot,-B,-DskipTests,clean,package' \
  --workspace name=maven-settings,config=maven-settings \
  --workspace name=source,claimName=tekton-tutorial-sources \
  --use-param-defaults \
  --showlog
kubectl create -n workspace-auth-demo -f maven-taskrun.yaml
taskrun.tekton.dev/maven-build-9cjws created

View the task run logs using,

tkn tr logs -f -a $(tkn tr ls -n workspace-auth-demo | awk 'NR==2{print $1}')

A successfull run should have output like(output trimmed for brevity):

...
[mvn-goals] [INFO] Downloaded from nexus: http://nexus:8081/repository/maven-public/org/eclipse/sisu/org.eclipse.sisu.plexus/0.3.4/org.eclipse.sisu.plexus-0.3.4.jar (205 kB at 1.0 MB/s)
[mvn-goals] [INFO] Downloaded from nexus: http://nexus:8081/repository/maven-public/org/eclipse/sisu/org.eclipse.sisu.inject/0.3.4/org.eclipse.sisu.inject-0.3.4.jar (379 kB at 1.9 MB/s)
[mvn-goals] [INFO] Downloaded from nexus: http://nexus:8081/repository/maven-public/org/codehaus/plexus/plexus-classworlds/2.6.0/plexus-classworlds-2.6.0.jar (53 kB at 259 kB/s)
[mvn-goals] [INFO] Downloaded from nexus: http://nexus:8081/repository/maven-public/org/sonatype/plexus/plexus-build-api/0.0.7/plexus-build-api-0.0.7.jar (8.5 kB at 40 kB/s)
[mvn-goals] [INFO] Replacing main artifact with repackaged archive
[mvn-goals] [INFO] ------------------------------------------------------------------------
[mvn-goals] [INFO] BUILD SUCCESS
[mvn-goals] [INFO] ------------------------------------------------------------------------
[mvn-goals] [INFO] Total time:  8.572 s
[mvn-goals] [INFO] Finished at: 2020-08-17T08:20:22Z
[mvn-goals] [INFO] ------------------------------------------------------------------------
...

When the TaskRun runs for the first , it will run loner as it will maven artifacts for the first time and caches the artifacts nexus repository manager. Try running the command again to see it will run a lot quicker.

List build target directory

  • tkn

  • kubectl

tkn task start list-directory \
  --namespace=workspace-auth-demo \
  --param sub-dirs='springboot/target' \
  --workspace name=directory,claimName=tekton-tutorial-sources \
  --use-param-defaults \
  --showlog
kubectl create -n workspace-auth-demo -f list-target-dir-taskrun.yaml
taskrun.tekton.dev/list-directory-xbzpq created

View the task run logs using,

tkn tr logs -f -a $(tkn tr ls -n workspace-auth-demo | awk 'NR==2{print $1}')

A successful command should show the following output:

The output(trimmed for brevity) of the command should be like:

[list-directory] total 18020
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 08:21 maven-status
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 08:21 generated-sources
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 08:21 test-classes
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 08:21 generated-test-sources
[list-directory] drwxr-xr-x    3 root     root          4096 Aug 17 08:21 classes
[list-directory] -rw-r--r--    1 root     root          3748 Aug 17 08:21 tekton-springboot-greeter.jar.original
[list-directory] drwxr-xr-x    2 root     root          4096 Aug 17 08:21 maven-archiver
[list-directory] -rw-r--r--    1 root     root      18421378 Aug 17 08:21 tekton-springboot-greeter.jar
...

Points to Ponder

  • How to mount a ConfigMap as workspace

  • Use the workspace across TaskRuns in this case used the git-clone output in maven build using tekton-tutorial-sources PVC as workspace

Deploy Pipeline

Let us now apply what we learned with workspace to build and deploy the application pipeline as shown:

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: greeter-app-deploy
spec:
  description: >-
    The Pipline to buld and deploy the Hello World Java App https://github.com/redhat-scholars/tekton-tutorial-greeter as Knative Service.
  params:
    - name: image-name (1)
      description: The fully qualified image name e.g example.com/tekton-tutorial/greeter
      default: example.com/tekton-tutorial/greeter
    - name: context-dir
      description: >-
        The application framework to use, value can be either quarkus or springboot
    - name: kn-service-name
      description: The Knative Service name
      default: greeter
    - name: github-repo-url
      description: The GitHub Repo of the Java Application
      default: https://github.com/redhat-scholars/tekton-tutorial-greeter
    - name: github-repo-revision
      description: The GitHub revision to use
      default: staging
  workspaces:
    - name: source (2)
    - name: maven-settings (3)
  tasks:
    - name: clone-sources
      taskRef:
        name: git-clone
      params:
        - name: url
          value: $(params.github-repo-url)
        - name: revision
          value: $(params.github-repo-revision)
        # just to do a fresh clone, as we already have the directory cloned
        # to reuse it we can exlude this step
        - name: deleteExisting
          value: 'true'
      workspaces:
        - name: output
          workspace: source
    - name: build-java-test
      taskRef:
        name: maven
      runAfter:
        - clone-sources
      params:
        - name: GOALS
          value: ['-pl', '$(params.context-dir)', '-B', 'clean', 'test']
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: source
    - name: build-java-app
      taskRef:
        name: maven
      runAfter:
        - build-java-test
      params:
        - name: GOALS
          value:
            [
              '-pl',
              '$(params.context-dir)',
              '-B',
              '-DskipTests',
              'clean',
              'package',
            ]
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: source
    - name: build-java-app-image
      taskRef:
        name: buildah
      runAfter:
        - build-java-app
      params:
        - name: CONTEXT
          value: '$(params.context-dir)'
        - name: IMAGE
          value: '$(params.image-name)'
        # since pushing to internal registry we skip TLS verify
        - name: TLSVERIFY
          value: 'false'
      workspaces:
        - name: source
          workspace: source
    - name: deploy-kn-service
      taskRef:
        name: kn
      runAfter:
        - build-java-app-image
      params:
        - name: ARGS
          value:
            - 'service'
            - 'create'
            - '$(params.kn-service-name)'
            - '--force'
            - '--image=$(params.image-name)@$(tasks.build-java-app-image.results.IMAGE_DIGEST)' (4)
1 The parameters for the Pipeline
2 A workpace named source, we will map it to the PVC`tekton-tutorial-sources` in PipelineRun in upcoming section
3 A workapce named maven-settings, we will map it to ConfigMap maven-settings in the PipelineRun in upcming section
4 The buildah build image task returns a output, the built Image digest via IMAGE_DIGEST. We use the that as part of the --image parameter to kn Task

Create the Pipeline

kubectl apply -n workspace-auth-demo -f greeter-app-deploy.yaml
pipeline.tekton.dev/greeter-app-deploy created

Create Service Account

We need to create the Service Account(SA) that is authorized to Knative Service deployments. To create the SA run:

curl -sSL \
  https://raw.githubusercontent.com/tektoncd/catalog/master/task/kn/0.1/kn-deployer.yaml \
  | yq w - -d0 metadata.namespace workspace-auth-demo \
  | yq w - -d2 subjects.[0].namespace workspace-auth-demo \
  | kubectl apply -f -

The successful command should show an output like:

serviceaccount/kn-deployer-account created
clusterrole.rbac.authorization.k8s.io/kn-deployer created
clusterrolebinding.rbac.authorization.k8s.io/kn-deployer-binding created

Run the Pipeline

  • tkn

  • kubectl

tkn pipeline start greeter-app-deploy \
  --namespace=workspace-auth-demo \
  --serviceaccount=kn-deployer-account \
  --param context-dir='quarkus' \
  --workspace name=maven-settings,config=maven-settings \
  --workspace name=source,claimName=tekton-tutorial-sources \
  --use-param-defaults \
  --showlog
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  generateName: greeter-app-
  labels:
    tekton.dev/pipeline: greeter-app-deploy
spec:
  serviceAccountName: kn-deployer-account (1)
  pipelineRef:
    name: greeter-app-deploy
  params:
    - name: context-dir
      value: quarkus
  workspaces: (2)
    - name: maven-settings
      configmap:
        name: maven-settings
    - name: source
      persistentVolumeClaim:
        claimName: tekton-tutorial-sources
1 The service account to be used with the PipelineRun
2 The Pipeline workspaces mapping
kubectl create -n workspace-auth-demo -f greeter-app-deploy-run.yaml
pipelinerun.tekton.dev/greeter-app-7k9cw created

View the pipeline run logs using,

tkn pr logs -f -a $(tkn pr ls -n workspace-auth-demo | awk 'NR==2{print $1}')

A successfull Pipelinerun should have the greeter application up and running as shown:

kn service describe -n workspace-auth-demo greeter

The command should show an output like :

Name:       greeter
Namespace:  workspace-auth-demo
Age:        21s
URL:        http://greeter.workspace-auth-demo.127.0.0.1.nip.io

Revisions:
  100%  @latest (greeter-ttyqz-1) [1] (21s)
        Image:  kind-registry:5000/rhdevelopers/tekton-tutorial-greeter@sha256:79b8a50a6ef29dbc0df5220de5aea13b8b38b7c4cd407ad074968de8cfbd41b6 (at 79b8a5)

Conditions:
  OK TYPE                   AGE REASON
  ++ Ready                  13s
  ++ ConfigurationsReady    14s
  ++ RoutesReady            13s

Verify Deployed Service

Let us now verify the deployed Knative Service:

KSVC_URL=$(kn service describe -n workspace-auth-demo greeter -o url)

Now do a invoke the service like:

http --body $KSVC_URL

A successfull pipeline deployment should show an output like:

Meeow from Tekton 😺 !! 🚀

Cleanup

kubectl delete -n workspace-auth-demo pipeline --all
kubectl delete -n workspace-auth-demo pr --all
kubectl delete -n workspace-auth-demo tr --all
Leave the namespace, nexus, pvc, confimaps created as part of this chapter, as we will be reusing them in next chapter.