How to build a Python app with PostgreSQL

I’m currently setting up a Flask app with PostgreSQL and Docker.

Like most examples you’ll find on the internet, the course I’m following uses Alpine Linux as a base image. Alpine’s selling point is the small image size.

But Alpine uses a different C library, musl, instead of glibc.

That’s one of the reasons why the website Pythonspeed recommends Debian Buster as the base image for Python (as of 2019).

Let’s say we have a requirements.txt file with the following packages. We want to get Flask working with a PostgreSQL database.

Flask==1.1.1
Flask-RESTful==0.3.7
Flask-SQLAlchemy==2.4.0
psycopg2-binary==2.8.3

Alpine Linux Docker

Let’s create a Dockerfile for an Alpine-based image.

## base image
FROM python:3.7.4-alpine

## install dependencies
RUN apk update && \
    apk add --virtual build-deps gcc python-dev musl-dev && \
    apk add postgresql-dev && \
    apk add netcat-openbsd

## set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

## set working directory
WORKDIR /usr/src/app

## add user
RUN adduser -D user
RUN chown -R user:user /usr/src/app && chmod -R 755 /usr/src/app

## add and install requirements
RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt

## add entrypoint.sh
COPY ./entrypoint.sh /usr/src/app/entrypoint.sh
RUN chmod +x /usr/src/app/entrypoint.sh

## switch to non-root user
USER user

## add app
COPY . /usr/src/app

## run server
CMD python manage.py run -h 0.0.0.0

We have to install several libraries (musl-dev, etc.) with apk add. Those libraries are required for installing psypcopg2-binary with pip install later.
netcat-openbsd is not necessary for PostgreSQL, but I need it in my app for my entrypoint.sh script.

You should probably use a multi-stage build to minimize the final image.

Debian Buster Slim Docker

Now, the same Dockerfile for Debian Buster Slim:

## base image
FROM python:3.7.5-slim-buster

## install dependencies
RUN apt-get update && \
    apt-get upgrade -y && \
    apt-get install -y netcat-openbsd gcc && \
    apt-get clean


## set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

## set working directory
WORKDIR /usr/src/app

## add user
RUN addgroup --system user && adduser --system --no-create-home --group user
RUN chown -R user:user /usr/src/app && chmod -R 755 /usr/src/app

## add and install requirements
RUN pip install --upgrade pip
COPY ./requirements.txt /usr/src/app/requirements.txt
RUN pip install -r requirements.txt

## add entrypoint.sh
COPY ./entrypoint.sh /usr/src/app/entrypoint.sh
RUN chmod +x /usr/src/app/entrypoint.sh

## switch to non-root user
USER user

## add app
COPY . /usr/src/app

## run server
CMD python manage.py run -h 0.0.0.0

We have to install gcc to get pip install working with psypcopg2-binary. (Consider using multi-stage builds to optimize speed and efficiency.)

Further Reading