Skip to content

Tekton Lab

Pre-requisites

Make sure your environment is properly setup.

Check the Environment Setup page for your setup.

Create Target Namespace

  • Set the environment variable NAMESPACE to tekton-demo-{initials}, if you open a new terminal remember to set this environment again
    export NAMESPACE=tekton-demo-{initials}
    
  • Create the namespace using the variable NAMESPACE
    oc create namespace $NAMESPACE
    

Pipeline Resources

Pipeline Resource Creation

Create a PipelineResource of type git

  • Create the file git.yaml
    apiVersion: tekton.dev/v1alpha1
    kind: PipelineResource
    metadata:
      name: source
    spec:
      type: git
      params:
        - name: revision
          value: master
        - name: url
          value: https://github.com/ibm-cloud-architecture/cloudnative_sample_app
    
    Verify the file content
    cat git.yaml
    

Create a PipelineResource of type image

  • Set the environment variable DOCKER_USERNAME to your dockerhub account, replace <REPLACEME> with your docker username, keep the quotes
    export DOCKER_USERNAME='<REPLACEME>'
    
  • Create the file image.yaml
    apiVersion: tekton.dev/v1alpha1
    kind: PipelineResource
    metadata:
      name: image
    spec:
      type: image
      params:
        - name: url
          value: index.docker.io/$DOCKER_USERNAME/cloudnative_sample_app
    
    Verify the file content, and make sure the url value is valid with your dockerhub username replaced
    cat image.yaml
    

Pipeline Resources deployment

  • Each pipeline resource has:
  • name: the name using which it will be referred in other places
  • type: the type of the pipeline resource, in this example we have two types
  • git - this type of resource refers to a GitHub repository
  • image - this type of resource is linux container image
  • params: each type can have one or more parameters that will be used to configure the underlying type. In the above example for the git-source pipeline resource, the parameters url and revision are used to identify the GitHub repository url and revision of the sources respectively.

  • More details on other types of pipeline resource types is available here.

  • Create the pipeline resources using the command:

    oc apply -f git.yaml -n $NAMESPACE
    oc apply -f image.yaml -n $NAMESPACE
    

Verify the deployed resource

  • Use the Tekton cli to list the created resources

    tkn res ls -n $NAMESPACE
    

  • The above command should list two resources as shown below:

    NAME                        TYPE    DETAILS
    source                      git     url: https://github.com/ibm-cloud-architecture/cloudnative_sample_app
    image                       image   url: index.docker.io/yourdockerhubusername/cloudnative_sample_app
    
    Use the command help via tkn res --help

  • Use the Tekton cli to describe the git resource
    tkn res describe source -n $NAMESPACE
    
    The output should look like this:
    Name:                    source
    Namespace:               tekton-demo
    PipelineResource Type:   git
    
    Params
    NAME       VALUE
    revision   master
    url        https://github.com/ibm-cloud-architecture/cloudnative_sample_app
    
    Secret Params
    No secret params
    
  • Use the Tekton cli to describe the git resource
    tkn res describe image -n $NAMESPACE
    
    The output should look like this:
    Name:                    image
    Namespace:               tekton-demo
    PipelineResource Type:   image
    
    Params
    NAME   VALUE
    url    index.docker.io/myusername/cloudnative_sample_app
    
    Secret Params
    No secret params
    

Tasks

Task Creation

  • Create the below yaml files.
  • The following snippet shows what a Tekton Task YAML looks like:
  • Create the file test_task.yaml

    apiVersion: tekton.dev/v1alpha1
    kind: Task
    metadata:
      name: java-test
    spec:
      inputs:
        resources:
          - name: source
            type: git
        params:
          - name: maven-image
            type: string
            default: maven:3.3-jdk-8
      steps:
        - name: test
          image: $(inputs.params.maven-image)
          workingdir: $(inputs.resources.source.path)
          command: ["/bin/bash"]
          args:
            - -c
            - |
              set -e
              mvn test
              echo "tests passed with rc=$?"
          volumeMounts:
            - name: m2-repository
              mountPath: /.m2
      volumes:
        - name: m2-repository
          emptyDir: {}
    

  • Each Task has the following:

  • name - the unique name using which the task can be referred

  • inputs - the inputs to the task
  • resources - the pipeline resources that will be used in the task e.g. git-source
  • name - the name of the input resource using which it can be referenced and bound via TaskRun
  • type - the type of the input resource, typically the pipeline resource type
  • params - the parameters that will be used in the task steps. Each parameter has
  • name - the name of the parameter
  • description - the description of the parameter
  • default - the default value of parameter

  • Note: The TaskRun or PipelineRun could override the parameter values, if no parameter value is passed then the default value will be used.

  • outputs the pipeline resource that will end artifact of the task. In the above example the build will produce a container image artifact.

  • resources - the pipeline resources that will be used in the task e.g. builtImage
  • name - the name of the input resource using which it can be referenced and bound via TaskRun
  • type - the type of the input resource, typically the pipeline resource type
  • steps - One or more sub-tasks that will be executed in the defined order. The step has all the attributes like a Pod spec
  • stepTemplate - when there is a need to have similar container configuration across all steps of a the task, we can have them defined in the stepTemplate, the task steps will inherit them implicitly in all steps. In the example above we define the resources and securityContext for all the steps
  • volumes - the task can also mount external volumes using the volumes attribute.

  • The parameters that were part of the spec inputs params can be used in the steps using the notation $(<variable-name>).

