Several ways to build a container image

Using Docker to build container images in your CI pipelines ? Alternative solutions exist, let’s explore some of them.

Quick overview

The following illustrates the usage of each of these tools in GitLab CI, it also details the usage of Docker as a reference.

build image with Docker:
  stage: build
  variables:
    TAG: docker
  image: docker:27.3-cli
  services:
    - docker:27.3-dind
  before_script:
    - docker login -u "gitlab-ci-token" -p $CI_JOB_TOKEN $CI_REGISTRY
  script: 
    - docker buildx create --use
    - docker buildx build -t $CI_REGISTRY_IMAGE:$TAG . --push

details

  • before_script is used to log in to the GitLab registry
  • script defines 2 commands:
    • creation of a builder
    • usage of this builder to create and to push the image
build image with Kaniko:
  stage: build
  variables:
    TAG: kaniko
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  before_script:
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"gitlab-ci-token\",\"password\":\"$CI_JOB_TOKEN\"}}}" > /kaniko/.docker/config.json
  script:
    - /kaniko/executor --context . --dockerfile ./Dockerfile --destination $CI_REGISTRY_IMAGE:$TAG

details

  • before_script creates a /kaniko/.docker folder and a config.json file inside it. This file contains the credentials to authenticate against the GitLab registry
  • script runs Kaniko executor which creates and pushes the image to the GitLab registry
build image with Buildah:
  stage: build
  variables:
    TAG: buildah
  image: ubuntu:24.04
  before_script:
    - apt-get -y update && apt-get -y install buildah runc
    - buildah login --tls-verify=false -u "gitlab-ci-token" -p "$CI_JOB_TOKEN" $CI_REGISTRY
  script:
    - buildah bud --tls-verify=false -t $CI_REGISTRY_IMAGE:$TAG .
    - buildah push --disable-compression --tls-verify=false $CI_REGISTRY_IMAGE:$TAG

details

  • before_script installs buildah and runc component, then it logs in to the GitLab registry
  • scripts builds the image and pushes it to the registry
build image with Podman:
  stage: build
  variables:
    TAG: podman
  image: quay.io/podman/stable
  before_script:
    - podman login -u "gitlab-ci-token" -p $CI_JOB_TOKEN $CI_REGISTRY
  script:
    - podman build -t $CI_REGISTRY_IMAGE:$TAG .
    - podman push $CI_REGISTRY_IMAGE:$TAG

details

  • before_script logs in to the GitLab registry
  • script builds and pushes the image

Example

The example above is based on a sample application in GitLab. Each code change pushed to the repository triggers the CI which builds 4 images:

  • registry.gitlab.com/lucj/shapes:docker
  • registry.gitlab.com/lucj/shapes:kaniko
  • registry.gitlab.com/lucj/shapes:buildah
  • registry.gitlab.com/lucj/shapes:podman

CI

Next it pushes the images to the GitLab registry:

Registry

These images can be run using Docker, Podman or any other OCI compatible container runtime.

⚠️
Because these images were built for amd64, they will not work on arm64 (Apple Silicon)