Geoff Garbers

Husband. Programmer. Tinkerer.

Using multi-stage builds to reduce Docker image sizes

Nov 15, 2017

Traditionally, copying in large files (or a directory containing a large number of files) and then running a chown or chmod on those causes a fairly dramatic increase in the final size of your Docker image (depending on the size of the files being modified).

The following Docker files provide a base to test this on (after generating a large file with dd if=/dev/zero of=bigfile count=102400 bs=1024):

# Dockerfile: without_chown
FROM alpine:3.6
COPY bigfile /
# Dockerfile: with_chown
FROM alpine:3.6
COPY bigfile /
RUN chown nobody:nobody /bigfile && chmod 0600 /bigfile

Building using those files will provide the following images:

with_chown          latest      3bf018e061dd        6 seconds ago       214MB
without_chown       latest      0ed1c7c0c62b        26 seconds ago      109MB

This Stack Overflow answer provides a good explanation for this increase in the image size. Thanks to this GitHub pull request, at least one of these problems has been solved by allowing the use of a --chown flag to be passed to the COPY command:

FROM alpine:3.6
COPY --chown=nobody:nobody bigfile /
RUN chmod 0600 /bigfile

However, running this still results in an inflated image size, due to the chmod command being run. Using multi-stage builds can help resolve this (requires Docker 17.05 or higher):

FROM alpine:3.6
COPY /bigfile /
RUN chmod 0600 /bigfile

FROM alpine:3.6
COPY --from=0 --chown=nobody:nobody /bigfile /bigfile

Using a multi-stage build like this, results in the following build size, with all the permissions and ownerships intact:

with_multistage     latest      bf1f27f308e2        3 minutes ago       109MB
with_chown          latest      da90bf59d0b4        11 minutes ago      214MB
without_chown       latest      0ed1c7c0c62b        21 minutes ago      109MB

/ # ls -lah /bigfile 
-rw-------    1 nobody   nobody    100.0M /bigfile