Skip to content

Instantly share code, notes, and snippets.

@snorfalorpagus
Created June 17, 2019 22:32
Show Gist options
  • Save snorfalorpagus/18689f350038f840d01ff0d7e8864fa4 to your computer and use it in GitHub Desktop.
Save snorfalorpagus/18689f350038f840d01ff0d7e8864fa4 to your computer and use it in GitHub Desktop.
Docker + Pipenv + multi-stage builds
FROM alpine:3.9 AS build
WORKDIR /opt/app
# Install Python and external dependencies, including headers and GCC
RUN apk add --no-cache python3 python3-dev py3-pip libffi libffi-dev musl-dev gcc
# Install Pipenv
RUN pip3 install pipenv
# Create a virtual environment and activate it
RUN python3 -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH" VIRTUAL_ENV="/opt/venv"
# Install dependencies into the virtual environment with Pipenv
COPY Pipfile Pipfile.lock /opt/app/
RUN pipenv install --deploy
FROM alpine:3.9
WORKDIR /opt/app
# Install Python and external runtime dependencies only
RUN apk add --no-cache python3 libffi
# Copy the virtual environment from the previous image
COPY --from=build /opt/venv /opt/venv
# Activate the virtual environment
ENV PATH="/opt/venv/bin:$PATH" VIRTUAL_ENV="/opt/venv"
# Copy your application
COPY . /opt/app/
@jetuk
Copy link

jetuk commented Jun 18, 2019

Why don't you copy the app from build at the end?

@snorfalorpagus
Copy link
Author

The app is never copied into the build image; only the Pipfile and Pipfile.lock are, which is enough to install the dependencies. This has a benefit to the layer cache, as it means if you change only your app (e.g. app.py) and not the Pipfile(.lock) only the very last statement needs to be run and you avoid reinstalling all the dependencies in the runtime image.

@jetuk
Copy link

jetuk commented Jun 18, 2019

This makes sense. I guess if your "app" was a click application then app.py might just be a shell script invoking your CLI?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment