Skip to content

container#

Overview#

Build, lint, and publish OCI container images in CI.

Building#

Two build strategies are defined:

  • Docker-in-Docker (planned): Build on a runner with the Docker socket mounted.
  • Kaniko: Build using Google's Kaniko tool.

For the most common use cases, the Kaniko pipeline is recommended, as it has minimal requirements for use.

Linting#

A hadolint job is defined for Dockerfile validation.

Versioning#

Two tags are produced for every pipeline that runs:

  • ${CONTAINER_VERSION}
  • ${CONTAINER_VERSION}-${CI_COMMIT_SHORT_SHA}

In addition, the default branch also publishes the latest tag.

It is recommended to garbage collect old tags.

Usage#

Project setup#

A Dockerfile in the project root is the minimum requirement to use this pipeline.

Variables#

The pipelines defined in this project consume some or all of the variables defined on this page.

CONTAINER_BUILD_OPTS

Extra options to pass to the container build command.

See Pass container build options for more details.

CONTAINER_COMMIT_SHA

Commit SHA for the container pipeline. Defaults to ${CI_COMMIT_SHA}.

variables:
  CONTAINER_COMMIT_SHA: "
CONTAINER_COMMIT_SHORT_SHA

Commit short SHA for the container pipeline. Defaults to ${CI_COMMIT_SHORT_SHA}.

CONTAINER_CONTEXT

Container build context. Defaults to ${CI_PROJECT_DIR}.

Example:

variables:
  CONTAINER_CONTEXT: "${CI_PROJECT_DIR}/some/project/subpath"
CONTAINER_DOCKER_ARCH

docker-multiarch only

This is the name of the machine architecture as defined by Docker.

Common architectures:

  • amd64: x86 64-bit
  • i386: x86 64-bit
  • arm64v8: ARMv8 64-bit
  • arm32v6: ARMv6 32-bit
  • arm32v7: ARMv7 32-bit

For all possible architecture values, see this page.

CONTAINER_DOCKER_PLATFORM

docker-multiarch only

This is the value that the docker CLI expects when using the --platform flag.

Common platforms:

  • linux/amd64: Linux, x86 64-bit
  • linux/386: Linux, x86 32-bit
  • linux/arm64: Linux, ARMv8 64-bit
  • linux/arm/v6: Linux, ARMv6 32-bit
  • linux/arm/v7: Linux, ARMv7 32-bit

This list can be generated by running docker buildx ls.

CONTAINER_DOCKERFILE

Container build Dockerfile. Defaults to ${CI_PROJECT_DIR}/Dockerfile.

Example:

variables:
  CONTAINER_DOCKERFILE: "${CI_PROJECT_DIR}/deploy/docker/Dockerfile"

A fully qualified path to the Dockerfile is required.

CONTAINER_IMAGE

Full name of container image tag. Defaults to ${CONTAINER_NAME}:${CONTAINER_VERSION}.

Example:

variables:
  CONTAINER_IMAGE: "${CONTAINER_NAME}:${CONTAINER_VERSION}"
CONTAINER_MULTIARCH_PLATFORMS

docker-multiarch only

Configures the docker-multiarch pipeline to build for multiple architectures.

Defaults to amd64 arm32v6 arm32v7 arm64v8 i386, which enables all currently supported architectures.

variables:
  # only build for arm
  CONTAINER_MULTIARCH_PLATFORMS: arm32v6 arm32v7 arm64v8

For a list of supported values, see CONTAINER_DOCKER_ARCH.

CONTAINER_NAME

Defaults to ${CONTAINER_REGISTRY}${CONTAINER_NAME_SUFFIX}.

variables:
  CONTAINER_NAME: "docker.io/jdoe/mycontainer"
CONTAINER_NAME_SUFFIX

Defaults to an empty string.

variables:
  CONTAINER_NAME_SUFFIX: "/variant"
CONTAINER_PROXY

Defaults to ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/.

variables:
  # proxy images through harbor.example.com
  CONTAINER_PROXY: "harbor.example.com/docker/library/"

Note

Only GitLab Dependency Proxy is currently supported.

For more info, see Configure a Docker Hub proxy.

CONTAINER_REGISTRY

Container registry to publish images to. Defaults to ${CI_REGISTRY_IMAGE}.

Example:

variables:
  # push to another project's registry
  CONTAINER_REGISTRY: "registry.gitlab.com/brettops/example/project"
CONTAINER_REGISTRY_USER

Defaults to ${CI_REGISTRY_USER}.

CONTAINER_REGISTRY_PASSWORD

Defaults to ${CI_REGISTRY_PASSWORD}.

CONTAINER_VERSION

