CLOUD & MANAGED SERVICES
18/01/2024 • Ugur Akkar

Tekton: Het Krachtige Open Source CI/CD-Framework

Tekton, een krachtig en flexibel open source-framework, biedt ontwikkelaars de mogelijkheid om CI/CD-systemen te bouwen, testen en implementeren, zowel in de cloud als on-premise. In dit artikel duiken we dieper in op wat Tekton is, de voordelen ervan, en hoe grote bedrijven zoals Google, Elastic, en RedHat er gebruik van maken.

Wat is Tekton?

Tekton is een open source-framework ontworpen voor het ontwikkelen van Continuous Integration en Continuous Deployment (CI/CD) systemen. Het stelt ontwikkelaars in staat om naadloos te werken met zowel cloud providers als on-premise infrastructuren. Met Tekton kunnen ontwikkelaars pipelines bouwen, testen en implementeren, en profiteren van een flexibele en uitbreidbare architectuur.

Voordelen van Tekton

CloudNative Ecosysteem

Tekton maakt gebruik van Kubernetes-clusters voor het beheren van resources en componenten. Hierdoor kan Tekton op verschillende cloud providers draaien en lokaal worden ingezet.

Kubernetes Custom Resources

Alle resources voor het opbouwen van een pipeline zijn beschikbaar als Kubernetes Custom Resources. Dit betekent dat de pipelines volledig kunnen worden beschreven in YAML-bestanden, waardoor GitOps principes kunnen worden toegepast voor een geautomatiseerd en versiebeheerd buildproces.

Uitbreidbaarheid

De core van Tekton is eenvoudig uit te breiden met extra componenten, zoals Tekton Triggers of Dashboards. Deze componenten bevinden zich niet direct in de core, waardoor de core compact blijft en minimale resources gebruikt.

Gemakkelijk Onderhoud

Dankzij de modulaire opzet van Tekton kan de core afzonderlijk worden geüpgraded zonder impact op de builds. Doordat de core en de uitbreidingen gescheiden zijn, wordt onderhoud een stuk eenvoudiger.

Schaalbaarheid

Als een CloudNative oplossing kan Tekton gemakkelijk worden geschaald voor high availability, waardoor het geschikt is voor uiteenlopende projecten en omgevingen.

Tekton Friends: Grote Bedrijven die Tekton Omarmen

Verschillende toonaangevende IT-bedrijven hebben Tekton geadopteerd en dragen via een GitHub repository actief bij aan de ontwikkeling ervan.

Enkele opmerkelijke bedrijven zijn:

  • Google: De initiatiefnemer van het Tekton-project en een actieve ontwikkelaar.
  • Elastic: De volledige Elastic stack wordt gebouwd en uitgebracht met behulp van het Tekton-ecosysteem.
  • RedHat: Zorgt ervoor dat het Tekton-ecosysteem naadloos werkt op OpenShift en levert een toegewijde bijdrage aan het Tekton-project.

Tekton Eco-systeem: Componenten en Functionaliteiten

Het Tekton-ecosysteem bestaat uit verschillende componenten die zowel samen als afzonderlijk kunnen worden ingezet. Hieronder volgt een uitleg van enkele belangrijke componenten.

1. Tekton Pipelines

Tekton Pipelines maakt gebruik van Kubernetes Custom Resources voor het definiëren van build processen. Met het 'pipeline-as-code'-principe kunnen ontwikkelaars pipelines in YAML-bestanden beschrijven en versiebeheer toepassen met GitOps.

Doordat we elke resource in Git kunnen opslaan, hebben we de mogelijkheid om te werken op basis van versies met diverse Pipeline-resources. Daarnaast kunnen we het GitOps-principe toepassen, waarbij de resource automatisch wordt ingezet op de cluster. Hierdoor kunnen we erop vertrouwen dat we altijd de juiste en meest recente versie in de cluster hebben, en dat er geen handmatige manipulaties van de Tekton-resources zullen plaatsvinden.
Een Pipeline is een subset van taken die in een bepaalde volgorde worden uitgevoerd.

