Grammars for Building Container Images
Table of Contents
ContainerFile and DockerFile are almost the same, the difference between which is simply that the former is the default for podman, while the latter is the default for docker.
1. Basic Structure of an Image Build
The container image is constructed within 5 stages: we start from base image, then install packages inside this image, copy application-specific files, configuration necessary environment (e.g., environment variables, settings up toolchains), and define the startup command.
Since we always start from base image, this design actually kind of defines a fixed procedure of “how to transform the image”, making the product reproducible.
2. Essential Commands
FROM <image[:tag]>We can use the
FROMcommand to configure the base image to build on. For example,FROM ubuntu:24.04tells podman it should build on top of Ubuntu 24.04.Moreover, we can use multiple
FROM ... ASstatements, so that followingFROMstatements can use the results produced in formerFROMstatements.RUN <command>- Executes commands during build. If
<command>is normal executable bash command, then it will be executed by/bin/sh; if<command>is a list of strings, then it will involve shell to execute.
- Layer
- Each statement creates a “layer” of the image. Docker images are a stack of immutable layers, each command “transforms” the previous layer into a new layer.
COPY <source> <destination>Copy some file or directory into other location. We can copy files as another file, copy file to directory, or copy directory as another directory.
# copy file to file COPY app.py /app/app.py # copy folder to folder COPY src/ /app/src/ # Use dot to copy everything COPY . /appADD <source> <destination>- An extension to
COPYthat can automatically extract archives, and support downloading from URLs. WORKDIR <path>- Set working directory. This means that, the following relative file paths will be relative to this working directory.
ENV <key=value>- Sets global environment variables.
ARG <key=value>- Build-time variables. These environment variables are only available during docker build.
EXPOSE <port>- It means the application listens on in-image port. It does not publish the port. This should be done via setting
-p <pub-port>:<in-image-port>instead through docker CLI or configuration files. CMD <command>- Defines what happens when the container starts. Similar to
RUN, the<command>can also be a list of strings. But unlikeRUN, it’s recommended to use list of commands forCMDbecause the signals can be received by apps correctly, instead of agented by shell. ENTRYPOINT <command-as-list>- This command fixes the executable used in later
CMD. For example,ENTRYPOINT ["python3"]; CMD ["app.py"]executespython3 app.py USER <username>- Change the default user (
root). Should first create a user usingRUN useradd ... VOLUME <path>- Sets up an in-container folder which is indeed an external folder, so that data in this “internal” folder can be retrieved by external system. Useful for databases, logs, user data.
LABEL <key=value>- Just configures the metadata of the image itself.
.dockerignoreor.containerignore- Similar functionality as
.gitignore, useful when copying the entire directory yet to exclude a few. HEALTHCHECK CMD <command>- Defines how the container is regarded as healthy. Docker periodically runs the
<command>, the container becomes unhealthy on healthcheck failure.