Dockerizing Django with Numpy and Gunicorn

Subscribe to my newsletter and never miss my upcoming articles

Hi all.

Actually theres lot of tutorial about dockerizing django on web. But at the project i working on we using libraries like Numpy and Pillow and alpine linux cannot compile this because missing dependencies.

Our Stack;

  • Django
  • Numpy
  • Pillow
  • Postgresql

First of all let create basic Dockerfile

FROM python:3.6.4-alpine

ADD . /app

WORKDIR /app

RUN pip install -r requirements.txt

EXPOSE 8000

CMD ["manage.py", "runserver"]

Its basically works if you not using c compiled libraries like Numpy.

The thing is we need to add compilers to alpine i have big layer on there because running this proccesses on one layer is better i think.

Full Dependency install Layer :

RUN apk add --no-cache jpeg tiff-dev openjpeg-dev postgresql-dev && \
    apk add --no-cache \
    --virtual=.build-deps \
    g++ zlib-dev freetype-dev lcms2-dev \
    gcc libc-dev linux-headers tk-dev tcl-dev harfbuzz-dev \
    fribidi-dev build-base py-pip rsyslog cython file binutils \
    musl-dev python3-dev cython && \
    ln -s locale.h /usr/include/xlocale.h && \
    pip install --upgrade pip && \
    pip install -r requirements.txt --no-cache-dir && \
    rm -r /root/.cache && \
    find /usr/lib/python3.*/ -name 'tests' -exec rm -r '{}' + && \
    find /usr/lib/python3.*/site-packages/ -name '*.so' -print -exec sh -c 'file "{}" | grep -q "not stripped" && strip -s "{}"' \; && \
    rm /usr/include/xlocale.h && \
    apk --purge del .build-deps

Compilers for Alpine

I installed some packages like g++ and linux-headers virtual and cleaned them after pip install because i just need this packages for post scripts of some dependencies and size is matter on container.

  -t, --virtual NAME    Instead of adding all the packages to 'world', create a new 
                        virtual package with the listed dependencies and add that 
                        to 'world'; the actions of the command are easily reverted 
                        by deleting the virtual package

What that means is when you install packages, those packages are not added to global packages. And this change can be easily reverted. So if I need gcc to compile a program, but once the program is compiled I no more need gcc.

I can install gcc, and other required packages in a virtual package and all of its dependencies and everything can be removed this virtual package name. Below is an example usage

apk add --virtual mypacks gcc vim
apk del mypacks

The next command will delete all 18 packages installed with the first command.

Postgres

Im running Postgresql on my local machine not docker. And i need to connect it. You can use host.docker.internal this mapping is directly routes your machines localhost

So i added this env variable

ENV DB_HOST=host.docker.internal

and used this on settings.py

Gunicorn

I decided to use Gunicorn for running processed with n workers. So i added gunicorn to my requirements.txt and added this two lines for run processes

ENV WORKER_COUNT=2

CMD ["sh", "-c", "gunicorn --bind :8000 --workers ${WORKER_COUNT} project.wsgi:application"]

Using WORKER_COUNT env variable for default value. Im overriding this value everytime i need.


Running

I decided to create makefile for run this container with n workers. So i created Makefile with this command.


docker-run:
    docker run -e worker_count=${worker} -p 127.0.0.1:8000:8000 project${version}

Full Dockerfile

FROM python:3.6.4-alpine

ADD . /app
WORKDIR /app

# Need to Update at Settings.py
ENV DB_HOST=host.docker.internal

# Default Worker Count is 2
ENV WORKER_COUNT=2

# Install dependencies layer.
RUN apk add --no-cache postgresql \
                        jpeg tiff-dev openjpeg-dev \
                        libpq postgresql-libs postgresql-dev && \
    apk add --no-cache \
    --virtual=.build-deps \
    g++ jpeg-dev zlib-dev freetype-dev lcms2-dev \
    gcc libc-dev linux-headers tk-dev tcl-dev harfbuzz-dev \
    fribidi-dev zlib-dev build-base py-pip rsyslog cython file binutils \
    musl-dev python3-dev cython && \
    ln -s locale.h /usr/include/xlocale.h && \
    pip install --upgrade pip && \
    pip install -r requirements.txt --no-cache-dir && \ 
    rm -r /root/.cache && \
    find /usr/lib/python3.*/ -name 'tests' -exec rm -r '{}' + && \
    find /usr/lib/python3.*/site-packages/ -name '*.so' -print -exec sh -c 'file "{}" | grep -q "not stripped" && strip -s "{}"' \; && \
    rm /usr/include/xlocale.h && \
    apk --purge del .build-deps  


EXPOSE 8000

CMD ["sh", "-c", "gunicorn --bind :8000 --workers ${WORKER_COUNT} project.wsgi:application"]

I hope you found this article useful.

Thanks.

No Comments Yet