When using normal one stage build Dockerfile, the final image is 216MB; but when using a multi-stage build approach shown below, I got a final image of 227MB. Why is this?
# This multi stage build Dockerfile actually makes the image larger! :(
FROM python:3.10.14-slim-bookworm AS base
LABEL authors="X"
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV ENVIRONMENT=production
ENV PYTHONPATH=/app
WORKDIR /app
FROM base AS build
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt &&
rm requirements.txt
FROM base AS final
# cleaning up unused files
RUN rm -rf /var/lib/apt/lists/*
COPY --from=build /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/
COPY ./src /app/src
# Expose port 8000 for FastAPI server
EXPOSE 8000
ENTRYPOINT ["python", "/app/src/main.py"]
The requirements.txt
file only contains 4 packages:
fastapi==0.111.0
loguru==0.7.2
aiohttp[speedups]==3.9.5
boto3==1.34.128
build
is just this, installing packages with pip
without writing any cache:
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt &&
rm requirements.txt
And final
does this, copying everything that pip
installed:
COPY --from=build /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/
So you’ve saved the size of requirements.txt and doubled the size of whatever already existed in /usr/local/lib/python3.10/site-packages/ before pip
.
There’s just not much reason to use a multi-stage build with this starting point, as-is.
(Note that RUN rm -rf /var/lib/apt/lists/*
also creates a new layer to hold deletions, increasing size very slightly and not decreasing it.)
1