Task Deploy

  • The application test task could be created using the command:

    oc apply -f test_task.yaml -n $NAMESPACE
    

  • We will use the Tekton cli to inspect the created resources

    tkn task ls -n $NAMESPACE
    

  • The above command should list one Task as shown below:

    NAME        AGE
    java-test   22 seconds ago
    

TaskRun

  • The TaskRun is used to run a specific task independently. In the following section we will run the build-app task created in the previous step

TaskRun Creation

  • The following snippet shows what a Tekton TaskRun YAML looks like:
  • Create the file test_taskrun.yaml
    apiVersion: tekton.dev/v1alpha1
    kind: TaskRun
    metadata:
      generateName: test-task-run-
    spec:
      taskRef:
        name: java-test
      inputs:
        resources:
          - name: source
            resourceRef:
              name: source
    
  • generateName - since the TaskRun can be run many times, in order to have unique name across the TaskRun ( helpful when checking the TaskRun history) we use this generateName instead of name. When Kubernetes sees generateName it will generate unique set of characters and suffix the same to build-app-, similar to how pod names are generated
  • taskRef - this is used to refer to the Task by its name that will be run as part of this TaskRun. In this example we use build-app Task.
  • As described in the earlier section that the Task inputs and outputs could be overridden via TaskRun.
  • In this example we make the Task Run spec > inputs > resources > source to refer to pipeline resource source via the resourceRef.
  • The application test task(java-maven-test) could be run using the command:
    oc create -n $NAMESPACE -f test_taskrun.yaml
    
  • Note - As tasks will use generated name, never use oc apply -f test_taskrun.yaml
  • We will use the Tekton cli to inspect the created resources:

    tkn tr ls -n $NAMESPACE
    
    The above command should list one TaskRun as shown below:
    NAME                       STARTED        DURATION   STATUS
    test-task-run-q6s8c        1 minute ago   ---        Running(Pending)
    
    Note - It will take few seconds for the TaskRun to show status as Running as it needs to download the container images.

  • To check the logs of the Task Run using the tkn:

    tkn tr logs -f -a -n $NAMESPACE
    
    Note - Each task step will be run within a container of its own. The -f or -a allows to tail the logs from all the containers of the task. For more options run tkn tr logs --help

  • If you see the TaskRun status as Failed or Error use the following command to check the reason for error:
    tkn tr describe <taskrun-name> -n $NAMESPACE
    
  • If it is successful, you will see something like below.
    tkn tr ls -n $NAMESPACE
    
    The above command should list one TaskRun as shown below:
    NAME                  STARTED          DURATION     STATUS
    test-task-run-q6s8c   47 seconds ago   34 seconds   Succeeded
    

Creating additional tasks and deploying them

  • Create a Task to build a container image and push to the registry
  • This task will be later used by the pipeline.
  • Download the task file task-buildah.yaml to build the image, push the image to the registry:
  • Create the buildah Task using the file and the command:
    oc apply -f task-buildah.yaml -n $NAMESPACE
    
  • Use the Tekton cli to inspect the created resources
    tkn task ls -n $NAMESPACE
    
  • The above command should list one Task as shown below:

    NAME              AGE
    buildah            4 seconds ago
    java-test         46 minutes ago
    

  • To access the docker registry, create the required secret as follows.

  • Create the environment variables to be use, replace with real values and include the single quotes:
    export DOCKER_USERNAME='<DOCKER_USERNAME>'
    
    export DOCKER_PASSWORD='<DOCKER_PASSWORD>'
    
    export DOCKER_EMAIL='<DOCKER_EMAIL>'
    
  • Run the following command to create a secret regcred in the namespace NAMESPACE

    oc create secret docker-registry regcred \
      --docker-server=https://index.docker.io/v1/ \
      --docker-username=${DOCKER_USERNAME} \
      --docker-password=${DOCKER_PASSWORD} \
      --docker-email=${DOCKER_EMAIL} \
      -n ${NAMESPACE}
    
    Before creating, replace the values as mentioned above. Note: If your docker password contains special characters in it, please enclose the password in double quotes or place an escape character before each special character.

  • (Optional) Only if you have problems with the credentials you can recreate it, but you have to deleted first

    oc delete secret regcred -n $NAMESPACE
    

  • Before we run the Task using TaskRun let us create the Kubernetes service account and attach the needed permissions to the service account, the following Kubernetes resource defines a service account called pipeline in namespace $NAMESPACE who will have administrative role within the $NAMESPACE namespace.
  • Create the file sa.yaml
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: pipeline
    secrets:
      - name: regcred
    
  • Create sa role as follows:

    oc apply -n $NAMESPACE -f sa.yaml
    

  • Lets create a Task Run for buildah Task using the tkn CLI passing the inputs, outputs and service account

    tkn task start buildah \
      -i source=source \
      -i image=image \
      -s pipeline \
      -n $NAMESPACE
    
    The task will start and logs will start printing automatically
    Taskrun started: buildah-run-vvrg2
    Waiting for logs to be available...
    

  • Verify the status of the Task Run

    tkn tr ls -n $NAMESPACE
    
    Output should look like this
    NAME                  STARTED          DURATION     STATUS
    buildah-run-zbsrv      2 minutes ago    1 minute     Succeeded
    

  • To clean up all Pods associated with all Task Runs, delete all the task runs resources
    oc delete taskrun --all -n $NAMESPACE
    
  • (Optional) Instead of starting the Task via tkn task start you could also use yaml TaskRun
    apiVersion: tekton.dev/v1alpha1
    kind: TaskRun
    metadata:
      generateName: buildah-task-run-
    spec:
      serviceAccountName: pipeline
      taskRef:
        name: buildah
      inputs:
        resources:
          - name: source
            resourceRef:
              name: source
          - name: image
            resourceRef:
              name: image
    
    Then create the TaskRun with generateName
    oc create -f taskrun.yaml -n $NAMESPACE
    
    Follow the logs with:
    tkn tr logs -f -n $NAMESPACE
    

Pipelines

Pipeline Creation

  • Pipelines allows to start multiple Tasks, in parallel or in a certain order

  • Create the file pipeline.yaml, the Pipeline contains two Tasks

    apiVersion: tekton.dev/v1alpha1
    kind: Pipeline
    metadata:
      name: test-build-push
    spec:
      resources:
        - name: source
          type: git
        - name: image
          type: image
      tasks:
        - name: test
          taskRef:
            name: java-test
          resources:
            inputs:
              - name: source
                resource: source
        - name: build-push
          taskRef:
            name: buildah
          runAfter: [test]
          resources:
            inputs:
              - name: source
                resource: source
              - name: image
                resource: image
    

  • Pipeline defines a list of Tasks to execute in order, while also indicating if any outputs should be used as inputs of a following Task by using the from field and also indicating the order of executing (using the runAfter and from fields). The same variable substitution you used in Tasks is also available in a Pipeline.

  • Create the Pipeline using the command:
    oc apply -f pipeline.yaml -n $NAMESPACE
    
  • Use the Tekton cli to inspect the created resources
    tkn pipeline ls -n $NAMESPACE
    
    The above command should list one Pipeline as shown below:
     NAME              AGE              LAST RUN   STARTED   DURATION   STATUS
    test-build-push   31 seconds ago   ---        ---       ---        ---
    

PipelineRun

