Docker Swarm
Single-node swarm running the zaideih and myordbok stacks.
Production runs a single-node swarm with Cloudflare Tunnel for ingress, so no port is published to the internet. Give the node a stable address first — see Static networking. Deployment scripts are Python; see Packaging scripts.
Init
sudo docker swarm init
sudo usermod -aG docker $USER
docker compose config # validate before deploying
Deploy and watch
docker stack deploy -c docker-compose.yml zaideih
watch docker service ls
docker service ps zaideih_web --no-trunc
docker inspect --format '{{.Status.Err}}' <task-id>
Logs
docker service logs -f zaideih_web
docker service logs --since 1h zaideih_web
docker service logs -f zaideih_web --tail 100
docker service logs -f myordbok_web --tail 100
Updates and rollback
docker service update --force zaideih_web
docker service update --rollback zaideih_web
Checking a running task
Swarm assigns new container IDs on every deploy, so look the ID up rather than keeping one around.
CONTAINER_ID=$(docker ps -q -f name=zaideih_web)
docker exec -it $CONTAINER_ID python manage.py check
docker exec $CONTAINER_ID env | grep DEBUG
docker exec $CONTAINER_ID env | grep STORAGE_DIR
docker exec $CONTAINER_ID ls -R /code/static/.vite/
Inspecting env prints secrets to the terminal. Grep for the specific variable
rather than dumping the whole environment.
Static files
find static -mindepth 1 ! -path "static/.vite*" -delete
npm run build && python manage.py collectstatic --clear --noinput
python manage.py check
docker run --rm -it ghcr.io/<owner>/zaideih/django-app:latest cat /code/staticfiles/.vite/manifest.json
Tearing a stack down
docker stack rm zaideih
# Deletes all database data in that volume
docker volume rm zaideih_mysql_data
docker volume prune -f
# If a container still holds the volume
docker rm -f <container-id>