Laten we als voorbeeld een Pipeline nemen voor het bouwen van een Docker-image:

Laten we dit nu visueel weergeven.

  • Elke uitvoering van een pipeline wordt een PipelineRun genoemd.
  • Elke uitvoering van een task wordt een TaskRun genoemd.

In de pipeline definiëren we de tasks. Deze tasks zijn tevens individuele Tekton Custom Resources die in Kubernetes zitten. Bij het uitvoeren van de pipeline raadpleegt Tekton de gedefinieerde resource en gebruikt deze om zijn taken uit te voeren.

Tasks zijn redelijk flexibel. Je kan een task herhaaldelijk gebruiken binnen een pipeline, maar ook in andere pipelines. Tasks kunnen zelfs worden aangepast of zelf geschreven zonder dat daarvoor plugins of aanvullende resources apart geïnstalleerd moeten worden. Een task kan eenvoudig een container image zijn die wordt uitgevoerd met bepaalde parameters.

Door versiebeheer toe te passen op tasks wordt het eenvoudig om voor elk specifiek doel een andere versie van de task te gebruiken. Hierdoor is het niet noodzakelijk om alle Pipelines te upgraden wanneer een task wordt bijgewerkt.

Wat wint een Developer hiermee?

  • Aanpasbaarheid: Alle resources van Tekton is aanpasbaar. Developers kunnen erg gedetailleerd hun Pipelines en Tasks schrijven.
  • Herbruikbaarheid: Pipeline en/of Tasks kunnen meerdere keren gebruikt worden in dezelfde Pipeline, maar ook in andere Pipelines. 
  • Uitbreidbaarheid: Tekton beschikt over een catalogus waar al een aantal meest gebruikte tasks vooraf geconfigureerd zijn. De resources in de catalogus kunnen gedownload en aangepast worden op maat van je project.

Voorbeeld: Een Docker Container Image Pipeline

Laten we als voorbeeld een pipeline opstellen die een Docker container image bouwt en dit naar een Docker container registry pusht.
Eerst gaan we onze Tekton tasks voorbereiden, zodat we deze kunnen definiëren in onze Tekton pipeline.

Welke stappen zijn nodig om een Docker container image te bouwen?

  1. Git Clone: Om onze broncode binnen te halen.
  2. Git Version: Om een versie te definiëren voor onze container.
  3. Trivy Scanning: Om eerst te controleren of ons image CVE's bevat.
  4. Kaniko Builder: Een tool om vanuit een Dockerfile een Docker-image te bouwen en naar het register te pushen.
  5. Pipeline starten: Met Tekton PipelineRun kunnen we onze parameters definiëren, zoals branch_name, repository_url en repository_name.
  6. Deployment: Deploy in volgorde de resources om te testen: Tasks, Pipeline en PipelineRun.

Je kunt de bijbehorende YAML-bestanden voor elk van deze tasks vinden in de Tekton Hub.

Tasks

Git Clone

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
  labels:
    app.kubernetes.io/version: "0.9"
  annotations:
    tekton.dev/pipelines.minVersion: "0.38.0"
    tekton.dev/categories: Git
    tekton.dev/tags: git
    tekton.dev/displayName: "git clone"
    tekton.dev/platforms: "linux/amd64,linux/s390x,linux/ppc64le,linux/arm64"
