Build container images

Build container images

These methods can be used to build a container image, at the time of writing:

SoftwareEaseSecurityPerfRun locationDescription
Azure Container Registry task, Google Cloud Build🟩🟩🟥🟩🟩🟩🟩🟩🟩Managed environmentA managed service build the container image in a dedicated environment.
Kaniko🟩🟥🟥🟩🟩🟩🟩🟩🟥Self-hosted KubernetesA Pod is created for each build, taking care of building and pushing the container to the registry. No security drawbacks.
img, BuildKit🟩🟩🟩🟩🟩🟥🟩🟥🟥Local CLICLI to build the images. Can build different architectures on a single machine. Requires Seccomp disabled and AppArmor disabled.
Docker in docker🟩🟩🟩🟥🟥🟥🟩🟩🟩Local CLIBefore Kubernetes 1.20, it was possible to build container images in the agent, using the Docker socket. This is not possible anymore, as Kubernetes deprecated the Docker socket in favor of the Container Runtime Interface.

We choose BuildKit for this project. Its license allows commercial use, and the project and mainly maintained, as the time of writing, by Docker, Netlix and Microsoft.

Linux systems are supported, but not Windows:

RefContainer build inside of the agent with BuildKit
ghcr.io/clemlesne/blue-agent:bookworm-main
ghcr.io/clemlesne/blue-agent:bullseye-main
ghcr.io/clemlesne/blue-agent:focal-main
ghcr.io/clemlesne/blue-agent:jammy-main
ghcr.io/clemlesne/blue-agent:ubi8-main
ghcr.io/clemlesne/blue-agent:ubi9-main
ghcr.io/clemlesne/blue-agent:win-ltsc2019-main
ghcr.io/clemlesne/blue-agent:win-ltsc2022-main

How to use the bundled BuildKit

There are two components, the backend, buildkitd, and the CLI, buildctl.

Requirements:

# azure-pipelines.yaml
variables:
  - name: container_name
    value: my-app
  - name: container_registry_domain
    value: my-app-registry.azurecr.io

steps:
  - bash: |
      # Start buildkitd
      rootlesskit buildkitd --oci-worker-no-process-sandbox --addr $BUILDKIT_HOST &
      # Wait for buildkitd to start
      while ! buildctl debug workers; do sleep 1; done      
    displayName: Run BuildKit

  - bash: |
      buildctl build \
        --frontend dockerfile.v0 \
        --local context=. \
        --local dockerfile=. \
        --output type=image,name=$(container_registry_domain)/$(container_name):latest,push=true      
    displayName: Build and push the image

Out of the box, argument --opt platform=linux/amd64,linux/arm64 can be added to build an image compatible with multiple architectures (more can be specified). Multiple cache strategies are available (including container registry, Azure Storage Blob, AWS S3).

BuildKit and the performance

BuildKit works by virtualization in the user space. You can’t expect build times as short as native (on your laptop for example). QEMU is used as a backend. This has the advantage of being able to create images for different architectures than your processor. Virtualization-wise, not all CPU models are equivalent, you can refer to the official project documentation to select the most appropriated CPU model for your Kubernetes Node Pool.

Last updated on