Alin
Alin
Java, Kubernetes, Cloud, Internet Of Things

Continuous Integrations with Tekton - Cloud Native Tool #004

Continuous Integrations with Tekton - Cloud Native Tool #004

I am currently refactoring my project, SmartFactory v2, and I want to set up a CI/CD pipeline to automate the testing and deployment process. In the past, I used GitHub Actions for CI, but I wanted to try a solution that is more Kubernetes native. I decided to use Tekton Pipelines.

1. What is Tekton?

Tekton is a Cloud Native CI/CD tools that allows you to build, test, and deploy your applications on Kubernetes.

Some important concepts in Tekton:

  • Task: A reusable, loosely coupled number of steps that perform a specific task.
  • Pipeline: A collection of tasks that are executed in a specific order.
  • PipelineRun: An instance of a pipeline. It defines the execution of a pipeline.
  • TaskRun: An instance of a task. It defines the execution of a task.

2. Prerequisites

  • A Kubernetes cluster (Minikube, Docker Desktop, or any other Kubernetes cluster)
  • kubectl CLI tool
  • Tekton CLI tool (tkn cli)
  • Tekton Pipelines installed on your Kubernetes cluster (Installation Guide)
  • Tekton Dashboard (Optional)

3. Creating CI Pipeline

I have this repository that contains 4 microservices: data-collector-service, notification-service, subscription-service and user-management-service. I want to create a CI pipeline that will build and test each microservice.

SmartFactory Repository

Our pipeline will have the following steps:

  • Clone the repository: Clone the repository from GitHub.
  • Build the microservices: Build the microservices using Maven.
  • Run the tests: Run the tests using Maven.
  • Build and push the Docker images: Build the Docker images and push them to Docker Hub.

So, we need a Tekton Task for each of these steps.

3.1. Create Tasks - Tekton Hub

Tekton Hub is a collection of reusable Tekton tasks and pipelines. You can find a lot of tasks and pipelines that you can use in your CI/CD pipeline.

For our pipeline, we will use the following tasks:

  • git-clone: Clone a git repository.
  • maven: Build and test a Maven project.
  • kaniko: Build and push Docker images.

Let’s install these tasks on our Kubernetes cluster:

1
2
3
tkn hub install task git-clone
tkn hub install task maven
tkn hub install task kaniko

List the installed tasks:

1
tkn task list
1
2
3
4
NAME        DESCRIPTION              AGE
git-clone   These Tasks are Git...   2 minutes ago
kaniko      This Task builds a ...   2 minutes ago
maven       This Task can be us...   2 minutes ago

3.2. Create the Pipeline

A Tekton Pipeline is a collection of tasks that are executed in a specific order.

Let’s create a pipeline.yaml file that defines our pipeline:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: smartfactory-ci-pipeline
spec:
  description: |
    This pipeline clones a git repo, then echoes the README file to the stout.
  params:
    - name: REPO_URL
      type: string
      description: The git repo URL to clone from.
    - name: PROJECT_DIR
      type: string
      description: The subdirectory to clone from the git repo.
      default: ""
    - name: IMAGE
      type: string
      description: The image name to build.
    - name: TAG
      type: string
      description: The image tag to build.
      default: "latest"
    - name: ACCOUNT
      type: string
      description: The docker account to push the image to.
  workspaces:
    - name: shared-workspace
      description: |
        This workspace contains the cloned repo files, so they can be read by the
        next task.
    - name: maven-settings
      description: |
        This workspace contains the maven settings file, so it can be used by the
        maven task.
    - name: maven-local-m2
      description: |
        This workspace contains the maven local repository, so it can be used by the
        maven task.
    - name: docker-credentials
      description: |
        This workspace contains the docker credentials, so it can be used by the
        kaniko task.
  tasks:
    - name: fetch-repository
      taskRef:
        name: git-clone
      workspaces:
        - name: output
          workspace: shared-workspace
      params:
        - name: url
          value: "$(params.REPO_URL)"
        - name: deleteExisting
          value: "true"
    - name: maven-run
      taskRef:
        name: maven
      runAfter:
        - fetch-repository
      params:
        - name: MAVEN_IMAGE
          value: "maven:3.8.8-eclipse-temurin-21-alpine"
        - name: CONTEXT_DIR
          value: "$(params.PROJECT_DIR)"
        - name: GOALS
          value:
            - clean
            - test
            - package
      workspaces:
        - name: maven-settings
          workspace: maven-settings
        - name: source
          workspace: shared-workspace
        - name: maven-local-repo
          workspace: maven-local-m2
    - name: build-push
      runAfter:
        - maven-run
      taskRef:
        name: kaniko
      workspaces:
        - name: source
          workspace: shared-workspace
        - name: dockerconfig
          workspace: docker-credentials
      params:
        - name: IMAGE
          value: "$(params.ACCOUNT)/$(params.IMAGE):$(params.TAG)"
        - name: DOCKERFILE
          value: "$(params.PROJECT_DIR)/Dockerfile"
        - name: CONTEXT
          value: "$(params.PROJECT_DIR)"

