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:
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"]