Bookmark this page

Guided Exercise: Creating CI/CD Workflows by Using Red Hat OpenShift Pipelines

Create multi-step CI/CD workflows for multi-container applications by using Red Hat OpenShift Pipelines.

Outcomes

  • Use OpenShift Pipelines to run common tasks when building an application.

  • Create a pipeline that builds a container image from application source code.

  • Create a custom task for running NPM commands.

  • Use the custom task to perform quality check tasks on the code before building the container image.

  • Manually run pipelines by using the Tekton CLI tool (tkn).

As the student user on the workstation machine, use the lab command to prepare your environment for this exercise, and to ensure that all required resources are available.

[student@workstation ~]$ lab start pipelines-creation

Instructions

  1. The application includes a Containerfile that uses registry.ocp4.example.com:8443/ubi8/nodejs-16:latest as the base image.

    To prevent permission problems in the pipeline execution, make this image public in the internal Quay registry.

    1. Open the Quay website at https://registry.ocp4.example.com:8443 and log in with the developer user and the developer password.

    2. Search for the ubi8/nodejs-16 repository.

    3. In the Repository Visibility section of the ubi8/nodejs-16 settings, make the repository public.

  2. Create a pipeline that builds a container image from the application code.

    1. Log in to OpenShift by using the developer user account.

      [student@workstation ~]$ oc login -u developer -p developer \
      https://api.ocp4.example.com:6443
      Login successful.
      ...output omitted...
    2. Change to the pipelines-creation project.

      [student@workstation ~]$ oc project pipelines-creation
      ...output omitted...
      Already on project "pipelines-creation" on server "https://api.ocp4.example.com:6443".
    3. Change to the directory containing the initial resource manifests.

      [student@workstation ~]$ cd ~/DO288/labs/pipelines-creation
      no output expected
    4. View the pipeline.yaml file. Observe that the pipeline accepts parameters relating to the location of the application source code. Additionally, observe that the pipeline defines a singular workspace called shared, which shares files and state between tasks.

      ---
      apiVersion: tekton.dev/v1beta1
      kind: Pipeline
      metadata:
        name: nodejs-build
      spec:
        workspaces:
          - name: shared
        params:
          - name: IMAGE_NAME
            type: string
            default: "exchange"
          - name: GIT_REPO
            type: string
            default: "https://git.ocp4.example.com/developer/DO288-apps"
          - name: GIT_REVISION
            type: string
            default: "master"
          - name: APP_PATH
            type: string
            default: "apps/pipelines-creation/exchange"
      
        tasks:
          - name: TODO
    5. Update the pipeline by adding a git-clone task that clones the application code from the classroom GitLab repository. The task uses the shared workspace so that later tasks can access the retrieved source code files.

      ...output omitted...
      spec:
        ...output omitted...
        tasks:
          - name: fetch-repository
            taskRef:
              name: git-clone
              kind: ClusterTask
            params:
              - name: url
                value: $(params.GIT_REPO)
              - name: revision
                value: $(params.GIT_REVISION)
              - name: subdirectory
                value: ""
              - name: deleteExisting
                value: "true"
              - name: sslVerify
                value: "false"
            workspaces:
              - name: output
                workspace: shared
    6. Add a buildah task that builds a container image from the application source code. For organization purposes, add this task after the clone task from the previous step.

      ...output omitted...
      spec:
        ...output omitted...
        tasks:
          - name: fetch-repository
            ...output omitted...
      
          - name: build-image
            taskRef:
              name: buildah
              kind: ClusterTask
            params:
              - name: IMAGE
                value: registry.ocp4.example.com:8443/developer/$(params.IMAGE_NAME):latest
              - name: DOCKERFILE
                value: Containerfile
              - name: CONTEXT
                value: $(params.APP_PATH)
              - name: TLSVERIFY
                value: "false"
              - name: SKIP_PUSH
                value: "true"
            runAfter:
              - fetch-repository
            workspaces:
              - name: source
                workspace: shared
  3. Create the pipeline within the cluster and view the pipeline diagram.

    1. Apply the pipeline.yaml manifest file to the cluster to create the pipeline resource object.

      [student@workstation pipelines-creation]$ oc apply -f pipeline.yaml
      pipeline.tekton.dev/nodejs-build created
    2. In a browser window, navigate to the OpenShift web console via the https://console-openshift-console.apps.ocp4.example.com URL. Log in as the developer user and open the developer perspective.

    3. Use the left side menu to navigate to Pipelines > Pipelines and select the nodejs-build pipeline. The pipeline details page shows a diagram illustrating the flow of the tasks within the pipeline.

      Note

      If you do not have a project selected, then select the pipelines-creation project from the Project selection menu at the top of the right pane.

  4. Manually run the pipeline by using the tkn Tekton CLI and view the logs.

    1. In a terminal window, run the pipeline by using the tkn start command. Use the provided volume-template.yaml file to specify the storage for the shared pipeline workspace. This file outlines how the cluster should create a persistent volume claim that can store files as they move between tasks.

      When prompted, accept the defaults for each of the four pipeline parameters by pressing Enter for each one. Note that the name of your pipeline run differs from the following.

      [student@workstation pipelines-creation]$ tkn p start nodejs-build \
      -w name=shared,volumeClaimTemplateFile=volume-template.yaml
      ? Value for param IMAGE_NAME of type string? (Default is exchange) exchange
      ...output omitted...
      PipelineRun started: nodejs-build-run-wh4v5
      ...output omitted...
    2. Use the watch command to wait for the pipeline to complete. The pipeline is done when the STATUS column reads anything other than Running.

      [student@workstation pipelines-creation]$ watch -n 2 tkn p list
      ...output omitted...
      NAME          ...output omitted...  DURATION   STATUS
      nodejs-build  ...output omitted...  2m51s      Succeeded

      After the pipeline finishes, stop the watch command by pressing Ctrl+c.

    3. View the logs for the pipeline to observe that git cloned the code repository and that the container image was built successfully.

      [student@workstation pipelines-creation]$ tkn p logs nodejs-build
      ...output omitted...
      {"level":"info" ... "Successfully cloned ... redhattraining/DO288-apps ..."}
      ...output omitted...
      Successfully tagged registry.ocp4.example.com:8443/developer/exchange:latest
      ...output omitted...
  5. Create a custom task for running NPM commands and apply it to the cluster.

    1. View the npm-task.yaml file that defines a task with a single step. Observe that the workspaces and params sections define storage and task parameters, respectively. The task uses the ARGS command within its step to run specified NPM commands. Additionally, the task defines an output result to store the output of the task.

      ---
      apiVersion: tekton.dev/v1beta1
      kind: Task
      metadata:
        name: npm
      spec:
        workspaces:
          - name: source
        results:
          - name: output
        params:
          - name: CONTEXT
            type: string
            default: "."
          - name: ARGS
            type: string
          - name: NODE_IMAGE
            type: string
            default: "registry.access.redhat.com/ubi8/nodejs-16:latest"
        steps:
          - name: TODO
    2. Update the file to add a step that runs the command provided by the ARGS parameter. The script uses the tee command to store the output of the command in the output result.

      spec:
        ...output omitted...
        steps:
          - name: npm-run
            image: $(params.NODE_IMAGE)
            script: |
              npm $(params.ARGS) | tee $(results.output.path)
            workingDir: $(workspaces.source.path)/$(params.CONTEXT)
            env:
              - name: CI
                value: "true"
            securityContext:
              runAsNonRoot: true
              runAsUser: 65532

      Note

      The securityContext section instructs the pod to run the command as a regular user. This is to match the configured user in the cluster tasks that are used in the pipeline.

    3. Apply the task manifest to the cluster within the pipelines-creation project.

      [student@workstation pipelines-creation]$ oc apply -f npm-task.yaml
      task.tekton.dev/npm created
  6. Update the pipeline so that it runs NPM commands via the custom NPM task and then run the pipeline.

    1. Update the pipeline.yaml file to add a task that runs npm install with the custom NPM task to fetch Node.js dependencies for the application. This task goes between the fetch-repository and build-image tasks. The file should match the following excerpt.

      ---
      apiVersion: tekton.dev/v1beta1
      kind: Pipeline
      metadata:
        name: nodejs-build
      spec:
        ...output omitted...
        tasks:
          - name: fetch-repository
            ...output omitted...
      
          - name: npm-install
            taskRef:
              name: npm
              kind: Task
            workspaces:
              - name: source
                workspace: shared
            params:
              - name: CONTEXT
                value: $(params.APP_PATH)
              - name: ARGS
                value: install --no-package-lock
            runAfter:
              - fetch-repository
      
          - name: build-image
            ...output omitted...

      Note

      Because YAML syntax is sensitive to indentation, make sure that your file exactly matches the preceding excerpt.

    2. Similar to the previous step, add tasks that run the application tests and a linter to check for code quality. These tasks go between the npm-install and build-image steps and have the same indentation level.

          - name: npm-test
            taskRef:
              name: npm
              kind: Task
            workspaces:
              - name: source
                workspace: shared
            params:
              - name: CONTEXT
                value: $(params.APP_PATH)
              - name: ARGS
                value: test
            runAfter:
              - npm-install
      
          - name: npm-lint
            taskRef:
              name: npm
              kind: Task
            workspaces:
              - name: source
                workspace: shared
            params:
              - name: CONTEXT
                value: $(params.APP_PATH)
              - name: ARGS
                value: run lint
            runAfter:
              - npm-install
    3. Add a task that uses the custom NPM task to retrieve the version of the application. This task goes between the npm-lint and build-image tasks and has the same indentation level.

          - name: app-version
            taskRef:
              name: npm
              kind: Task
            workspaces:
              - name: source
                workspace: shared
            params:
              - name: CONTEXT
                value: $(params.APP_PATH)
              - name: ARGS
                value: version|grep exchange|cut -d\' -f2|tr -d '\n'
            runAfter:
              - fetch-repository
    4. Update the build-image task so that it runs after the quality checks and tags the image with the version number. The build-image should look like the following excerpt.

          - name: build-image
            taskRef:
              name: buildah
              kind: ClusterTask
            params:
              - name: IMAGE
                value: registry.ocp4.example.com:8443/developer/$(params.IMAGE_NAME):$(tasks.app-version.results.output)
              - name: DOCKERFILE
                value: Containerfile
              - name: CONTEXT
                value: $(params.APP_PATH)
              - name: TLSVERIFY
                value: "false"
              - name: SKIP_PUSH
                value: "true"
            runAfter:
              - npm-test
              - npm-lint
              - app-version
            workspaces:
              - name: source
                workspace: shared
    5. Update the pipeline in the cluster by applying the updated pipeline.yaml file.

      [student@workstation pipelines-creation]$ oc apply -f pipeline.yaml
      pipeline.tekton.dev/nodejs-build configured
    6. In the browser window, refresh the pipeline details page to observe the updated pipeline diagram.

      Notice that the diagram matches the ordering of the tasks as specified by the runAfter fields in the pipeline manifest.

  7. Run the updated pipeline and view the logs.

    1. In a terminal window, run the pipeline by using the same tkn command as before.

      When prompted, accept the defaults for each of the four pipeline parameters by pressing Enter for each one. Note that the name of your pipeline run differs from the following.

      [student@workstation pipelines-creation]$ tkn p start nodejs-build \
      -w name=shared,volumeClaimTemplateFile=volume-template.yaml
      ? Value for param IMAGE_NAME of type string? (Default is exchange) exchange
      ...output omitted...
      PipelineRun started: nodejs-build-run-4nspb
      ...output omitted...
    2. Use the watch command to wait for the pipeline to complete. Because there are more tasks, the pipeline might take longer to finish.

      [student@workstation pipelines-creation]$ watch -n 2 tkn p list
      ...output omitted...
      NAME          ...output omitted...  DURATION   STATUS
      nodejs-build  ...output omitted...  3m25s      Succeeded

      After the pipeline finishes, stop the watch command by pressing Ctrl+c.

    3. View the logs for the pipeline to observe that the new tasks run in addition to the original two. Also notice that the application version number is used in the container image tag. Because there is now more than one run of the pipeline, press Enter to select the latest instance when prompted.

      [student@workstation pipelines-creation]$ tkn p logs nodejs-build
      ...output omitted...
      {"level":"info" ... "Successfully cloned ... redhattraining/DO288-apps ..."}
      ...output omitted...
      1.0.0
      ...output omitted...
      > exchange@1.0.0 test
      > mocha tests
      ...output omitted...
        5 passing (10ms)
      ...output omitted...
      > exchange@1.0.0 lint
      > eslint .
      ...output omitted...
      Successfully tagged registry.ocp4.example.com:8443/developer/exchange:1.0.0
      ...output omitted...

Finish

On the workstation machine, use the lab command to complete this exercise. This step is important to ensure that resources from previous exercises do not impact upcoming exercises.

[student@workstation ~]$ lab finish pipelines-creation

Revision: do288-4.12-0d49506