February 07, 2017

Pipfiles, pipenv and Docker

Exciting times in Python. With the recent introduction of Pipfiles and the new pipenv library it's time to rewrite our Dockerfiles to leverage all the goodness of modern Python packaging.


FROM python:3.6

# 1. install pipenv and create an entrypoint
RUN pip install pipenv
RUN echo "#!/bin/bash" >> /entrypoint.sh && \
    echo "source /app/.local/share/virtualenvs/app/bin/activate" >> /entrypoint.sh && \
    echo 'exec "$@"' >> /entrypoint.sh && \
    chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

# 2. install system level dependencies
# <-- system level dependencies here

# 3. don't run as root
RUN groupadd --gid 1001 app
RUN useradd --uid 1001 --gid app --home /app app
RUN mkdir /app && \
    chown app.app /app
USER app
WORKDIR /app/app

# 4. copy the Pipfile and install it
COPY Pipfile /app/Pipfile
RUN pipenv install

# 5. add your own code
# <--- own code here

COPY . /app/app

1. Install pipenv and create an entrypoint

The first thing we have to do is install pipenv. In order to use it properly, we are going to create a small entrypoint that activates the virtualenv whenever we enter the container.

2. Install system level dependencies

If you have any system level dependencies, install them here. We are going to switch to a non-privileged user next, this is your last chance.

3. Don't run as root

Running Docker containers as root is not a good idea. Check out Graham Dumpleton's blog for more details on this.

We are going to create a new user that lives in /app and change the WORKDIR accordingly.

4. Copy the Pipfile and install it

Finally, it's time to install the Pipfile. If this is a Dockerfile for a development environment, you want to add the --dev flag.

5. add your own code

This is where you add your own code. No help here, you have to write this yourself.

Try it out

First, create a new Dockerfile with the contents from above.

Docker Compose makes it extremely simple to build Dockerfiles, so we are going to use it. If you haven't already, install it and create a docker-compose.yml that looks like this:


version: '2'

    build: .

Next, create a minimal Pipfile with requests as its only dependency:


requests = "*"

Time to build the image, run:

docker-compose build

And run the container by running:

docker-compose run app python

This should give you a Python shell with pre installed requests to play with.