Contents

Building Custom Docker Image with GitLab CI and Kaniko in kubernetes

In my CI/CD pipelines at home, I often use ready-made Docker images and add extra steps to install the necessary packages. However, this time I decided to create a master build image, incorporating essential packages and the Hugo binary for my Hugo build and deploy pipelines.

Current Setup

  • GitLab CE (self-hosted)
  • Kubernetes cluster with a GitLab Runner (tag: k8s-new)
  • Remote web server using lftp to update my Hugo HTML website

In my GitLab instance, I organize my Docker images in a group named docker_images. Inside this group, I create repositories for building custom images.

Repository Structure

1
2
3
4
my-golden-build-image:
    ├── Dockerfile
    ├── .gitlab-ci.yml
    └── README.md

I spent considerable time configuring Docker-In-Docker GitLab Runner in Kubernetes. To avoid running it as privileged (which is not my preferred approach for security reasons), I explored an alternative solution. Following the Kaniko documentation, I decided to use Kaniko.

Kaniko: A Secure Solution

Kaniko provides a straightforward and secure alternative to Docker-In-Docker. The pipeline configuration with Kaniko is more secure and aligns with best practices.

Pipeline Configuration (.gitlab-ci.yml)

The GitLab CI pipeline configuration for using Kaniko is much more straightforward compared to Docker-In-Docker:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
build:
  stage: build
  image:
    name: gcr.io/kaniko-project/executor:v1.14.0-debug
    entrypoint: [""]
  script:
    - echo "Building Docker image..."
    - /kaniko/executor
      --context "${CI_PROJECT_DIR}"
      --dockerfile "${CI_PROJECT_DIR}/Dockerfile"
      --destination "${CI_REGISTRY_IMAGE}:${CI_COMMIT_SHORT_SHA}"
      --destination "${CI_REGISTRY_IMAGE}:latest" 
  only:
    - master
  tags:
    - k8s-new

With Kaniko, you can build Docker images securely in a Kubernetes environment without the need for privileged containers.

By adopting Kaniko, I enhanced the security of my CI/CD pipeline and streamlined the Docker image building process. This approach aligns with best practices and ensures a more reliable and secure development workflow.

Dockerfile:

 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

FROM alpine:latest
RUN apk update && apk add --no-cache \
    ca-certificates           \
    libc6-compat              \
    libstdc++                 \
    gcompat                   \
    libc6-compat              \
    git                       \
    lftp                      \
    go                        \
    build-base                \
    ca-certificates           \
    curl                      \
    git                       \
    libc6-compat              \
    libstdc++                 \
    make                      \
    rsync                     \
    wget  && \
    wget https://github.com/gohugoio/hugo/releases/download/v0.120.4/hugo_extended_0.120.4_linux-amd64.tar.gz && \
    tar -xvf hugo_extended_0.120.4_linux-amd64.tar.gz && \
    rm hugo_extended_0.120.4_linux-amd64.tar.gz && \
    mv hugo /usr/local/bin/ && \
    rm -Rf /var/cache/apk/*

After pushing changes to the repository, a CI job is triggered to build the Docker image. In my configuration, I set it up to push two images each time—one with the “latest” tag and another with the short commit SHA (CI_COMMIT_SHORT_SHA).

Once the CI job completes, the images are available at the following registry:

https://URL/docker_images/my-golden-build-image/container_registry

It’s crucial to note that if you wish to access this container image from another project, you’ll need to either disable “Token Access” under “Limit access to this project” (https://URL/docker_images/my-favourite-build-image/-/settings/ci_cd) or ensure that the accessing project is listed in “Allow CI job tokens from the following projects to access this project.”

This ensures secure and controlled access to the container image across different projects. (more information on this https://gitlab.com/help/ci/jobs/ci_job_token#limit-your-projects-job-token-access)