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
sailcommand line convenience scripts for reaching into your containers to do common tasks - It comes with a neat
sail sharecommand 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 upwill first put up the webserver and databased managecan be used for passing commands to[manage.py](http://manage.py)— eg.d manage startapp frontendd pipcan be used for pip — eg.d pip install djangorestframeworkd npmfor npm commands — eg.d npm i axiosd devfor putting the vite server up at http://localhost:5173d buildto build vite- The npm commands spin up a temporary container with a volume mounted to the
frontendfolder instead of exec-ing on an existing container (since I don’t have the vite server running at all times)
Pretty fun detour! ☺️