spec:
  description: >-
    These Tasks are Git tasks to work with repositories used by other tasks
    in your Pipeline.
 
    The git-clone Task will clone a repo from the provided url into the
    output Workspace. By default the repo will be cloned into the root of
    your Workspace. You can clone into a subdirectory by setting this Task's
    subdirectory param. This Task also supports sparse checkouts. To perform
    a sparse checkout, pass a list of comma separated directory patterns to
    this Task's sparseCheckoutDirectories param.
  workspaces:
    - name: output
      description: The git repo will be cloned onto the volume backing this Workspace.
    - name: ssh-directory
      optional: true
      description: |
        A .ssh directory with private key, known_hosts, config, etc. Copied to
        the user's home before git commands are executed. Used to authenticate
        with the git remote when performing the clone. Binding a Secret to this
        Workspace is strongly recommended over other volume types.
    - name: basic-auth
      optional: true
      description: |
        A Workspace containing a .gitconfig and .git-credentials file. These
        will be copied to the user's home before any git commands are run. Any
        other files in this Workspace are ignored. It is strongly recommended
        to use ssh-directory over basic-auth whenever possible and to bind a
        Secret to this Workspace over other volume types.
    - name: ssl-ca-directory
      optional: true
      description: |
        A workspace containing CA certificates, this will be used by Git to
        verify the peer with when fetching or pushing over HTTPS.
  params:
    - name: url
      description: Repository URL to clone from.
      type: string
    - name: revision
      description: Revision to checkout. (branch, tag, sha, ref, etc...)
      type: string
      default: ""
    - name: refspec
      description: Refspec to fetch before checking out revision.
      default: ""
    - name: submodules
      description: Initialize and fetch git submodules.
      type: string
      default: "true"
    - name: depth
      description: Perform a shallow clone, fetching only the most recent N commits.
      type: string
      default: "1"
    - name: sslVerify
      description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote.
      type: string
      default: "true"
    - name: crtFileName
      description: file name of mounted crt using ssl-ca-directory workspace. default value is ca-bundle.crt.
      type: string
      default: "ca-bundle.crt"
    - name: subdirectory
      description: Subdirectory inside the `output` Workspace to clone the repo into.
      type: string
      default: ""
    - name: sparseCheckoutDirectories
      description: Define the directory patterns to match or exclude when performing a sparse checkout.
      type: string
      default: ""
    - name: deleteExisting
      description: Clean out the contents of the destination directory if it already exists before cloning.
      type: string
      default: "true"
    - name: httpProxy
      description: HTTP proxy server for non-SSL requests.
      type: string
      default: ""
    - name: httpsProxy
      description: HTTPS proxy server for SSL requests.
      type: string
      default: ""
    - name: noProxy
      description: Opt out of proxying HTTP/HTTPS requests.
      type: string
      default: ""
    - name: verbose
      description: Log the commands that are executed during `git-clone`'s operation.
      type: string
      default: "true"
    - name: gitInitImage
      description: The image providing the git-init binary that this Task runs.
      type: string
      default: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.40.2"
    - name: userHome
      description: |
        Absolute path to the user's home directory.
      type: string
      default: "/home/git"
  results:
    - name: commit
      description: The precise commit SHA that was fetched by this Task.
    - name: url
      description: The precise URL that was fetched by this Task.
    - name: committer-date
      description: The epoch timestamp of the commit that was fetched by this Task.
  steps:
    - name: clone
      image: "$(params.gitInitImage)"
      env:
      - name: HOME
        value: "$(params.userHome)"
      - name: PARAM_URL
        value: $(params.url)
      - name: PARAM_REVISION
        value: $(params.revision)
      - name: PARAM_REFSPEC
        value: $(params.refspec)
      - name: PARAM_SUBMODULES
        value: $(params.submodules)
      - name: PARAM_DEPTH
        value: $(params.depth)
      - name: PARAM_SSL_VERIFY
        value: $(params.sslVerify)
      - name: PARAM_CRT_FILENAME
        value: $(params.crtFileName)
      - name: PARAM_SUBDIRECTORY
        value: $(params.subdirectory)
      - name: PARAM_DELETE_EXISTING
        value: $(params.deleteExisting)
      - name: PARAM_HTTP_PROXY
        value: $(params.httpProxy)
      - name: PARAM_HTTPS_PROXY
        value: $(params.httpsProxy)
      - name: PARAM_NO_PROXY
        value: $(params.noProxy)
      - name: PARAM_VERBOSE
        value: $(params.verbose)
      - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES
        value: $(params.sparseCheckoutDirectories)
      - name: PARAM_USER_HOME
        value: $(params.userHome)
      - name: WORKSPACE_OUTPUT_PATH
        value: $(workspaces.output.path)
      - name: WORKSPACE_SSH_DIRECTORY_BOUND
        value: $(workspaces.ssh-directory.bound)
      - name: WORKSPACE_SSH_DIRECTORY_PATH
        value: $(workspaces.ssh-directory.path)
      - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND
        value: $(workspaces.basic-auth.bound)
      - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH
        value: $(workspaces.basic-auth.path)
      - name: WORKSPACE_SSL_CA_DIRECTORY_BOUND
        value: $(workspaces.ssl-ca-directory.bound)
      - name: WORKSPACE_SSL_CA_DIRECTORY_PATH
        value: $(workspaces.ssl-ca-directory.path)
      securityContext:
        runAsNonRoot: true
        runAsUser: 65532
      script: |
        #!/usr/bin/env sh
        set -eu
 
        if [ "${PARAM_VERBOSE}" = "true" ] ; then
          set -x
        fi
 
        if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ] ; then
          cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials"
          cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig"
          chmod 400 "${PARAM_USER_HOME}/.git-credentials"
          chmod 400 "${PARAM_USER_HOME}/.gitconfig"
        fi
 
        if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then
          cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh
          chmod 700 "${PARAM_USER_HOME}"/.ssh
          chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
        fi
 
        if [ "${WORKSPACE_SSL_CA_DIRECTORY_BOUND}" = "true" ] ; then
           export GIT_SSL_CAPATH="${WORKSPACE_SSL_CA_DIRECTORY_PATH}"
           if [ "${PARAM_CRT_FILENAME}" != "" ] ; then
              export GIT_SSL_CAINFO="${WORKSPACE_SSL_CA_DIRECTORY_PATH}/${PARAM_CRT_FILENAME}"
           fi
        fi
        CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}"
 
        cleandir() {
          # Delete any existing contents of the repo directory if it exists.
          #
          # We don't just "rm -rf ${CHECKOUT_DIR}" because ${CHECKOUT_DIR} might be "/"
          # or the root of a mounted volume.
          if [ -d "${CHECKOUT_DIR}" ] ; then
            # Delete non-hidden files and directories
            rm -rf "${CHECKOUT_DIR:?}"/*
            # Delete files and directories starting with . but excluding ..
            rm -rf "${CHECKOUT_DIR}"/.[!.]*
            # Delete files and directories starting with .. plus any other character
            rm -rf "${CHECKOUT_DIR}"/..?*
          fi
        }
 
        if [ "${PARAM_DELETE_EXISTING}" = "true" ] ; then
          cleandir || true
        fi
 
        test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}"
        test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}"
        test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}"
 
        git config --global --add safe.directory "${WORKSPACE_OUTPUT_PATH}"
        /ko-app/git-init \
          -url="${PARAM_URL}" \
          -revision="${PARAM_REVISION}" \
          -refspec="${PARAM_REFSPEC}" \
          -path="${CHECKOUT_DIR}" \
          -sslVerify="${PARAM_SSL_VERIFY}" \
          -submodules="${PARAM_SUBMODULES}" \
          -depth="${PARAM_DEPTH}" \
          -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}"
        cd "${CHECKOUT_DIR}"
        RESULT_SHA="$(git rev-parse HEAD)"
        EXIT_CODE="$?"
        if [ "${EXIT_CODE}" != 0 ] ; then
          exit "${EXIT_CODE}"
        fi
        RESULT_COMMITTER_DATE="$(git log -1 --pretty=%ct)"
        printf "%s" "${RESULT_COMMITTER_DATE}" > "$(results.committer-date.path)"
        printf "%s" "${RESULT_SHA}" > "$(results.commit.path)"
        printf "%s" "${PARAM_URL}" > "$(results.url.path)"

Git Versioning

---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-version
  labels:
    app.kubernetes.io/version: "0.1"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.0"
    tekton.dev/displayName: "git version"
    tekton.dev/categories: Git
    tekton.dev/tags: git
    tekton.dev/platforms: "linux/amd64"
spec:
  description: >-
    This task can be used to create a version from git history
  params:
    - description: branch to checkout to create a version for e.g. "develop"
      name: branch
      type: string
  results:
    - description: The calculated git version you could use for git tagging e.g. "0.1.0-tektonize.1-188"
      name: gitVersion
    - description: A normalized version for use in container images e.g. "0.1.0-tektonize.1-188"
      name: packageVersion
  steps:
    - image: mcr.microsoft.com/dotnet/sdk:3.1-focal@sha256:1d31e2582f69920c3a6ea9498bb7da285baffbca7ea84d90d9e5b545604cc92d
      name: set-git-version
      workingDir: $(workspaces.source.path)
      securityContext:
        runAsUser: 0
      env:
        - name: PARAM_BRANCH
          value: $(params.branch)
      script: |
        #!/usr/bin/env bash
        export PATH="$PATH:/tekton/home/.dotnet/tools"
        dotnet tool install GitVersion.Tool --version 5.5.0 --tool-path "/tekton/home/.dotnet/tools"
 
        git checkout "${PARAM_BRANCH}"
 
        export GITVERSION=$(dotnet gitversion /showvariable FullSemVer)
        echo -n "${GITVERSION}" | tee $(results.gitVersion.path)
 
        # normalize a bit because
        # image tags can only contain `abcdefghijklmnopqrstuvwxyz0123456789_-.ABCDEFGHIJKLMNOPQRSTUVWXYZ`
        export PACKAGEVERSION=$(echo -n $GITVERSION | sed 's/[^-._0-9A-Za-z]/-/g')
        echo -n "${PACKAGEVERSION}" | tee $(results.packageVersion.path)
  workspaces:
    - name: source
      description: A workspace that contains the fetched git repository to create a version for.

Trivy Scanner

---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: trivy-scanner
  labels:
    app.kubernetes.io/version: "0.2"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.1"
    tekton.dev/categories: Security
    tekton.dev/tags: CLI, trivy
    tekton.dev/displayName: "trivy scanner"
    tekton.dev/platforms: "linux/amd64,linux/arm64,linux/ppc64le,linux/390x"
spec:
  description: >-
    Trivy is a simple and comprehensive scanner for
    vulnerabilities in container images,file systems
    ,and Git repositories, as well as for configuration issues.
 
    This task can be used to scan for vulnenrabilities on the source code
    in stand alone mode.
  workspaces:
    - name: manifest-dir
  params:
    - name: ARGS
      description: The Arguments to be passed to Trivy command.
      type: array
    - name: TRIVY_IMAGE
      default: docker.io/aquasec/trivy@sha256:944a044451791617cc0ed2ee4d1942a4f66b790d527fcd0575a6b399ccbc05a1  # 0.43.1
      description: Trivy scanner image to be used
    - name: IMAGE_PATH
      description: Image or Path to be scanned by trivy.
      type: string
    - name: AIR_GAPPED_ENABLED
      default: "false"
      description: a flag enabling Air-Gapped mode
      type: string
  steps:
    - name: trivy-scan
      image: $(params.TRIVY_IMAGE)
      workingDir: $(workspaces.manifest-dir.path)
      script: |
        #!/usr/bin/env sh
          cmd="trivy $* "
          if [ "$(params.AIR_GAPPED_ENABLED)" = "true" ]; then
            echo "Air-Gapped mode enabled"
            TRIVY_TEMP_DIR=$(mktemp -d)
            trivy --cache-dir "$TRIVY_TEMP_DIR" image --download-db-only
            tar -cf ./db.tar.gz -C "$TRIVY_TEMP_DIR/db" metadata.json trivy.db
            rm -rf "$TRIVY_TEMP_DIR"
            mkdir -p "$HOME"/.cache/trivy/db
            tar xvf ./db.tar.gz -C "$HOME"/.cache/trivy/db
            cmd="${cmd}--skip-update "
          fi
          cmd="${cmd}$(params.IMAGE_PATH)"
          echo "Running trivy task with command below"
          echo "$cmd"
          eval "$cmd"
      args:
        - "$(params.ARGS)"

Kaniko Builder

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: kaniko
  labels:
    app.kubernetes.io/version: "0.6"
  annotations:
    tekton.dev/pipelines.minVersion: "0.17.0"
    tekton.dev/categories: Image Build
    tekton.dev/tags: image-build
    tekton.dev/displayName: "Build and upload container image using Kaniko"
    tekton.dev/platforms: "linux/amd64,linux/arm64,linux/ppc64le"
spec:
  description: >-
    This Task builds a simple Dockerfile with kaniko and pushes to a registry.
    This Task stores the image name and digest as results, allowing Tekton Chains to pick up
    that an image was built & sign it.
  params:
    - name: IMAGE
      description: Name (reference) of the image to build.
    - name: DOCKERFILE
      description: Path to the Dockerfile to build.
      default: ./Dockerfile
    - name: CONTEXT
      description: The build context used by Kaniko.
      default: ./
    - name: EXTRA_ARGS
      type: array
      default: []
    - name: BUILDER_IMAGE
      description: The image on which builds will run (default is v1.5.1)
      default: gcr.io/kaniko-project/executor:v1.5.1@sha256:c6166717f7fe0b7da44908c986137ecfeab21f31ec3992f6e128fff8a94be8a5
  workspaces:
    - name: source
      description: Holds the context and Dockerfile
    - name: dockerconfig
      description: Includes a docker `config.json`
      optional: true
      mountPath: /kaniko/.docker
  results:
    - name: IMAGE_DIGEST
      description: Digest of the image just built.
    - name: IMAGE_URL
      description: URL of the image just built.
  steps:
    - name: build-and-push
      workingDir: $(workspaces.source.path)
      image: $(params.BUILDER_IMAGE)
      args:
        - $(params.EXTRA_ARGS)
        - --dockerfile=$(params.DOCKERFILE)
        - --context=$(workspaces.source.path)/$(params.CONTEXT) # The user does not need to care the workspace and the source.
        - --destination=$(params.IMAGE)
        - --digest-file=$(results.IMAGE_DIGEST.path)
      # kaniko assumes it is running as root, which means this example fails on platforms
      # that default to run containers as random uid (like OpenShift). Adding this securityContext
      # makes it explicit that it needs to run as root.
      securityContext:
        runAsUser: 0
    - name: write-url
      image: docker.io/library/bash:5.1.4@sha256:c523c636b722339f41b6a431b44588ab2f762c5de5ec3bd7964420ff982fb1d9
      script: |
        set -e
        image="$(params.IMAGE)"
        echo -n "${image}" | tee "$(results.IMAGE_URL.path)"

Nu dat we onze Tasks hebben voorbereid, kunnen we onze custom Tekton Pipeline schrijven.
Tekton Pipeline wordt van boven naar onder uitgevoerd.

Tekton Pipeline

apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: custom-docker-image
  namespace: tekton-pipelines
spec:
  params:
    - name: branch_name
      description: The git branch
    - name: repository_url
      description: The git repository url
    - name: repository_name
      description: The git repository name
  tasks:
    - name: clonegit
      taskRef:
        name: git-clone
      params:
        - name: url
          value: $(params.repository_url)
        - name: revision
          value: $(params.branch_name)
        - name: deleteExisting
          value: true
        - name: depth
          value: "0"
      workspaces:
        - name: output
          workspace: source-workspace
    - name: gitversion
      taskRef:
        name: git-version
      runAfter:
        - clonegit
      params:
        - name: branch
          value: "$(params.branch_name)"
      workspaces:
        - name: source
          workspace: source-workspace
    - name: trivyscanner
      taskRef:
        name: trivy-scanner
      runAfter:
        - gitversion
      params:
        - name: IMAGE_PATH
          value: "."
        - name: ARGS
          value: [ ]
      workspaces:
        - name: source
          workspace: source-workspace
    - name: kanikobuilder
      taskRef:
        name: kaniko
      runAfter:
        - trivyscanner
      params:
        - name: IMAGE
          value: "<your-custom-registry>/$(params.repository_name):$(tasks.gitversion.results.packageVersion)"
        - name: DOCKERFILE
          value: "Dockerfile"
      workspaces:
        - name: source
          workspace: source-workspace
        - name: dockerconfig
          workspace: docker-credentials
  workspaces:
    - name: source-workspace
    - name: docker-credentials

Pipeline Run

Nu dat we een volledige Tekton Pipeline hebben, kunnen we onze pipeline starten.
Hiervoor hebben we Tekton PipelineRun nodig. Hierin gaan we onze parameters definieren zoals:

  • branch_name
  • repository_url
  • repository_name

apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: custom-docker-image
  namespace: tekton-pipelines
spec:
  serviceAccountName: tekton-pipelines-build-bot
  pipelineRef:
    name: custom-docker-image
  params:
    - name: branch_name
      value: "develop"
    - name: repository_url
      value: "<repository-branch>"
    - name: repository_name
      value: "<repository-name>"
  workspaces:
    - name: source-workspace
      subPath: source
      persistentVolumeClaim:
        claimName: custom-docker-image-source
    - name: docker-credentials
      subPath: source
      persistentVolumeClaim:
        claimName: custom-docker-image-docker-credentials
  pipelineSpec:
    tasks:
      - name: clonegit
        taskRef:
          name: git-clone]
      - name: gitversion
        taskRef:
          name: git-version
      - name: trivyscanner
        taskRef:
          name: gitversion
      - name: kanikobuilder
        taskRef:
          name: kaniko

Deploy in volgorde de resources om te testen: Tasks, Pipeline en PipelineRun.

2. Tekton Triggers: Start Pipelines met Events

Triggers zorgt ervoor dat Tekton Pipelines kunnen worden gestart door een event, zoals bijvoorbeeld een commit op een repository die vervolgens een Webhook verstuurt naar je Trigger Listener.
Er zijn verschillende mogelijkheden om je pipeline te activeren vanaf een event.

Wanneer we het bovenstaande schema verder uitwerken en Tekton Triggers toevoegen, ziet dit er als volgt uit:

Stappen:

  1. Git stuurt een payload via een Webhook naar de EventListener.
  2. De EventListener leest de inkomende Webhook en payload en controleert of dit voor hem bestemd is.
  3. Wanneer de EventListener ziet dat dit voor hem bedoeld is, plaatst hij de geconfigureerde waarden vanuit de payload in een variabele. Dit wordt gedaan via TriggerBinding.
  4. De EventListener maakt vervolgens een TriggerTemplate aan met de waarden uit TriggerBinding.
  5. TriggerTemplate start vervolgens een PipelineRun en voert de gedefinieerde tasks uit.

Voorbeeld

EventListener

Eerst gaan we onze EventListener maken op basis van eel CEL expressie.

apiVersion: triggers.tekton.dev/v1alpha1
kind: EventListener
metadata:
  name: custom-docker-build-listener
  namespace: tekton-pipelines
spec:
  serviceAccountName: tekton-triggers-build-bot
  triggers:
    - name: git-custom-docker-build-listener
      interceptors:
        - cel:
              filter: (body.repository.workspace.slug.matches('<WORKSPACE>') && body.push.changes[0].new.name.matches('<branch-name>') && body.repository.name.matches('<repository-name>'))
      template:
        - ref: git-custom-docker-build-listener
      bindings:
        - ref: git-custom-docker-build-listener

In onze EventListener hebben we triggers geconfigureerd die:

  • naar de WORKSPACE naam gaat kijken
  • naar de BRANCH naam gaat kijken
  • naar de REPOSITORY naam gaat kijken

Wanneer deze velden juist zijn gaat hij een template voorbereiden.
We gaan ook een TriggerTemplate en TriggerBinding voorbereiden om parameters te gebruiken tijdens de trigger.

TriggerBinding

In de TriggerBinding gaan we de Trigger Body extracten en de variables inladen met body values die vanuit Webhook worden verstuurd.

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerBinding
metadata:
  name: custom-docker-build-listener
  namespace: tekton-pipelines
spec:
  params:    
    - name: branch_name
      value: $(body.pullrequest.destination.branch.name)
    - name: repository_url
      value: $(body.repository.links.html.href)
    - name: repository_name
      value: $(body.repository.name)

TriggerTemplate

Nu dat we de variables hebben in de TriggerBinding, kunnen we onze Pipeline starten vanuit TriggerTemplate met onze variables die uit Trigger komt.

Hiervoor kunnen we de  ${tt.xx}  notatie gebruiken.

apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
  name: custom-docker-build-listener
  namespace: tekton-pipelines
spec:
  params:
    - name: branch_name
      description: The git branch name
    - name: repository_url
      description: The git repository url
    - name: repository_name
      description: The git repository name
  resourcetemplates:
    - apiVersion: tekton.dev/v1beta1
      kind: PipelineRun
      metadata:
        generateName: $(tt.params.repository_name)-
        labels:
          tekton.dev/pipeline: tekton-pipeline
      spec:
        serviceAccountName: tekton-pipelines-build-bot
        pipelineRef:
          name: custom-docker-build-listener
        params:
          - name: branch_name
            value: $(tt.params.branch_name)
          - name: repository_url
            value: $(tt.params.repository_url)
          - name: repository_name
            value: $(tt.params.repository_name)
        workspaces:
          - name: source-workspace
            subPath: source
            persistentVolumeClaim:
              claimName: custom-docker-image-source
          - name: docker-credentials
            subPath: source
            persistentVolumeClaim:
              claimName: custom-docker-image-docker-credentials
        pipelineSpec:
          tasks:
            - name: clonegit
              taskRef:
                name: git-clone]
            - name: gitversion
              taskRef:
                name: git-version
            - name: trivyscanner
              taskRef:
                name: gitversion
            - name: kanikobuilder
              taskRef:
                name: kaniko

Deploy de resources in volgorde om te testen: TriggerTemplate, TriggerBinding, EventListener.

Tekton Dashboard

Het monitoren en bekijken van Tekton resources in een Kubernetes omgeving is niet altijd vanzelfsprekend. Ontwikkelaars hebben doorgaans beperkte rechten binnen de Kubernetes omgeving.

Daarom is het raadzaam om Tekton Dashboards te gebruiken. Tekton Dashboard is een uitbreiding op het Tekton ecosysteem en biedt een webinterface voor het beheren en monitoren van Tekton resources in Kubernetes omgevingen.

Het maakt het makkelijker voor ontwikkelaars om pipelines te volgen, logs realtime te bekijken en de status van tasks te controleren. Zo kan de ontwikkelaar direct zien waarom de build is mislukt en waar dat is gebeurd.

4. Tekton Hub: Uitgebreide Bibliotheek van Pipelines en Tasks

Tekton heeft een uitgebreid scala aan pipelines en tasks en pipelines beschikbaar. Je kan pipelines of tasks vanaf het begin schrijven, maar je hebt ook de mogelijkheid om tasks en pipelines over te nemen vanuit de Tekton Hub. De resources die je vanuit de Hub overneemt, kan je naar behoefte aanpassen.

Dit biedt flexibiliteit voor ontwikkelaars. Ze hoeven zich niet aan te passen aan bepaalde resources, maar kunnen hun resources volledig herschrijven zoals gewenst.

Enkele belangrijke tasks uit de Hub zijn onder andere:

  • Git-Clone
  • Workspace cleaner
  • Maven
  • Jib-Maven
  • BuildPacks
  • Kaniko/Docker

Meer taken zijn beschikbaar op https://hub.tekton.dev/

Aan de Slag met Tekton

Voor ontwikkelaars die Tekton willen gebruiken, biedt de officiële Tekton-documentatie gedetailleerde informatie over installatie en configuratie.

Concluderend biedt Tekton een krachtige, flexibele en schaalbare oplossing voor CI/CD-processen. Met zijn CloudNative kenmerken, uitbreidbaarheid en ondersteuning van grote bedrijven, heeft Tekton zich gevestigd als een betrouwbaar framework voor developers.

Wil je de voordelen van Tekton in de praktijk ervaren en ontdekken hoe ACA Group innovatieve oplossingen kan bieden voor je IT-uitdagingen?

Neem dan contact op met onze experten voor persoonlijk advies en een soepele implementatie.