본문으로 건너뛰기 Docker Multi-Stage Builds | Smaller Images

Docker Multi-Stage Builds | Smaller Images

Docker Multi-Stage Builds | Smaller Images

이 글의 핵심

Split builder and runtime stages with COPY --from, shrink C++ and Node images, pick slim or distroless bases, fix missing.so errors, and avoid Alpine/glibc mismatches.

Introduction

Multi-stage builds put several FROM lines in one Dockerfile, name stages with AS, compile in the builder stage, then COPY —from only the binary and required .so files into a small runtime image. The final image does not ship compilers, headers, or source—smaller pulls and smaller attack surface. This article focuses on patterns illustrated with C++ toolchains; the same ideas apply to Node, Go, and other compiled or bundled apps.

After reading this post

  • You understand builder vs runtime separation
  • You can write a minimal multi-stage Dockerfile
  • You can troubleshoot missing shared libraries and Alpine vs glibc issues

Table of contents

  1. Multi-stage build concepts
  2. Optimize the deployment image
  3. Common errors
  4. Conclusion

Multi-stage build concepts

Builder vs runtime

  • Multi-stage: Multiple FROM lines; name stages with AS. Build in the first stage; in the second, use a light base (alpine, distroless, debian-slim) and COPY —from=build_stage to bring only the binary and needed .so files.
  • The final image excludes compilers, headers, and build tools → smaller size and attack surface.
flowchart TB
  subgraph stage1["Stage 1: builder"]
    S1[ubuntu:22.04] --> S2[Install g++, cmake]
    S2 --> S3[Copy source]
    S3 --> S4[Build]
    S4 --> S5[myapp binary]
  end
  subgraph stage2["Stage 2: runtime"]
    R1[debian:bookworm-slim] --> R2[Install libstdc++6 only]
    R2 --> R3[COPY --from builder]
    R3 --> R4["Final image ~50MB"]
  end
  S5 -.->|COPY --from| R3

Basic multi-stage Dockerfile

The builder stage compiles with g++/cmake; the debian:bookworm-slim stage copies only myapp and installs libstdc++6 for dynamic linking.

# Stage 1: build
FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
    g++ cmake \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY . .
RUN cmake -B build && cmake --build build
# Stage 2: runtime
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
    libstdc++6 \
    && rm -rf /var/lib/apt/lists/*
COPY --from=builder /src/build/myapp /usr/local/bin/
CMD [myapp]

Dynamic vs static linking

  • Dynamic: Install libstdc++6 (and friends) in the runtime stage—usually easier to maintain.
  • Static: Options like -static-libstdc++ can reduce runtime packages—verify licensing and ABI policies.

vcpkg + multi-stage example

# ========== Stage 1: build ==========
FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
    g++ cmake git ca-certificates \
    && rm -rf /var/lib/apt/lists/*
ENV VCPKG_ROOT=/opt/vcpkg
RUN git clone https://github.com/Microsoft/vcpkg.git ${VCPKG_ROOT} \
    && ${VCPKG_ROOT}/bootstrap-vcpkg.sh -disableMetrics
WORKDIR /src
COPY vcpkg.json .
RUN ${VCPKG_ROOT}/vcpkg install
COPY CMakeLists.txt .
COPY src/ src/
RUN cmake -B build \
    -DCMAKE_TOOLCHAIN_FILE=${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake \
    && cmake --build build --target myapp
# ========== Stage 2: runtime ==========
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
    libstdc++6 libgcc-s1 \
    && rm -rf /var/lib/apt/lists/*
COPY --from=builder /src/build/myapp /usr/local/bin/
USER nobody
CMD [myapp]

Optimize the deployment image

Slim bases and clean layers

  • Base images: Alpine is tiny but uses musl—a glibc binary may not run. debian-slim, ubuntu minimal, or distroless are safer defaults for many glibc binaries.
  • Cleanup: Use apt-get install —no-install-recommends and remove /var/lib/apt/lists/ after installs to shrink layers.
  • Fewer layers: Combine RUN steps when practical.

Base image comparison

BaseSizeglibcTypical C++Notes
ubuntu:22.04~77MBYesYesEasy default
debian:bookworm-slim~80MBYesYesOften recommended
alpine:3.19~7MBNo (musl)Cautionglibc binaries won’t run
gcr.io/distroless/cc-debian12~50MBYesYesNo shell—strong isolation

distroless example

FROM debian:bookworm-slim AS builder
# ... build ...
FROM gcr.io/distroless/cc-debian12
COPY --from=builder /usr/local/bin/myapp /app/myapp
ENTRYPOINT [/app/myapp]

distroless has no shell or package manager—minimal attack surface. For debugging, override entrypoint at docker run time.

Common errors

“cannot find -lstdc++” / “undefined reference”

Cause: Runtime stage missing libstdc++. Fix:

RUN apt-get update && apt-get install -y --no-install-recommends \
    libstdc++6 libgcc-s1 \
    && rm -rf /var/lib/apt/lists/*

“error while loading shared libraries: libxxx.so.X”

Cause: Dynamic dependency missing in the runtime image. Fix: On the builder, run:

ldd build/myapp

Install missing .so in the runtime stage or COPY --from=builder the needed libraries.

Alpine: “FATAL: kernel too old” or glibc mismatch

Cause: Alpine uses musl; binaries built for glibc won’t run. Fix: Use debian-slim or distroless for glibc binaries, or build inside Alpine if you standardize on musl.

”no such file or directory” when running the binary

Cause: Missing dynamic linker or wrong architecture. Fix: file build/myapp and ldd build/myapp.

Conclusion

Multi-stage Docker builds keep heavy toolchains out of production and make runtime images easier to scan and deploy. Pair with layer caching, .dockerignore, and a registry workflow—see Docker Compose production patterns and the Node.js deployment guide for full-stack examples.


Frequently Asked Questions (FAQ)

Q. When would I use this in practice?

A. Split builder and runtime stages with COPY —from, shrink C++ and Node images, pick slim or distroless bases, fix missin…

Q. What should I read before this?

A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.

Q. Where can I study this more deeply?

A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.


Other articles related to this topic.


Keywords Covered in This Article (Related Search Terms)

This article covers Docker, Multi-Stage Build, Container, CI, distroless, Image Size, Security.