Building a small docker image with a C executable

The problem with building an executable from a C program in Docker is that the image is extremely large. The way I chose to handle it for this experiment was to make a throwaway image to compile the C program, then copy that built executable into a much smaller container.

The C program for this proof-of-concept

This is, of course, the ubiquitous hello-world program:

#include <stdio.h>

int main() {
	printf("Hello, world\n");

The Dockerfile

FROM gcc:4.9 AS build
COPY Hello.c .
RUN gcc -static -o myapp Hello.c

# Base image is an explicitly empty image. 
# It has no shared object, it has no runtime libraries.
# Make sure you compile your binary with -static flags.

FROM alpine
COPY --from=build /app/myapp /app/myapp
CMD ["/app/myapp"]


  • First block sets up the build environment, and calls it build
  • The application is built here
  • In theory I could strip the executable, but I haven’t bothered to
  • The second block uses a miniscule base image
  • It then copies the executable from the first image
  • It then makes that executable the runable application

End result:

hello       latest  a92e11966d72  About a minute ago  5.11MB
<none>      <none>  cd28adb1bc19  About a minute ago  1.37GB

As you can see, the non-named image (cd28adb1bc19) is 1.37 GB as it contains a complete C development environment. But what we really want is a fraction of the size - only 5 MB.

Running docker commands

docker build -t hello .
docker run --rm hello

Proof it works!

Running docker commands

Final notes

In theory this could be smaller:

# ls -ltrh
total 948K
-rw-r--r-- 1 root root   63 Aug  6  2017 Hello.c
-rwxr-xr-x 1 root root 942K Jan 19 18:29 myapp

# strip myapp

# ls -ltrh
total 736K
-rw-r--r-- 1 root root   63 Aug  6  2017 Hello.c
-rwxr-xr-x 1 root root 730K Jan 19 18:54 myapp

Gaining that extra 212 KB is not worth it for my proof-of-concept, but your milage may vary.