Search code examples
djangopostgresqlpostgisgdalgeodjango

Installing Geospatial libraries in Docker


Django's official documentation lists 3 dependencies needed to start developing PostGIS application. They list a table depending on the database.

I use docker for my local development and I am confused about which of those packages should be installed in the Django container and which in the PostgreSQL container. I am guessing some of them should be on both.

I would appreciate your help with this.


Solution

  • You need to install the Geospatial libraries only in the Django container because they are used for interacting with a spatially enabled DB (such as PostgreSQL with PostGIS). You can deploy such a DB by using as a base a ready-made image for that purpose, such as kartoza/postgis.
    Here is a nice example of a Dockerfile that uses python:3.6-slim as a base and builds the GDAL dependencies into the container. The part of the Dockerfile that you need for that is the following:

    FROM python:3.6-slim
    
    ENV PYTHONUNBUFFERED=1
    
    # Add unstable repo to allow us to access latest GDAL builds
    # Existing binutils causes a dependency conflict, correct version will be installed when GDAL gets intalled
    RUN echo deb http://deb.debian.org/debian testing main contrib non-free >> /etc/apt/sources.list && \
        apt-get update && \
        apt-get remove -y binutils && \
        apt-get autoremove -y
    
    # Install GDAL dependencies
    RUN apt-get install -y libgdal-dev g++ --no-install-recommends && \
        pip install pipenv && \
        pip install whitenoise && \
        pip install gunicorn && \
        apt-get clean -y
    
    # Update C env vars so compiler can find gdal
    ENV CPLUS_INCLUDE_PATH=/usr/include/gdal
    ENV C_INCLUDE_PATH=/usr/include/gdal
    
    ENV LC_ALL="C.UTF-8"
    ENV LC_CTYPE="C.UTF-8"
    

    You can deploy both the Django app and the DB using docker-compose, using the following docker-compose.yaml (from the same repo as the Dockerfile):

    # Sample compose file for a django app and postgis
    version: '3'
    
    services:
    
      postgis:
        image: kartoza/postgis:9.6-2.4
        volumes:
          - postgis_data:/var/lib/postgresql
        environment:
          ALLOW_IP_RANGE: 0.0.0.0/0
          POSTGRES_PASS: ${POSTGRES_PASSWORD}
          POSTGRES_USER: ${POSTGRES_USER}
          POSTGRES_DB: postgis
    
      web:
        image: intelligems/geodjango:latest
        command: python manage.py runserver 0.0.0.0:8000
        environment:
          DEBUG: "True"
          SECRET_KEY: ${SECRET_KEY}
          DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgis:5432/postgis
          SENTRY_DSN: ${SENTRY_DSN}
        ports:
          - 8000:8000
        depends_on:
          - postgis
    
    volumes:
      postgis_data: {}
    

    In this repository, you can find more info and interesting bits of configuration for your issue: https://github.com/intelligems/docker-library/tree/master/geodjango (the Dockerfile snippet above is from that repo).


    As a Note:
    If you want to create a PostgreSQL with PostGIS enabled database as a "local DB" to interact with your local Django, you can deploy the previously mentioned kartoza/postgis:

    1. Create a Volume:

      $ docker volume create postgresql_data
      
    2. Deploy the container:

      $ docker run \
            --name=postgresql-with-postgis -d \
            -e POSTGRES_USER=user_name \
            -e POSTGRES_PASS=user_pass \
            -e ALLOW_IP_RANGE=0.0.0.0/0 -p 5433:5432 \
            -v postgresql_data:/var/lib/postgresql \
            --restart=always \
            kartoza/postgis:9.6-2.4
      
    3. Connect to the default DB (postgres) of the container and create your DB:

      $ psql -h localhost -U user_name -d postgres
      $ CREATE DATABASE database_name;
      
    4. Enable PostGIS extension to the database:

      $ \connect database_name
      $ CREATE EXTENSION postgis;
      

    This will result in a DB with the name database_name listening to port 5432 of your localhost and you can connect to that from your local Django app.