Tekton CI/CD Part 1: Building image with Pipelines

·

5 min read

What is Tekton

Tekton is an open-source project from the Continuous Delivery Foundation for creating CI/CD systems from

You might wonder what is the difference with Jenkins, in shorts Jenkins is more like "stateful" (Jenkins can be stateless with Kubernetes plugins) and Tekton is "stateless"

image.png image.png

Comparison tables above are taken from OpenShift


Installation

Assume you have a Kubernetes cluster and kubectl installed

Install tekton, dashboard and optionally cli

Preview dashboard with the following command

kubectl --namespace tekton-pipelines port-forward svc/tekton-dashboard 9097:9097

Run sample task

With Tekton, each operation in your CI/CD workflow becomes a Step, which is executed with a container image you specify. Steps are then organized in Tasks, which run as a Kubernetes pod in your cluster. You can further organize Tasks into Pipelines, which can control the order of execution of several Tasks.

Create a file named task-hello.yaml, it specifies a Task with one simple Step, which prints a Hello World! message using the official Ubuntu image

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: hello
spec:
  steps:
    - name: hello
      image: ubuntu
      command:
        - echo
      args:
        - "Hello World!"

To run this task with Tekton, you need to create a TaskRun, which is another Kubernetes object used to specify run-time information for a Task.

Create a file named task-hello-run.yaml

apiVersion: tekton.dev/v1beta1
kind: TaskRun
metadata:
  generateName: hello-run-
spec:
  taskRef:
    name: hello

Run the task, and view it on the dashboard

kubectl apply -f task-hello.yaml
kubectl create -f task-hello-run.yaml

Tekton Hub

Tasks and Pipelines can be reused, a handful of command Tasks and Pipelines like git clone, docker build and etc can be found on Tekton Hub


Build your own pipeline

A Pipeline is a collection of Tasks that you define and arrange in a specific order of execution as part of your continuous integration flow. Each Task in a Pipeline executes as a Pod on your Kubernetes cluster. You can configure various execution conditions to fit your business needs

We will build a Pipeline that builds the Go program into a Docker image, and push it to the registry

Complete source code can be found on cncf-demo/hello-word

hello-world sample without auth

Install the following Tasks from the Tekton hub

tkn hub install task git-clone
tkn hub install task kaniko

Examine pipeline.yaml, which contains two steps

  1. Clone the project with git-clone task that we installed above
  2. Build an image with Kaniko, without pushing to registry (--no-push)

Tekton Tasks are executed in parallel, use runAfter to execute in a specific order within the Pipeline

... 
  workspaces:
    - name: git-source # attach a volume to store source code
  params:
    - name: git_revision # from PipelineRun
  tasks:
    - name: fetch-from-git # first task, clone project
      taskRef:
        name: git-clone # using git-clone task that we installed from the Tekton hub
      params:
        - name: url
          value: https://github.com/WLun001/cncf-demo
       - name: revision
         value: $(params.git_revision) # refers from PipelineRun
      workspaces:
        - name: output
          workspace: git-source
    - name: build-image # second task, build an image
      runAfter: [ fetch-from-git ] # to run after first task
      taskRef:
        name: kaniko # using kaniko task that we installed from Tekton hub
      params:
        - name: IMAGE
          value: ghcr.io/wlun001/hello-world # replace with your own registry
        - name: CONTEXT
          value: examples/hello-world
        - name: DOCKERFILE
          value: $(workspaces.source.path)/examples/hello-world/Dockerfile
        - name: EXTRA_ARGS
          value: ['--no-push'] # only build the image, without pushing to a registry.
      workspaces:
        - name: source
          workspace: git-source

And pipeline-run.yaml to run the pipeline

...
 pipelineRef:
   name: kaniko-pipeline # refer to the pipeline above
 params:
   - name: git_revision
     value: HEAD
 workspaces:
   - name: git-source
     volumeClaimTemplate: # create volume claim
       spec:
         accessModes:
           - ReadWriteOnce # access mode may affect how you can use this volume in parallel tasks
         resources:
           requests:
             storage: 100m

Create Pipeline and PipelineRun

kubectl apply -f pipeline.yaml
kubectl create -f pipeline-run.yaml

The output should be visible on the dashboard. We have created a Pipeline that clone and build an image

hello-world sample with auth

Most of the time we will need to access the private git repository and registry, we will continue to enhance the Pipeline with authentication

Add registry credentials

Get your docker registry user and password encoded in base64

echo -n USER:ACCESS_TOKEN | base64

Create a config.json file with your Docker registry URL and the generated base64 string

{
  "auths": {
    "ghcr.io": {
      "auth": "XXXXXX"
    }
  }
}

Create registry secret

kubectl create secret generic kaniko-secret --from-file=config.json

Add git ssh credentials

git-clone supports multiple ways of authentication, we only show ssh credentials, more refer to git-clone

Replace the values by running the command in the comment

kind: Secret
apiVersion: v1
metadata:
  name: ssh-credentials
type: Opaque
stringData:
  # ssh-keygen -t ed25519 -C "example.com"
  # cat id_ed25519
  id_ed25519: |
    XXXXXX
  # ssh-keyscan github.com >> githubKey
  # cat githubkey
  known_hosts: |
    XXXXX
  config: |
    IdentityFile ~/.ssh/id_ed25519

And add the SSH key to Git service, for example Github

Use secrets in Pipeline

Add credentials to related Tasks by attaching Workspace

...
  workspaces:
    - name: git-source
    - name: ssh-creds # git credentials
    - name: dockerconfig # registry credentials
  tasks:
    - name: fetch-from-git
        ...
      workspaces:
        - name: output
          workspace: git-source
        - name: ssh-directory # need git credentials to clone
          workspace: ssh-creds
    - name: build-image
      ...
      workspaces:
        - name: source
          workspace: git-source
        - name: dockerconfig # registry credentials to push
          workspace: dockerconfig

And PipelineRun will get the secret, and attached as Workspace

...
spec:
  pipelineRef:
    name: kaniko-pipeline
  workspaces:
    ...
    - name: ssh-creds
      secret:
        secretName: ssh-credentials # refer to the secret
    - name: dockerconfig
      secret:
        secretName: kaniko-secret # refer to the secret

Create the Pipeline and execute it

kubectl apply -f pipeline.yaml
kubectl create -f pipeline-run.yaml

View the build logs on the dashboard, it should push to the registry after building the image


Conclusion

We have built Pipelines that can build images and push them to the registry. Next, we will look at Triggers, which will automatically run the Pipelines when events occur, for example, the git push event.

Did you find this article valuable?

Support Wei Lun by becoming a sponsor. Any amount is appreciated!