[SOLVED] Should I minimize the number of docker layers?

Issue

This Content is from Stack Overflow. Question asked by kidfrom

My goal is to create an image using the FROM scratch. However, I need pdftotext. Hence, I need to install poppler-utils on FROM alpine:3.16. Then, copy it to FROM scratch stage.

My concern is that:

  1. someone said that there are layers limit of 42. This reproducible code already uses 22.

What I am thinking to do:

  1. multi-stage build.
FROM alpine:3.16

RUN apk add poppler-utils

FROM scratch

(...tons of COPY --from=0)

FROM scratch

COPY --from=1 . .
  1. or RUN --mount
FROM alpine:3.16

RUN apk add poppler-utils

FROM scratch

RUN --mount=src=/,dst=/,from=0 
  (...tons of cp)

This is the current solution that I use.

Dockerfile

FROM alpine:3.16

RUN apk add poppler-utils

FROM scratch

WORKDIR /

COPY --from=0 /lib/ld-musl-aarch64.so.1 /lib/ld-musl-aarch64.so.1
COPY --from=0 /usr/lib/libpoppler.so.121 /usr/lib/libpoppler.so.121
COPY --from=0 /usr/lib/libstdc++.so.6 /usr/lib/libstdc++.so.6
COPY --from=0 /lib/ld-musl-aarch64.so.1 /lib/ld-musl-aarch64.so.1
COPY --from=0 /usr/lib/libfreetype.so.6 /usr/lib/libfreetype.so.6
COPY --from=0 /usr/lib/libfontconfig.so.1 /usr/lib/libfontconfig.so.1
COPY --from=0 /usr/lib/libjpeg.so.8 /usr/lib/libjpeg.so.8
COPY --from=0 /lib/libz.so.1 /lib/libz.so.1
COPY --from=0 /usr/lib/libopenjp2.so.7 /usr/lib/libopenjp2.so.7
COPY --from=0 /usr/lib/liblcms2.so.2 /usr/lib/liblcms2.so.2
COPY --from=0 /usr/lib/libpng16.so.16 /usr/lib/libpng16.so.16
COPY --from=0 /usr/lib/libtiff.so.5 /usr/lib/libtiff.so.5
COPY --from=0 /usr/lib/libgcc_s.so.1 /usr/lib/libgcc_s.so.1
COPY --from=0 /usr/lib/libbz2.so.1 /usr/lib/libbz2.so.1
COPY --from=0 /usr/lib/libbrotlidec.so.1 /usr/lib/libbrotlidec.so.1
COPY --from=0 /usr/lib/libexpat.so.1 /usr/lib/libexpat.so.1
COPY --from=0 /usr/lib/libwebp.so.7 /usr/lib/libwebp.so.7
COPY --from=0 /usr/lib/libzstd.so.1 /usr/lib/libzstd.so.1
COPY --from=0 /usr/lib/liblzma.so.5 /usr/lib/liblzma.so.5
COPY --from=0 /usr/lib/libbrotlicommon.so.1 /usr/lib/libbrotlicommon.so.1
COPY --from=0 /usr/bin/pdftotext /usr/bin/pdftotext

Output from $ docker build -t test .

