Workspaces

Currently, there is an incompatibility between Tekton pipelines webhook and Minikube. Please expect no logs when running tkn commands .

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 crucial for you to share the filesystem between Tasks and between Steps. The filesystem could typically hold a clone github repostiory, a ConfigMap or a secret.

A Task step and Pipeline task can share a common filesystem via a Tekton workspace. 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 namespace workspace-auth-demo, let’s 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 and cluster 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:

kubectl 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 kubectl -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
  • Minikube

  • OpenShift

The nexus maven repository could be opened using the url:

minikube -p tektontutorial service nexus -n workspace-auth-demo --url
http://192.168.64.27:30102

In OpenShift we can use routes to expose the service if we need to access it from outside the cluster 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:

kubectl 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:

kubectl get -n workspace-auth-demo cm maven-settings -o yaml \
    -o jsonpath='{.data}'

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

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 by following the instructions here for installing OpenShift Serverless.

Follow the instructions for installing the Serverless Operator on the cluster and then follow the instructions for creating Knative Serving.

Check Default Storage Class

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

kubectl get sc
  • Minikube

  • OpenShift

In minikube cluster it should show an output like:

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

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.

kubectl 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:
  generateName: 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: master
  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=master \
  --param deleteExisting=true \
  --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

It will take few minutes for the TaskRun to start.

Watch the status of the Task run using:

tkn tr ls

View the task run logs using,

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

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 master -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/master) 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 Pipeline to build and deploy the Hello World Java App
    https://github.com/redhat-scholars/tekton-tutorial-greeter as Knative
    Service.
  params:
    - description: >-
        The fully qualified image name. If you are running on Minikube please
        use example.com/tekton-tutorial/greeter On OpenShift, use
        image-registry.openshift-image-registry.svc:5000/workspace-auth-demo/tekton-tutorial-greeter
      default: image-registry.openshift-image-registry.svc:5000/workspace-auth-demo/tekton-tutorial-greeter
      name: image-name (1)
      type: string
    - description: >-
        The application framework to use, value can be either quarkus or
        springboot
      name: context-dir
      type: string
    - default: greeter
      description: The Knative Service name
      name: kn-service-name
      type: string
    - default: 'https://github.com/redhat-scholars/tekton-tutorial-greeter'
      description: The GitHub Repo of the Java Application
      name: github-repo-url
      type: string
    - default: staging
      description: The GitHub revision to use
      name: github-repo-revision
      type: string
    - name: storageDriver
      type: string
      description: Use storage driver type vfs if you are running on OpenShift.
      default: vfs
  workspaces:
    - name: source (2)
    - name: maven-settings (3)
  tasks:
    - name: clone-sources
      params:
        - name: url
          value: $(params.github-repo-url)
        - name: revision
          value: $(params.github-repo-revision)
        - name: deleteExisting
          value: 'true'
      taskRef:
        kind: Task
        name: git-clone
      workspaces:
        - name: output
          workspace: source
    - name: build-java-test
      params:
        - name: GOALS
          value:
            - '-pl'
            - $(params.context-dir)
            - '-B'
            - clean
            - test
      runAfter:
        - clone-sources
      taskRef:
        kind: Task
        name: maven
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: source
    - name: build-java-app
      params:
        - name: GOALS
          value:
            - '-pl'
            - $(params.context-dir)
            - '-B'
            - '-DskipTests'
            - clean
            - package
      runAfter:
        - build-java-test
      taskRef:
        kind: Task
        name: maven
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: source
    - name: build-java-app-image
      params:
        - name: CONTEXT
          value: $(params.context-dir)
        - name: IMAGE
          value: $(params.image-name)
        - name: STORAGE_DRIVER
          value: $(params.storageDriver)
        - name: TLSVERIFY
          value: 'false'
      runAfter:
        - build-java-app
      taskRef:
        kind: ClusterTask
        name: buildah
      workspaces:
        - name: source
          workspace: source
    - name: deploy-kn-service
      params:
        - name: ARGS
          value:
            - service
            - create
            - $(params.kn-service-name)
            - '--force'
            - >-
              --image=$(params.image-name)@$(tasks.build-java-app-image.results.IMAGE_DIGEST) (4)
      runAfter:
        - build-java-app-image
      taskRef:
        kind: Task
        name: kn
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. 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/support/kn-deployer.yaml \
  | yq '.metadata.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 \
  --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
# enable this for OpenShift
#    - name: storageDriver
#      value: vfs
  workspaces: (2)
    - name: maven-settings
      configmap:
        name: maven-settings
    - name: source
      persistentVolumeClaim:
        claimName: tekton-tutorial-sources
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 successful 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.192.168.64.7.nip.io

Revisions:
  100%  @latest (greeter-ttyqz-1) [1] (21s)
        Image:  example.com/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:

Tekton 😺 rocks 🚀

Cleanup

Leave the namespace, nexus, pvc, confimaps created as part of this chapter, as we will be reusing them in next chapter.
$TUTORIAL_HOME/bin/cleanup.sh workspace-auth-demo