Creating your base Docker image is quite straightforward. Just as we used the docker commit command previously to create an image from a running container, we can also create an image from a system or server where our applications are originally hosted. However, it’s crucial to keep the base image small and lightweight. Simply moving existing applications from traditional servers to Docker isn’t enough.
If you’re using a production server, the resulting image could end up quite large. For smaller virtual machines that seem ideal for a base image, you can follow these steps to create one. Similar to the docker commit command, this method works for any system you have access to.
Creating Custom Base Docker Images
Let’s take the Docker image we’re already using (basic-server) and transform it into a custom base image. This is a simple demo, but the same process works for bigger, more complex setups.
First, we need to start the container and connect to it at the same time. Here’s how
Use the docker image save command to create a backup of the repository:
Create a new image using the docker load command.
This example has demonstrated how to generate a base image from an existing running system or environment. However, if your goal is to create a minimal base image, the next section will explain how to utilize the scratch image.
The SCRATCH Image
The scratch image is Docker’s secret weapon for building incredibly lean and efficient images. It’s essentially a blank slate, devoid of any operating system or pre-installed software, making it the perfect starting point for running compiled binary applications like those written in Java or C++. These binaries are self-contained and don’t rely on external libraries or dependencies, allowing them to run directly on the minimal environment provided by the scratch image.
By using the FROM scratch directive in your Dockerfile, you signal to Docker that you want to build an image with the absolute minimum footprint. This results in a container image that is remarkably small and lightweight, as it doesn’t include any unnecessary overhead from an operating system or additional software layers.
Using the SCRATCH Image
In this example, we’ll craft a simple C application to showcase how to build one of the most minimal Docker base images possible. While prior knowledge of C programming isn’t required, this hands-on experience will demonstrate the process of creating a highly efficient and compact image using Docker’s “scratch” image as our foundation. By leveraging the scratch image, we can eliminate any unnecessary dependencies and produce an image with a remarkably small footprint. Let’s get started.
Try getting the scratch image using the docker pull command
You will notice that you will get an error
Error response from daemon: ‘scratch’ is a reserved name
Create a C program that we will build into the image to use in our Dockerfile.
Add the following C code:
int main() {
int height = 12;
int i, j, spaces;
for (i = 1; i <= height; i++) {
for (spaces = height – i; spaces > 0; spaces—) {
printf(” “);
}
for (j = 1; j <= 2 * i – 1; j++) {
printf(“*”);
}
printf(“n“);
}
return 0;
}
This C program crafts a Christmas tree composed of asterisks based on user-specified height. It employs a series of nested loops to achieve this. The outer loop controls the number of rows, starting from the top of the tree and iterating downwards. For each row, an inner loop determines the number of spaces preceding the asterisks, ensuring the tree’s triangular shape.
Another inner loop handles the actual printing of asterisks, with the number of asterisks increasing by two with each descending row. This creates the tree’s wider base. A newline character is printed after each row, moving the cursor to the next line for the subsequent row’s output. The result is a beautifully constructed Christmas tree in the console, ready to spread festive cheer!
Build the image form the command line by running the following command to build the C program
Now lets create the Dockerfile. The Dockerfile will be pretty minimal but needs to start with FROM scratch. The rest of the file will add the C program and then run it
ADD christmas-tree.exe /
CMD [“/christmas-tree.exe”]
Build a new image. In this instance, call the image scratch-test using the following command
Run the image from the command line
Run the docker images command for your new image
This will show some pretty impressive results with a size of 41.2kB in size
scratch-test latest 817c50b9dbe6 3 minutes ago 41.2kB
View the layers of the image using the docker history command
You will see a similar output to the following one
817c50b9dbe6 5 minutes ago CMD [“./christmas-tree.exe”] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago CMD [“ls”] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago ADD christmas-tree.exe / # buildkit 41.2kB buildkit.dockerfile.v0
Alright, the scratch image we whipped up in this exercise shows how to make a Docker image that’s both super-lean and still gets the job done. It also proves that if you put some thought into your goals, you can easily speed up your builds and shrink those images down to size.
Conclusion
Creating a base Docker image is a straightforward process, but it’s important to keep the image small and lightweight. You can create a custom base image from an existing running system or environment using the docker save and docker load commands.
Additionally, Docker’s “scratch” image is a powerful tool for building minimal and efficient images, especially for compiled binary applications. By using the FROM scratch directive in your Dockerfile, you can create a container image with the absolute minimum footprint. This results in a remarkably small and lightweight image that eliminates unnecessary dependencies.
Overall, by following these techniques, you can optimize your Docker images for better performance and efficiency.
In the next post, let’s take a breather from building for a moment and dive into the world of naming and tagging our Docker creations. After all, organizing our work is just as important as creating it