How to create your own Docker base images from “Scratch” – CloudSavvy IT

Docker images were created from a Dockerfile which defines a base image and a series of instructions that add your own file system layers. What happens if you want to make yours own “Basic image” though? How to start from scratch and create a complete container file system from scratch.

What is a picture?

Docker images generally use a popular Linux distribution as their base image. If you have written FROM ubuntu:latest, FROM debian:latest or FROM alpine:latest, you have used an operating system as your base. You can also use an image that is preconfigured for a specific programming language or frame, e.g. FROM php:8.0 or FROM node:16.

All of these images are a useful starting point for your applications. They come with standard Unix tools and key software packages. However, all of this increases the size of your final image. A truly minimal image should be built by constructing your own file system based on the first principles.

The “scratch” image

Docker provides a special base image that indicates that you want to control the first file system layer. This is the bottom layer of your image, usually defined by the base image specified by yours FROM instruction.

When you want to create an image “from scratch”, type FROM scratch in your Dockerfile is the way to it! This gives you a file system that is an empty slate to begin with.

FROM scratch

You will then need to use the rest of your Docker file as usual to populate the container file system with the binaries and libraries you need.

What is “scratch”?

That scratch “Image” looks and feels like a regular Docker image. It’s even listed in the Docker Hub. scratch however, is not really an image – it is a reserved keyword that indicates the lowest file system layer in a working image. All Docker images are on top scratch as their common foundation.

You can not docker pull scratch and it is not possible to run containers using it. It represents an empty image layer, so there is nothing for Docker to run. Images cannot be marked as scratch either because of its reserved nature.

What can be added to scratch-based images?

You do not need much to build a working image on top of that scratch. All you need to add is a statically compiled Linux binary that you can use as your image command.

Here is a working demo running a small “hello world” program prepared from C:

#include <stdio.h>
 
int main() {
    printf("Hello World");
    return 0;
}

Compile your C code into a binary:

gcc -o helloworld hello.c

Run your binary and observe that “hello world” is printed to your terminal:

./helloworld

Now you can create a scratch-based Docker container that runs your binary:

FROM scratch
COPY helloworld /
CMD ["helloworld"]

Build your image:

docker build -t hello:latest .

Inspection of the image with docker inspect will show that it has a single layer. The image system of this image contains only one file, helloworld binary.

Now run a container using your image:

docker run hello:latest

You will see “hello world” in your terminal when your compiled binary is executed. Your scratch-based image contains only your binary, so it will only be a few KB in size. Using any operating system-based image would increase it to several megabytes, even with a minimal distribution like Alpine.

Virtually all images will have some dependencies beyond a simple static binary. You need to add these to your image as part of your Docker file. Keep in mind that none of the tools you take for granted in standard Linux distributions will be available until you manually add them to the image file system.

When to use Scratch?

The decision to start from scratch must be based on your application dependencies and your image portability goals. Pictures built from scratch is best suited for hosting statically compiled binaries where image size and build times matter.

scratch gives you a clean slate to work from, so it requires an initial investment to write yours correctly Dockerfile and maintain it over time. Some Docker commands can e.g. attach does not work by default as there will be no shell inside your container unless you add one.

Using scratch could be more problems than it is worth when using interpreted languages ​​with major environmental dependencies. You need to constantly update your base image to refer to the latest versions of these packages. It is usually more convenient and maintenance to use a minimal taste of an existing Docker Hub base image.

Summary

FROM scratch in a Docker file indicates that you want to boot from an empty file system where you have control over each layer that is added. It facilitates highly streamlined images cleaned of everything except the dependencies your application needs.

Most developers probably will not use it scratch directly as it is unsuitable for the majority of containers. You can choose to use it if you want to contain independent static binaries with few environmental requirements.

scratch also serves as a clear indicator of the difference between “containers” and VMs. An image that contains only one executable file is a usable Docker container, as the process runs on your host’s kernel. An ordinary VM must start independently of its host, so it must include a full operating system core in its image.

Leave a Comment