Docker multi-stage build Dockerfile best practices
See original GitHub issue- I have searched the issues of this repo and believe that this is not a duplicate.
- I have searched the documentation and believe that my question is not covered.
Question
I continue to try to replace our pip/setuptools-based system with poetry, but hit a new snag when it comes to how we build our Docker images.
Here’s the basic pattern we use for our Docker images, in a build and a deploy stage:
- (build) Resolve all dependencies and build wheels for them
- (build) Build the actual project as a wheel too
- (deploy) Take all of those wheels we built and install them into a lightweight image (that has no build tools)
Here’s how this translates into a Dockerfile:
# ---------------------------------------------------------------------------------------
# BUILD
# ---------------------------------------------------------------------------------------
FROM gitlab.example.com:4567/namespace/build-base:py37-1.0.4 as builder
RUN mkdir -p /build/wheels
# This is separated out to take advantage of caching
ADD requirements.txt /tmp/requirements.txt
RUN pip3.7 wheel --trusted-host pypi.example.com \
--wheel-dir=/tmp/python-wheels --index-url http://pypi.example.com/simple/ \
-r /tmp/requirements.txt
ADD . /src
WORKDIR /src
RUN pip3.7 wheel --find-links /tmp/python-wheels --trusted-host=pypi.example.com --wheel-dir=/build/wheels .
# ---------------------------------------------------------------------------------------
# DEPLOY
# ---------------------------------------------------------------------------------------
FROM gitlab.example.sec:4567/namespace/deploy-base:py37-1.0.0 as deploy
WORKDIR /opt/app
# Copy the already-built wheels
COPY --from=builder /build/wheels /tmp/wheels
# Install into main system python.
RUN pip3.7 install --no-cache-dir /tmp/wheels/* && rm -rf /tmp/wheels
CMD ["myproject-server"]
How do I do this with poetry? – in the most short-sighted form, I’d like to know how to collect all dependencies as wheels in order to match this pattern.
However, my real requirement here is just to have separate build and deploy stages where the deploy image has no python (or lower-level) build-related tools installed (but does have pip) and simply takes artifacts from the build image.
(I suppose one idea would be to treat the entire virtualenv from the build stage as an artifact? That seems a little dirty, but provided the base OS images were the same, might work?)
Issue Analytics
- State:
- Created 4 years ago
- Reactions:8
- Comments:13 (2 by maintainers)
Top GitHub Comments
Hey,
I found this solution for me to work best:
Dont forget a
.dockerignore
:Ticks all my boxes:
pyproject.toml
orpoetry.lock
changeJust make sure to use the same path in the builder and the final image, virtualenv uses some hardcoded paths. Change the
CMD
to match your application.EDIT: Updated to reflect some of @alexpovel’s critics
We’ve had relatively good success copying virtualenvs between images with pip. I’m just beginning to see if we can transition to poetry - we’ve just been using it for small utilities right now but we’re using the following code to do what you’re describing:
Haven’t figured out a clean way to work with prod vs. dev dependencies