Building Container Images

From Leo's Notes
Last edited on 23 February 2022, at 22:16.

Container build Tools[edit | edit source]

The easiest way to build container images is to use Docker and a Dockerfile. However, since Docker isn't cool anymore, there are some other options that may be worth looking into which will be covered in the following subsections.

Docker[edit | edit source]

The tried and true method to build container images. However, Docker itself can be a bit resource heavy and requires a daemon to be running on the system.

A container is defined in a Dockerfile and built with the docker build command.

BuildKit[edit | edit source]

BuildKit is a new code base for building containers that's been part of Docker since version 19.03. It supports some interesting features such as more efficient caching, concurrent dependency resolution, and distributed workers, among other things. A container build is typically faster because of these performance enhancements. Best of all, it uses the same Dockerfile format as Docker.

A container build can be done right now by export the DOCKER_BUILDKIT=1 environment variable while calling docker build.

Buildah[edit | edit source]

Buildah is the container building component of podman, Red Hat's replacement to Docker. Containers are built with Dockerfiles (though not all features are supported) using the the podman build command.

Container build tips[edit | edit source]

Review the Dockerfile best practices at https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

RUN commands[edit | edit source]

Try to bundle multiple RUN commands together to reduce the number of container image layers and their overall size. Concatenating multiple commands with && or ; (with set-x, which stops the script when a non zero exit code is returned).

RUN set -ex; \
   yum -y install vim; \
   yum clean all

## or,
RUN yum -y install vim && yum clean all

Remember to clean up at the end of each RUN to minimize the layer sizes. Things you can do include:

  • rm -rf /tmp/* /var/cache/* /var/tmp/*
  • Clean up package manager caches and remove unnecessary build-only packages

Better yet, use multi-staged builds (https://docs.docker.com/develop/develop-images/multistage-build/) to bundle the results of multiple layers into one.

FROM centos:8 as build
RUN yum -y update
RUN yum -y install vim

FROM centos:8
## We can copy specific artifacts from the build container. Eg:
COPY --from=build /usr/bin/vim /usr/bin/vim


Yum/dnf-based package managers[edit | edit source]

Yum or dnf package managers are used on Red Hat based distros.

  • Install packages with yum -y install to avoid prompts
  • At the end of the run, yum -y clean all, and clean up caches rm -rf /var/cache afterwards

Apt-based package managers[edit | edit source]

Apt-based package managers are used on Ubuntu and Debian based distros.

  • Prepend your apt install command with DEBIAN_FRONTEND=noninteractive to prevent some packages from prompting interactive input (tzdata for example), which leads to indefinite waiting for an user input. Don't set this as an environment variable since it will linger after the container is built.
  • At the end of the run, rm -rf /var/lib/apt/lists/* to clean up.

apk-based package managers[edit | edit source]

Alpine Linux uses the apk package manager. One neat feature with apk is the ability to group packages into virtual groups which we can uninstall with one command.

  • Create virtual groups for build dependencies using apk add --virtual=build-deps make gcc. These groups can later be removed with apk del --purge build-deps.
  • At the end of the run, /var/cache/apk/* to clean up.