Public registries provide container images for most use cases but they might not cover all of them. That’s why container engines such as Podman & Docker and CLI tools like
buildah provide utilities for creating custom container images.
The build steps are written in a plaintext file called Containerfile and parsed by container engines (or
buildah) during the build process.
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
Steps inside the containerfile are defined using instructions such as
Container Engines go through the containerfile line-by-line and perform each step, stacking a new image layer on top of the previous one.
FROM instruction specifies the base layer container image. The base layer image could be chosen based on OS preference (like Fedora, Kali, etc.) or programming language preference (like gcc, python, etc.), or any other preference.
It is mandatory to have a
FROM instruction in the containerfile.
FROM instruction are defined using
FROM instruction is executed, the value for the variable declared in
ARG becomes inaccessible.
The Environment variables (used by other instructions or container at runtime) are declared using
= operator between the variable name and its value is optional.
LABEL is used to add metadata for container images in the form of key-value pairs. Metadata usually contains the author’s name, author’s email, version of the container image, etc.
ADD instruction will copy files/directories from the source (host OS/URL/tarball) to the destination (container image).
ADD allows permissions to be omitted on the copied files/directories with the
ADD --chown=user:group src/ dest
Builds are performed inside a build context directory on the host.
ADD will fail if the source file/directory is outside the build context.
COPY is similar to
ADD but it is limited to sources on the host, it doesn’t support URLs or tarball.
COPY is sufficient for most use cases, so it is preferred over
WORKDIR changes the current working directory (inside the image) for the next instructions.
RUN instruction executes the shell command passed as an argument.
A temporary container is created to execute the shell command and the changes on the file system (after command execution) are layered on top of existing image layers. By default, the instruction
RUN apt-get update -y will be executed as
/bin/bash -c apt-get update -y.
SHELL instruction is used in containerfile to change the default shell for
RUN, for example,
SHELL ["/bin/zsh", "-c"] will change the default shell from
EXPOSE specifies the network ports to be used by the container on runtime. The ports still have to be published when the container is provisioned.
CMD adds a shell command that will be executed on container startup.
CMD instructions could be written as
CMD param1 param2 or
CMD ["/bin/executable", "param1", "param2"].
CMD instruction can define the behavior of the container on startup, for example, a webserver container should start the webserver automatically on startup by running the invocation command defined in
If the executable on container startup is expected to be the same in most conditions then it is preferable to add
CMD. Parameters for the executable could be passed from
CMD ["param1", "param2"]
To create a mount point inside the container,
VOLUME instruction can be used. During runtime, the
--volume flag is used to map a directory on the host to the mount point declared by
VOLUME instruction. The data stored on the mount point will persist after container execution.
The command added in the
ONBUILD instruction is executed when the built image is used as the base container image.
If container image
container-image-a as a base image, then the
ONBUILD instruction defined in
container-image-a will be triggered after
FROM instruction is executed in
Execution of ONBUILD instruction
ONBUILD, the developers can ensure that any new image built upon their container image has the latest source code or that packages are up-to-date.
ONBUILD RUN git clone source-code-repo-link.git
USER instruction sets
GID during the build process.
Building container images using Docker
Docker and Podman provide
build subcommand for building container images from containerfile.
docker build .
. will be substituted with the current working directory on the host.
By default Docker expects Dockerfile (instead of Containerfile) in the build context,
--file flag could be used to pass the path to containerfile.
docker build --tag node-application:latest . --file ./Containerfile
Container Engines cache the built layers to save time and storage. Cached layers are reused in other image builds to disable this behavior
--no-cache flag could be used with the
--rm flag ensures that the intermediate container images are removed once the build process is successful.
Adding files with sensitive data to
.dockerignore will make sure that they aren’t included in the container image.
Building container images using buildah
buildah provides a
bud subcommand for building container images from containerfile.
buildah bud --tag "webserver:latest" .
Images built by
buildah could then be executed using Podman and Docker or any other OCI image-compatible container engine. Podman also has a
build subcommand for building container images and it uses the same code as
buildah provides finer control over image building process that allows users to
- Create base images using the scratch image, an image with a minimal footprint.
- Mount a container’s root filesystem, useful for debugging container-related issues.
- Create a container image from a working container, helpful if Containerfile isn’t accessible.
- Execution of containerfile instructions using subcommands. For example,
RUNinstruction could be executed on a container image using
buildah run. Similarly for
- Debug image building process by executing instructions manually with buildah.
- Making ad-hoc changes to existing container images.
- Automating build process.
Thank you for taking the time to read this blog post! If you found this content valuable and would like to stay updated with my latest posts consider subscribing to my RSS Feed.
About the Open Container Initiative
OCI Image Manifest Specification
Image Layer Filesystem Changeset
OCI Image Configuration
About storage drivers
scratch container image
Buildah Tutorial 1
Buildah and Podman relationship