Hello World! Until now, you and I have relied on the Docker team's base images (ubuntu, alpine, and so on), but have you considered how we may construct our own base image from the ground up, rather than relying on someone else's base image? No more wait! In this post, I will guide you with two ways to create your own images from scratch: via File System and Scratch image
Before moving forward, I would like to clear some confusion between parent image, base image, and scratch image. If you already know that, feel free to skip this. Every Dockerfile starts with the
FROM directive which is used to tell the docker runtime which image to use as an underlying base image and perform operations on top of it.
A parent image is what tells the runtime to pull the image from the remote repository or use from the one already pulled. Most of the docker files start from this image instead of creating their own base image.
The base image is the one that has a special
FROM scratch directive. It will send the signal to the build system to not pull any image but to create from the start. You can say, the base image is the parent image of the parent image.
Creating from the File System
Docker image is nothing but information of files to be mounted via overlay filesystem that has all the available tools to run your application without installing any particular OS-level libraries like
libc and other standard things. To have these files, I have copied the libraries and binaries from
/usr directory to
myimage directory as shown below
Now create a
secret.txt file with some random string. I am using
openssl rand function here. After you have done this, create the
tar archive of the image and save it into the tar file of any name.
Import the files using
docker import command which requires the tar archive file and the image name. Once this is done, you will see the sha256 hash digest of the image imported and
docker images output will show the entry of the same.
Now run the docker container of
myimage:latest image we have just imported as shown below
The default command executed by docker is defined in the
ENTRYPOINTinstruction. Since that was not defined while importing the image, you can provide it manually via
--entrypoint </path/to/bin>in docker run
Let's use our image as the parent image. In the following Dockerfile, I am using the filesystem from
myimage:latest image, creating a file with name mysecret.txt and appending another string to the secrets.txt. Lastly, the entrypoint is mentioned to spawn a shell so we don't have to provide it in the run command.
Build the docker with different image name or tag or both. In this I am using the same image name
myimage but using different tag
v2. Let the runtime parse dockerfile and build the image.
Run the docker image with tag
v2. Now this time since the entrypoing is already defined, it is not required in the following command. However, docker still provides you an option to override it with the
The docker team has already noticed the need that users might require to create their own images. Keeping that in mind, they have already created a special base image known as
scratch and released on the Docker Hub
Despite being hosted on the public repository, you cannot pull it and save it to the local registry but provide it in the Dockerfile
FROM instruction which will trigger a signal in the build process that next coming file as the first one.
Compile the above code using GCC in the Linux system using the following command
Since the base image has no other libraries required by the binary, we have used
-staticflag in the GCC to tell the compiler that embed all the libraries in the binary (static linking)
Now create a Dockerfile in the current directory with the following instructions
You can see the build succeeded in a very short time and the size of the image is less than the size of the binary created by the GCC build. This is because of the compressed image size and also has some metadata with it.
When you will export the image using
docker save and then check for the file systems, you will find only 1. Extract it, you will see that there is the same file that we have added from the local file system.
Now let's run the docker image and test whether our image is working as expected or not.