Containerize Application
Resources
Introduction
The resources mentioned above contain tutorials to get up-and-running with Docker develop and code containerization. Below you will find some specific content highlighted for clarity.
Dockerfile
Docker builds images automatically by reading the instructions from a Dockerfile -- a text file that contains all commands, in order, needed to build a given image. A Dockerfile adheres to a specific format and set of instructions which you can find at Dockerfile reference.
Multi-stage Build
Multi-stage builds are a method of organizing a Dockerfile to minimize the size of the final container, improve run time performance, allow for better organization of Docker commands and files, and provide a standardized method of running build actions. A multi-stage build is done by creating different sections of a Dockerfile, each referencing a different base image. This allows a multi-stage build to fulfill a function previously filled by using multiple docker files, copying files between containers, or running different pipelines.
For more specific reading on the specifications of a multi-stage Docker build please see here.
By default, the stages are not named, and you refer to them by their integer number,
starting with 0 for the first FROM
instruction. However, you can
name your stages, by adding an AS <NAME>
to the
FROM
instruction. This example improves the previous one by
naming the stages and using the name in the COPY
instruction. This
means that even if the instructions in your Dockerfile are re-ordered later, the
COPY
doesn’t break.
When you build your image, you don’t necessarily need to build the entire Dockerfile
including every stage. You can specify a target build stage using the
--target <NAME>
build flag. A docker build without the
--target
flag will build the final stage.
When using multi-stage builds, you are not limited to copying from stages you created
earlier in your Dockerfile. You can use the COPY --from
instruction
to copy from a separate image, either using the local image name, a tag available
locally or on a Docker registry, or a tag ID. The Docker client pulls the image if
necessary and copies the artifact from there.
You can pick up where a previous stage left off by referring to it when using the
FROM
directive.
Scratch Image
The scratch image is Docker’s reserved empty image, which is useful in the context of building base images (such as debian and busybox) or super minimal images. As of Docker 1.5.0, FROM scratch is a no-op in the Dockerfile, and will not create an extra layer in our image. The FROM scratch command signals to the build process that we want the next command in the Dockerfile to be the first filesystem layer in our image.
Since the scratch image doesn’t contain anything, it is ideal to be used as a final build image to contain the binary that was statically compiled in the build stage so that it can be executed in a minimalistic Docker container. To create statically compiled binaries, we can build them from code in, for example, Go or C/C++.
Note, an interpreted language, such as Python, needs a base system and required libraries. An Alpine container would be smallest. (See this blog post for a tutorial.)
Build Multi-platform Images
When building an image using docker build
the image is built for the
platform the command is run on. In other words, when building on an Intel based
64-bit linux OS the resulting image will be for the linux/amd64
platform.
If you want to build for a different target platform or for multiple target platforms
you can use the buildx
Docker plugin. See the working with buildx documentation page.
When the current builder instance is backed by the "docker-container" driver, you can
specify multiple platforms together. In this case, it builds a manifest list which
contains images for all specified architectures. When you use this image in
docker run
or docker service
, Docker picks the
correct image based on the node’s platform.
A useful blog post about building for ARM platforms on a linux host can be found here. For macOS and Windows using Docker Desktop the this post might be useful. Under the hood this uses QEMU with the tool set called binfmt_misc.