Django dev docker compose
In the Laravel ecosystem, there’s a first party development environment called Laravel Sail which takes care of your Docker containers. This is super useful for local development.
- It comes with a bunch of supported containers out of the box which might be useful for local dev (php of course, mysql/postgres, redis, meilisearch, mailhog, selenium, etc)
- It provides the
sail
command line convenience scripts for reaching into your containers to do common tasks - It comes with a neat
sail share
command which is similar to an ngrok wrapper that will pop your development site up at a subdomain of your choice attached to[laravel-sail.site](http://laravel-sail.site)
(great for testing webhooks)
When I popped my first Django project up, I was looking for Django’s version of Sail, but it doesn’t seem like there’s a first party equivalent. I’ve been getting the impression Django is more light-weight and unopinionated, and doesn’t include features which I’m used to coming with Laravel either as an out of the box or first-party solution.
Some other examples I’ve come across include Laravel’s queue/scheduler (the Django community seems to recommend options such as Celery, Django Q, RQ, which I’ll have to try out) and Laravel Passport (this seems to come in the third party Django OAuth Toolkit), but it seems likely I’ll run into more. This isn’t a big deal; it just means that I need to take the extra step of researching which choice is best instead of just using the tool recommended to me by the framework.
I ended up patching a docker compose and some convenience scripts together with help from Docker’s Awesome Compose, and I suppose I’ll just use free ngrok and deal with the randomised subdomains for now.
# docker-compose.yml
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
- /code/frontend/dist
- /code/frontend/node_modules
ports:
- "8000:8000"
environment:
- POSTGRES_NAME=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
env_file:
- ".env"
depends_on:
- db
db:
image: postgres
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
npm:
image: node:19.3-alpine
volumes:
- ./frontend:/usr/src/app
working_dir: /usr/src/app
ports:
- "5173:5173"
profiles:
- donotstart
# syntax=docker/dockerfile:1
FROM node:19.3-alpine As npm
WORKDIR /usr/src/app
COPY frontend/ ./
RUN npm install
RUN mode=production npm run build
FROM python:3 as production
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
COPY --from=npm /usr/src/app/ ./frontend
Convenience script for easy development —
#!/usr/bin/env bash
EXEC_WEB="docker compose exec web "
EXEC_NPM="docker compose run npm "
if [ $# -gt 0 ];then
if [ "$1" == "manage" ]; then
shift 1
$EXEC_WEB python3 manage.py "$@"
elif [ "$1" == "pip" ]; then
shift 1
$EXEC_WEB pip "$@"
elif [ "$1" == "npm" ]; then
shift 1
$EXEC_NPM npm "$@"
elif [ "$1" == "dev" ]; then
$EXEC_NPM npm install
docker compose run -p 5173:5173 npm npm run dev
elif [ "$1" == "build" ]; then
$EXEC_NPM npm install
docker compose run -e mode=production npm npm run build
else
$EXEC_WEB "$@"
fi
fi
I named this helper script d
and my development flow seems pretty OK so far!
docker compose up
will first put up the webserver and databased manage
can be used for passing commands to[manage.py](http://manage.py)
— eg.d manage startapp frontend
d pip
can be used for pip — eg.d pip install djangorestframework
d npm
for npm commands — eg.d npm i axios
d dev
for putting the vite server up at http://localhost:5173d build
to build vite- The npm commands spin up a temporary container with a volume mounted to the
frontend
folder instead of exec-ing on an existing container (since I don’t have the vite server running at all times)
Pretty fun detour! ☺️