Lab 1: Application CI Pipeline

Overview

Create a Tekton CI pipeline that clones your application source, builds and tests it, retrieves registry credentials from Vault, and pushes the container image. Then wire up Tekton Triggers to fire the pipeline automatically when code is pushed to GitLab.

Pipeline Workspace and ServiceAccount

Create a workspace PVC and a ServiceAccount for the pipeline:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pipeline-workspace-pvc
  namespace: <your_namespace>
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: pipeline
  namespace: <your_namespace>

Apply them:

oc apply -f pipeline-workspace.yaml

Retrieve Registry Credentials from Vault

Create a Tekton Task that authenticates to Vault using the Kubernetes auth method configured in the Supporting Services section and writes registry credentials to the workspace:

apiVersion: tekton.dev/v1
kind: Task
metadata:
  name: vault-fetch-registry-creds
  namespace: <your_namespace>
spec:
  workspaces:
    - name: source
  results:
    - name: registry-server
    - name: registry-username
    - name: registry-password
  steps:
    - name: fetch
      image: quay.io/curl/curl:latest
      script: |
        #!/bin/sh
        set -e

        # Authenticate to Vault using ServiceAccount token
        VAULT_ADDR="http://vault.vault.svc:8200"
        SA_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

        VAULT_TOKEN=$(curl -s --request POST \
          "${VAULT_ADDR}/v1/auth/kubernetes/login" \
          --data "{\"role\":\"pipeline\",\"jwt\":\"${SA_TOKEN}\"}" \
          | grep -o '"client_token":"[^"]*"' | cut -d'"' -f4)

        # Fetch registry credentials
        CREDS=$(curl -s --header "X-Vault-Token: ${VAULT_TOKEN}" \
          "${VAULT_ADDR}/v1/secret/data/registry")

        echo "${CREDS}" | grep -o '"server":"[^"]*"' | cut -d'"' -f4 \
          | tr -d '\n' > $(results.registry-server.path)
        echo "${CREDS}" | grep -o '"username":"[^"]*"' | cut -d'"' -f4 \
          | tr -d '\n' > $(results.registry-username.path)
        echo "${CREDS}" | grep -o '"password":"[^"]*"' | cut -d'"' -f4 \
          | tr -d '\n' > $(results.registry-password.path)

Create the Pipeline

Define the CI pipeline with four tasks: clone, build/test, fetch credentials, and build/push the container image:

apiVersion: tekton.dev/v1
kind: Pipeline
metadata:
  name: parasol-ci
  namespace: <your_namespace>
spec:
  params:
    - name: git-url
      type: string
    - name: git-revision
      type: string
      default: main
    - name: image-name
      type: string
  workspaces:
    - name: shared-workspace
  tasks:
    - name: clone
      taskRef:
        name: git-clone
        kind: ClusterTask
      params:
        - name: url
          value: $(params.git-url)
        - name: revision
          value: $(params.git-revision)
      workspaces:
        - name: output
          workspace: shared-workspace

    - name: build-and-test
      runAfter: [clone]
      taskRef:
        name: maven
        kind: ClusterTask
      params:
        - name: GOALS
          value: ["package", "-DskipTests=false"]
      workspaces:
        - name: source
          workspace: shared-workspace
        - name: maven-settings
          workspace: shared-workspace

    - name: fetch-creds
      runAfter: [clone]
      taskRef:
        name: vault-fetch-registry-creds
      workspaces:
        - name: source
          workspace: shared-workspace

    - name: build-image
      runAfter: [build-and-test, fetch-creds]
      taskRef:
        name: buildah
        kind: ClusterTask
      params:
        - name: IMAGE
          value: $(params.image-name):$(params.git-revision)
      workspaces:
        - name: source
          workspace: shared-workspace
git-clone, maven, and buildah are ClusterTasks provided by OpenShift Pipelines. Run tkn clustertask list to verify they are available.

Apply the tasks and pipeline:

oc apply -f vault-fetch-task.yaml
oc apply -f parasol-ci-pipeline.yaml

Test the Pipeline Manually

Run the pipeline once to verify it works before adding webhooks:

tkn pipeline start parasol-ci \
  --param git-url=https://<gitlab_host>/parasol-insurance \
  --param git-revision=main \
  --param image-name=image-registry.openshift-image-registry.svc:5000/<your_namespace>/parasol-insurance \
  --workspace name=shared-workspace,claimName=pipeline-workspace-pvc \
  --serviceaccount pipeline \
  --showlog

Watch the logs to confirm all tasks complete successfully.

Set Up Webhooks with Tekton Triggers

Create the trigger resources so the pipeline runs automatically when code is pushed to GitLab.

TriggerBinding

Maps fields from the GitLab webhook payload to pipeline parameters:

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerBinding
metadata:
  name: gitlab-push-binding
  namespace: <your_namespace>
spec:
  params:
    - name: git-url
      value: $(body.repository.git_http_url)
    - name: git-revision
      value: $(body.checkout_sha)

TriggerTemplate

Creates a PipelineRun when triggered:

apiVersion: triggers.tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
  name: gitlab-push-template
  namespace: <your_namespace>
spec:
  params:
    - name: git-url
    - name: git-revision
  resourcetemplates:
    - apiVersion: tekton.dev/v1
      kind: PipelineRun
      metadata:
        generateName: parasol-ci-
      spec:
        pipelineRef:
          name: parasol-ci
        params:
          - name: git-url
            value: $(tt.params.git-url)
          - name: git-revision
            value: $(tt.params.git-revision)
          - name: image-name
            value: image-registry.openshift-image-registry.svc:5000/<your_namespace>/parasol-insurance
        workspaces:
          - name: shared-workspace
            persistentVolumeClaim:
              claimName: pipeline-workspace-pvc
        taskRunTemplate:
          serviceAccountName: pipeline

EventListener

Exposes an HTTP endpoint that GitLab can send webhooks to:

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: gitlab-listener
  namespace: <your_namespace>
spec:
  serviceAccountName: pipeline
  triggers:
    - name: gitlab-push
      bindings:
        - ref: gitlab-push-binding
      template:
        ref: gitlab-push-template

Apply all trigger resources:

oc apply -f trigger-binding.yaml
oc apply -f trigger-template.yaml
oc apply -f event-listener.yaml

Expose the EventListener

Create a route so GitLab can reach the EventListener:

oc expose svc el-gitlab-listener -n <your_namespace>

Get the webhook URL:

echo "$(oc get route el-gitlab-listener -n <your_namespace> -o jsonpath='{.spec.host}')"

Configure GitLab

  1. In GitLab, go to your repository’s Settings  Webhooks

  2. Add a new webhook:

  3. Click Add webhook

  4. Click Test and select Push events to send a test payload

Verify the Pipeline

Push a change to your repository and confirm:

# Check for new pipeline runs
tkn pipelinerun list -n <your_namespace>

# Follow the latest run
tkn pipelinerun logs -f -n <your_namespace>

Verify the image was pushed:

oc get imagestream parasol-insurance -n <your_namespace>

You should see the image tagged with the commit SHA.

Next Steps