PipelineRun Creation

  • To execute the Tasks in the Pipeline, you must create a PipelineRun. Creation of a PipelineRun will trigger the creation of TaskRuns for each Task in your pipeline.
  • Create the file pipelinerun.yaml
    apiVersion: tekton.dev/v1alpha1
    kind: PipelineRun
    metadata:
      generateName: test-build-push-run-
    spec:
      serviceAccountName: pipeline
      pipelineRef:
        name: test-build-push
      serviceAccountName: pipeline
      resources:
        - name: source
          resourceRef:
            name: source
        - name: image
          resourceRef:
            name: image
    
    serviceAccount - it is always recommended to have a service account associated with PipelineRun, which can then be used to define fine grained roles.
  • Create the PipelineRun using the command:
    oc create -f pipelinerun.yaml -n $NAMESPACE
    
  • We will use the Tekton cli to inspect the created resources

    tkn pipelinerun ls -n $NAMESPACE
    

  • The above command should list one PipelineRun as shown below:

    NAME                        STARTED         DURATION   STATUS
    test-build-push-run-c7zgv   8 seconds ago   ---        Running
    

  • Wait for few minutes for your pipeline to complete all the tasks. If it is successful, you will see something like below.

    tkn pipeline ls -n $NAMESPACE
    
    NAME              AGE              LAST RUN                    STARTED         DURATION    STATUS
    test-build-push   33 minutes ago   test-build-push-run-c7zgv   2 minutes ago   2 minutes   Succeeded
    

  • Run again the pipeline ls command

    tkn pipelinerun ls -n $NAMESPACE
    
    NAME                        STARTED         DURATION    STATUS
    test-build-push-run-c7zgv   2 minutes ago   2 minutes   Succeeded
    
    If it is successful, go to your container registry account and verify if you have the cloudnative_sample_app image pushed.

  • (Optional) Run the pipeline again using the tkn CLI

    tkn pipeline start test-build-push \
      -r source=source \
      -r image=image \
      -s pipeline \
      -n $NAMESPACE
    

  • (Optional) Re-run the pipeline using last pipelinerun values
    tkn pipeline start test-build-push --last -n $NAMESPACE
    

Deploy Application

  • Deploy the app as follows:
    export APP_YAML_URL='https://raw.githubusercontent.com/ibm-cloud-architecture/cloudnative_sample_app_deploy/master/yamls/'
    oc apply -n $NAMESPACE -f $APP_YAML_URL/deployment.yaml
    oc apply -n $NAMESPACE -f $APP_YAML_URL/service.yaml
    
  • Replace the default image with the new image you deployed using Tekton
  • Replace <DOCKER_USERNAME> with your username
    export DOCKER_USERNAME='<DOCKER_USERNAME>'
    
  • Replace <SHORT_GIT_HASH> with the tag of the image you push to the registry, you can go the registry Web UI and verify the tag value.
    export SHORT_GIT_HASH='<SHORT_GIT_HASH>'
    
  • Set the environment variable IMAGE_URL to the new image url value sing the two previous environment variables DOCKER_USERNAME and SHORT_GIT_HASH
    export IMAGE_URL=docker.io/${DOCKER_USERNAME}/cloudnative_sample_app:${SHORT_GIT_HASH}
    echo $IMAGE_URL
    
  • Replace the image on the deployment
    oc set image \
      deployment/cloudnativesampleapp-deployment \
      \*=${IMAGE_URL} \
      -n $NAMESPACE --record
    
  • Verify the image is set
    oc get deploy \
      cloudnativesampleapp-deployment \
      -o jsonpath='{.spec.template.spec.containers[0].image}' \
      -n $NAMESPACE
    
  • Verify if the pods are running:
    oc get pods -n $NAMESPACE -l app=cloudnativesampleapp-selector
    
    NAME                          READY   STATUS      RESTARTS   AGE
    cloudnativesampleapp...       1/1     Running     0          82s
    
  • Retrieve the service NodePort:
    oc describe svc cloudnativesampleapp-service -n $NAMESPACE | grep NodePort
    
    Type:                     NodePort
    NodePort:                 http  30632/TCP
    
    In this instance the NodePort assigned is 30632
  • Get the External Public IP as follows:
    crc ip
    
    192.168.64.30
    
  • Now access the compose the URL of the App using IP and NodePort
    export APP_EXTERNAL_IP=$(crc ip)
    export APP_NODEPORT=$(oc get svc cloudnativesampleapp-service -n $NAMESPACE -o jsonpath='{.spec.ports[0].nodePort}')
    export APP_URL="http://${APP_EXTERNAL_IP}:${APP_NODEPORT}/greeting?name=Carlos"
    echo $APP_URL
    
    http://192.168.64.30:30632//greeting?name=Carlos
    
  • Now access the app from terminal or browser
    curl $APP_URL
    
    open $APP_URL