[+] Building 0.5s (27/27) FINISHED                                              
 => [internal] load build definition from Dockerfile                       0.0s
 => => transferring dockerfile: 2.04kB                                     0.0s
 => [internal] load .dockerignore                                          0.0s
 => => transferring context: 2B                                            0.0s
 => [internal] load metadata for docker.io/library/alpine:3.16             0.0s
 => [stage-0 1/2] FROM docker.io/library/alpine:3.16                       0.0s
 => CACHED [stage-0 2/2] RUN apk add poppler-utils                         0.0s
 => [stage-1  1/22] COPY --from=0       /lib/ld-musl-aarch64.so.1 /lib/ld  0.0s
 => [stage-1  2/22] COPY --from=0       /usr/lib/libpoppler.so.121 /usr/l  0.0s
 => [stage-1  3/22] COPY --from=0       /usr/lib/libstdc++.so.6 /usr/lib/  0.0s
 => [stage-1  4/22] COPY --from=0       /lib/ld-musl-aarch64.so.1 /lib/ld  0.0s
 => [stage-1  5/22] COPY --from=0       /usr/lib/libfreetype.so.6 /usr/li  0.0s
 => [stage-1  6/22] COPY --from=0       /usr/lib/libfontconfig.so.1 /usr/  0.0s
 => [stage-1  7/22] COPY --from=0       /usr/lib/libjpeg.so.8 /usr/lib/li  0.0s
 => [stage-1  8/22] COPY --from=0       /lib/libz.so.1 /lib/libz.so.1      0.0s
 => [stage-1  9/22] COPY --from=0       /usr/lib/libopenjp2.so.7 /usr/lib  0.0s
 => [stage-1 10/22] COPY --from=0       /usr/lib/liblcms2.so.2 /usr/lib/l  0.0s
 => [stage-1 11/22] COPY --from=0       /usr/lib/libpng16.so.16 /usr/lib/  0.0s
 => [stage-1 12/22] COPY --from=0       /usr/lib/libtiff.so.5 /usr/lib/li  0.0s
 => [stage-1 13/22] COPY --from=0       /usr/lib/libgcc_s.so.1 /usr/lib/l  0.0s
 => [stage-1 14/22] COPY --from=0       /usr/lib/libbz2.so.1 /usr/lib/lib  0.0s
 => [stage-1 15/22] COPY --from=0       /usr/lib/libbrotlidec.so.1 /usr/l  0.0s
 => [stage-1 16/22] COPY --from=0       /usr/lib/libexpat.so.1 /usr/lib/l  0.0s
 => [stage-1 17/22] COPY --from=0       /usr/lib/libwebp.so.7 /usr/lib/li  0.0s
 => [stage-1 18/22] COPY --from=0       /usr/lib/libzstd.so.1 /usr/lib/li  0.0s
 => [stage-1 19/22] COPY --from=0       /usr/lib/liblzma.so.5 /usr/lib/li  0.0s
 => [stage-1 20/22] COPY --from=0       /usr/lib/libbrotlicommon.so.1 /us  0.0s
 => [stage-1 21/22] COPY --from=0 /usr/bin/pdftotext /usr/bin/pdftotext    0.0s
 => exporting to image                                                     0.1s
 => => exporting layers                                                    0.1s
 => => writing image sha256:e427868094aba36fafea50aeca50bad9b70315c651914  0.0s
 => => naming to docker.io/library/test                                    0.0s



Solution

I just wanted to see what were the differences of 2 images, one built with multiple RUNs and the other built with one RUN concatenating commands.

In the first case, the images are doing trivial operations (creating and deleting files).

Content of the “single” layer image:

FROM busybox

RUN echo This is the 1 > 1 \
    && rm -f 1 \
    && echo This is the 2 > 2 \
    && rm -f 2 \
# ... for about 70 commands

Content of the multiple layers image:

FROM busybox

RUN echo This is the 1 > 1
RUN rm -f 1
RUN echo This is the 2 > 2
RUN rm -f 2
# ... for about 70 layers

The build time is very different (multiple: 0m34,973s, singular: 0m0,568s). The container start-up time is also different but less noticeable (multiple: 0m0,435s, singular: 0m0,378s). I’ve run different times the images but the times do not change that much.

Concerning the space, I’ve looked on purpose for the worst case for the multiple layer case and as expected the multiple layer image is bigger than the single layer.

In another test, I concatenated layers that only add content to the image. The build time does not change from the previous case but the run-time case shows something a little different: the multi layer image is faster to start-up than the single layer image. Concerning the space, same results.

I don’t think this proves anything but I had fun in doing it 😛


This Question was asked in StackOverflow by gukoff and Answered by Stefano It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?