In this pipeline, we have defined three tasks:

  • fetch-repository: Clones the git repository.
  • maven-run: Builds the Maven project.
  • build-push: Builds and pushes the Docker image.

We have also defined some parameters that are used by the tasks:

  • REPO_URL: The git repo URL to clone from.
  • PROJECT_DIR: The subdirectory to clone from the git repo. (We have 3 microservices in our repository, so we need to specify the subdirectory for each microservice)
  • IMAGE: The image name to build.
  • TAG: The image tag to build.
  • ACCOUNT: The docker account to push the image to.

Workspaces are used to share files between tasks.

3.3. Create the PipelineRun

Now that we have defined our pipeline, we need to create a PipelineRun that will execute the pipeline.

We need to create a pipelinerun.yaml file that defines our PipelineRun for each microservice:

Before creating the PipelineRun, we need to create a secret that contains the Docker credentials that will be used by the kaniko task to push the Docker image to Docker Hub.

1
2
3
4
5
6
apiVersion: v1
data:
  config.json: <base64 encoded docker config.json>
kind: Secret
metadata:
  name: docker-credentials

To create the secret, you need to create a config.json file that contains your Docker credentials and then encode it to base64:

1
2
3
4
5
6
7
8
9
10
{
  "auths": {
    "https://index.docker.io/v1/": {
      "username": "<username>",
      "password": "<token>",
      "email": "<email>",
      "auth": "<base64 encoded username:token>"
    }
  }
}

Let’s create a pipelinerun.yaml file for the notification-service microservice:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  generateName: smartfactory-ci-notification-service-
spec:
  pipelineRef:
    name: smartfactory-ci-pipeline
  podTemplate:
    securityContext:
      fsGroup: 65532
  workspaces:
    - name: shared-workspace
      volumeClaimTemplate:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 10Gi
    - name: maven-local-m2
      volumeClaimTemplate:
        spec:
          accessModes:
            - ReadWriteOnce
          resources:
            requests:
              storage: 10Gi
    - name: maven-settings
      emptyDir: { }
    - name: docker-credentials
      secret:
        secretName: docker-credentials
  params:
    - name: REPO_URL
      value: https://github.com/DragomirAlin/smartfactory
    - name: PROJECT_DIR
      value: "notification-service"
    - name: IMAGE
      value: "notification-service"
    - name: TAG
      value: "latest"
    - name: ACCOUNT
      value: "dragomiralin"

In this PipelineRun, we have defined the following parameters:

  • REPO_URL: The git repo URL to clone from.
  • PROJECT_DIR: The subdirectory to clone from the git repo. (notification-service)
  • IMAGE: The image name to build. (notification-service)
  • TAG: The image tag to build. (latest)
  • ACCOUNT: The docker account to push the image to. (dragomiralin)

We have also defined some workspaces:

  • shared-workspace: Contains the cloned repo files.
  • maven-local-m2: Contains the maven local repository.
  • maven-settings: Contains the maven settings file.
  • docker-credentials: Contains the docker credentials.

4. Run the Pipeline

Now that we have defined our pipeline and pipeline runs, we can run the pipeline using the Tekton CLI tool.

Let’s create the pipeline:

1
kubectl apply -f pipeline.yaml

See the list of pipelines:

1
2
3
tkn pipeline list
NAME                       AGE            LAST RUN                                        STARTED          DURATION   STATUS
smartfactory-ci-pipeline   3 minutes ago   -                                               -                 -      Succeeded

Let’s run the pipeline for the notification-service microservice:

1
kubectl create -f pipelinerun-notification-service.yaml

See the list of pipeline runs:

1
2
3
tkn pipelinerun list
NAME                                            STARTED          DURATION   STATUS
smartfactory-ci-notification-service-8l75f      4 minutes ago   1m45s      Succeeded

We can check the logs of the pipeline run:

1
tkn pipelinerun logs smartfactory-ci-notification-service-8l75f

The result of the pipeline run is a Docker image that is pushed to Docker Hub: DockerHub

Tekton has a nice dashboard that you can use to see the status of your pipelines and pipeline runs. You need to install the Tekton Dashboard on your Kubernetes cluster.

Tekton Dashboard

Next Steps

  • Use Tekton Triggers to trigger the pipeline when a new commit is pushed to the repository.

comments powered by Disqus