dockerdockerfiledocker-multi-stage-build

Docker multi stage build


I came across this example . Here they made a 3 stage build. Is it necessary to have a 2nd stage (build-venv) ?

Is it mentioned that having it can have an advantage of "Build the virtualenv as a separate step: Only re-execute this step when requirements.txt changes". But I was under assumption that docker is intelligent enough to not build the image layer if it is not changed.

Is there any difference between

original Dockerimage

# Build a virtualenv using the appropriate Debian release
# * Install python3-venv for the built-in Python3 venv module (not installed by default)
# * Install gcc libpython3-dev to compile C Python modules
# * In the virtualenv: Update pip setuputils and wheel to support building new packages
FROM debian:11-slim AS build
RUN apt-get update && \
    apt-get install --no-install-suggests --no-install-recommends --yes python3-venv gcc libpython3-dev && \
    python3 -m venv /venv && \
    /venv/bin/pip install --upgrade pip setuptools wheel

# Build the virtualenv as a separate step: Only re-execute this step when requirements.txt changes
FROM build AS build-venv
COPY requirements.txt /requirements.txt
RUN /venv/bin/pip install --disable-pip-version-check -r /requirements.txt

# Copy the virtualenv into a distroless image
FROM gcr.io/distroless/python3-debian11
COPY --from=build-venv /venv /venv
COPY . /app
WORKDIR /app
ENTRYPOINT ["/venv/bin/python3", "psutil_example.py"] 

And (2nd stage removed)

# Build a virtualenv using the appropriate Debian release
# * Install python3-venv for the built-in Python3 venv module (not installed by default)
# * Install gcc libpython3-dev to compile C Python modules
# * In the virtualenv: Update pip setuputils and wheel to support building new packages
FROM debian:11-slim AS build
RUN apt-get update && \
    apt-get install --no-install-suggests --no-install-recommends --yes python3-venv gcc libpython3-dev && \
    python3 -m venv /venv && \
    /venv/bin/pip install --upgrade pip setuptools wheel

COPY requirements.txt /requirements.txt
RUN /venv/bin/pip install --disable-pip-version-check -r /requirements.txt

# Copy the virtualenv into a distroless image
FROM gcr.io/distroless/python3-debian11
COPY --from=build-venv /venv /venv
COPY . /app
WORKDIR /app
ENTRYPOINT ["/venv/bin/python3", "psutil_example.py"]

Any build time advantage of one over the other ?

Thanks


Solution

  • I'd expect both paths to be identical. Arguably the first path would let you docker build --target do get an image that contained the C toolchain and an empty virtual environment, but I wouldn't expect this to be a frequent use case.

    More generally, there's not really a benefit to splitting a build into multiple stages but having the second stage start FROM the first one. If your Dockerfile has

    FROM ... AS a
    COPY ...
    RUN ...
    
    FROM a
    RUN ...
    

    then you will get the same image out at the end whether there are two build stages or just one (deleting the second FROM line). Build-time layer caching will work the same way, and the final image will contain all of the layers from the first stage.