Defaults to ${CI_COMMIT_REF_NAME}${CONTAINER_VERSION_SUFFIX}.

variables:
  # pull the version from another variable
  CONTAINER_VERSION: "${ANOTHER_VERSION_VARIABLE}"
CONTAINER_VERSION_SUFFIX

Defaults to an empty string.

variables:
  # append '-ubuntu' to the image tag
  CONTAINER_VERSION_SUFFIX: "-ubuntu"

Default pipelines#

docker pipeline#

This pipeline is a minimal container build with Docker + BuildKit. It's useful for when you need the extra features of BuildKit, but has a slower startup time.

Usage#

Include the pipeline in the .gitlab-ci.yml file:

gitlab-ci.yml
include:
  - project: brettops/pipelines/container
    file: docker.yml

docker-multiarch pipeline#

This pipeline builds full multi-arch Docker containers. It builds them in separate jobs for parallelism and then recombines them in a later manifest creation job.

Usage#

Include the pipeline in the .gitlab-ci.yml file:

gitlab-ci.yml
include:
  - project: brettops/pipelines/container
    file: docker-multiarch.yml

Optionally, define architectures to build in a space-separated list. Defaults to all available:

variables:
  CONTAINER_MULTIARCH_PLATFORMS: amd64 arm32v6 arm32v7 arm64v8 i386

For a list of supported values, see CONTAINER_DOCKER_ARCH.

kaniko pipeline#

This pipeline builds containers via Kaniko. Kaniko lacks many features of Docker, but it's highly portable across runner executors as it can run without root access.

Usage#

Include the pipeline in the .gitlab-ci.yml file:

gitlab-ci.yml
include:
  - project: brettops/pipelines/container
    file: kaniko.yml

Custom pipeline#

The following snippet shows how a custom pipeline might be defined:

stages:
  - test
  - build
  - deploy

workflow:
  rules:
    - if: $CI_PIPELINE_SOURCE == "push" && $CI_OPEN_MERGE_REQUESTS
      when: never
    - when: always

include:
  - project: brettops/pipelines/container
    file: .include.yml

container-hadolint:
  extends: .container-hadolint

container-docker:
  extends: .container-docker

container-kaniko:
  extends: .container-kaniko

Use cases#

Image tag names#

${CONTAINER_REGISTRY}${CONTAINER_NAME_SUFFIX}:

The following variables are available to customize the generated image tag names:

Pass build options#

This section is a stub. Please help by expanding it.

The CONTAINER_BUILD_OPTS variable may be used to pass extra arguments to the container build command.

Docker and Kaniko sometimes have different names for the same option.

--build-arg#

--build-arg is the same for Docker and Kaniko.

container-kaniko:
  variables:
    CONTAINER_BUILD_OPTS: >-
      --destination ${CONTAINER_NAME}:3.4.4-${CONTAINER_VERSION}
      --destination ${CONTAINER_NAME}:3.4-${CONTAINER_VERSION}
      --destination ${CONTAINER_NAME}:3-${CONTAINER_VERSION}
container-kaniko:
  variables:
    CONTAINER_BUILD_OPTS: >-
      --build-arg PIP_INDEX_URL=$PYTHON_PYPI_DOWNLOAD_URL
      --platform linux/arm/v6

--tag (docker) / --destination (kaniko)#

TBD.

Cross-platform container build support#

This section is a stub. Please help by expanding it.

Use a custom build context#

This section is a stub. Please help by expanding it.

Use a custom Dockerfile#

This section is a stub. Please help by expanding it.

Use a custom registry#

This section is a stub. Please help by expanding it.

Use a Docker Hub proxy#

Docker Hub rate limits container image pulls. These limits are easily hit in a CI environment, so it's recommended to enable a container proxy.

GitLab's Dependency Proxy feature allows you to proxy Docker Hub containers through GitLab. However, rather than use these values directly, use the CONTAINER_PROXY variable to make it easy to change proxy location in the future without updating every repository.

When this pipeline is included, CONTAINER_PROXY is set by default to the following value:

variables:
  CONTAINER_PROXY: "${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/"

Note the trailing /! This allows projects to continue to function if CONTAINER_PROXY is not configured.

It's recommended to configure CONTAINER_PROXY at the group level, so that CI jobs can use proxied containers. Here is an example that uses the image keyword.

image: "${CONTAINER_PROXY}alpine:latest"

This pipeline will automatically add CONTAINER_PROXY as a --build-arg, so you can proxy FROM images in Dockerfiles as well:

ARG CONTAINER_PROXY
FROM ${CONTAINER_PROXY}node:lts-bullseye

Use a private PyPI repository#

This section is a stub. Please help by expanding it.