Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dummy downsize after Docker build

Using multi-stage builds, I want to downsize an image at the end of Dockerfile, something like this:

FROM ubuntu AS ubuntu_build

RUN # do a lot of build things

FROM alpine

COPY --from=ubuntu_build /app /app

ENTRYPOINT whatever

the alpine image is small, and in theory only the /app stuff will get copied from the ubuntu image, is this the best trick in the book, or is there some other way to minimize the size of the final image?

like image 488
Alexander Mills Avatar asked Jul 02 '19 23:07

Alexander Mills


2 Answers

Distroless

Google provides instructions and tools to help make distroless images.

"Distroless" images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution.

Why should I use distroless images?

Restricting what's in your runtime container to precisely what's necessary for your app is a best practice employed by Google and other tech giants that have used containers in production for many years. It improves the signal to noise of scanners (e.g. CVE) and reduces the burden of establishing provenance to just what you need.

If your app is a compiled binary then you could get away with a single binary plus the shared libraries it links against. If you limit the libraries you link against you might only need a couple. Here, for instance, is what a minimal C program compiled with gcc links against on my machine:

$ ldd basic-program
        linux-vdso.so.1 (0x00007fffd3fa2000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2e4611b000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f2e4670e000)

Heck, you could even statically link the entire program and have no dependencies at all.

Google provides a set of base images targeted at different languages:

  • gcr.io/distroless/static (Go, Rust, D)
  • gcr.io/distroless/base (C, C++)
  • gcr.io/distroless/java (Java)
  • gcr.io/distroless/cc (Rust, D)

They have only some bare essential files, far less than what even a minimal distro like alpine pulls in, since it still has the apk package manager, userspace utilities, etc. You use them the same way you describe in your question: as the last stage in a multi-stage build.

FROM gcr.io/distroless/base
COPY --from=build /go/bin/app /
CMD ["/app"]

FROM scratch

You can also go the full raw-food-living-in-the-woods route and build your final image FROM scratch. It doesn't get any purer than that. There's absolutely nothing that you didn't put there yourself. This is the route traefik chose, for instance.

FROM scratch
COPY certs/ca-certificates.crt /etc/ssl/certs/
COPY traefik /
EXPOSE 80
VOLUME ["/tmp"]
ENTRYPOINT ["/traefik"]
like image 131
John Kugelman Avatar answered Sep 28 '22 06:09

John Kugelman


Besides use multi-stage, another typical way is use docker-slim to reduce the size of final built out image, like next:

docker-slim build --http-probe your-name/your-app

Detail refers to this guide

Add other common thoughts excerpt from "Five Ways to Slim Your Docker Images" in case you needed:

  • Think Carefully About Your Application’s Needs
    • Just install what you really needed in dockerfile.
  • Use a Small Base Image
    • Could use Alpine Linux or even directly from scratch, see how to create-the-smallest-possible-docker-container
  • Use as Few Layers As Possible
    • Combine run together, more run more layers, more layers more size
  • Use .dockerignore files
    • This avoid copy all things to images if use COPY . /, more, if not use .gitignore, you then need to avoid to use COPY . / which may copy some necessary things to image.
  • Squash Docker Images
    • The idea here is that after your image is created, you then flatten it as much as possible, using a tool such as docker-squash.
like image 44
atline Avatar answered Sep 28 '22 07:09

atline