feat(deploy): production docker compose stack + Gitea CI image build
Adds a complete deployment surface for production:
Dockerfile multi-stage 3.12-slim build, collectstatic
baked into the image, runs as non-root mnemosyne
uid/gid 1000.
docker/entrypoint.sh dispatches `web | mcp | worker | beat | migrate
| setup | shell` from a single image, so every
service in compose runs the same artifact.
docker-compose.yaml five services: static-init (one-shot copies
statics into the shared volume on every up),
web (gunicorn), mcp (uvicorn), worker (celery),
nginx. External services (Postgres, Neo4j,
RabbitMQ, S3, Memcached, embedder, reranker)
reached over the 10.10.0.0/24 internal network
and configured via mnemosyne/.env.
nginx/mnemosyne.conf reverse proxy: /library/* and /admin/* → web,
/mcp/* → mcp, /static/* → volume, /metrics
internal-network-only (127/8 + RFC1918), /healthz
proxies to /mcp/health for liveness probes.
.gitea/workflows/ CVE scan + image build, image pushed to
git.helu.ca/r/mnemosyne. Trivy scans pyproject
extras (dev/test/lint/docs) and the built image.
pyproject.toml adds [test], [lint], [docs] extras so the CI
pip-compile step has something to resolve.
README documents the bring-up flow (`docker compose run --rm web migrate`,
then `setup`, then `up -d`), day-to-day commands, and the env-var values
that need adjusting for production (DEBUG=False, KVDB_LOCATION pointing
at the external memcached, AWS keys filled in, etc.).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
66
docker/entrypoint.sh
Normal file
66
docker/entrypoint.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#!/bin/sh
|
||||
# Mnemosyne container entrypoint.
|
||||
#
|
||||
# The same image runs all three processes — the compose service supplies
|
||||
# `web`, `mcp`, `worker`, or `migrate` as CMD.
|
||||
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
web)
|
||||
# Django REST API + admin (gunicorn → wsgi).
|
||||
exec gunicorn \
|
||||
--bind 0.0.0.0:8000 \
|
||||
--workers "${GUNICORN_WORKERS:-3}" \
|
||||
--access-logfile - \
|
||||
--error-logfile - \
|
||||
mnemosyne.wsgi:application
|
||||
;;
|
||||
|
||||
mcp)
|
||||
# FastMCP over Streamable HTTP at /mcp/, mounted by mnemosyne.asgi.
|
||||
exec uvicorn \
|
||||
--host 0.0.0.0 \
|
||||
--port 22091 \
|
||||
--workers "${UVICORN_WORKERS:-1}" \
|
||||
mnemosyne.asgi:app
|
||||
;;
|
||||
|
||||
worker)
|
||||
# Celery worker covering embedding + ingest + batch + default queues.
|
||||
# In production you may want to split these onto separate worker
|
||||
# services for queue-level isolation; one process is fine to start.
|
||||
exec celery -A mnemosyne worker \
|
||||
--loglevel="${CELERY_LOG_LEVEL:-info}" \
|
||||
--queues="${CELERY_QUEUES:-celery,embedding,batch}" \
|
||||
--concurrency="${CELERY_CONCURRENCY:-2}"
|
||||
;;
|
||||
|
||||
beat)
|
||||
# Celery scheduled tasks (only needed if/when periodic jobs are wired).
|
||||
exec celery -A mnemosyne beat \
|
||||
--loglevel="${CELERY_LOG_LEVEL:-info}"
|
||||
;;
|
||||
|
||||
migrate)
|
||||
# One-shot DB migration runner — invoke before bringing services up
|
||||
# for the first time or after a deploy.
|
||||
exec python manage.py migrate --noinput
|
||||
;;
|
||||
|
||||
setup)
|
||||
# One-shot init — Neo4j indexes + library_type seed data.
|
||||
python manage.py setup_neo4j_indexes
|
||||
python manage.py load_library_types
|
||||
;;
|
||||
|
||||
shell)
|
||||
# Drop into the management shell for ad-hoc work.
|
||||
exec python manage.py shell
|
||||
;;
|
||||
|
||||
*)
|
||||
# Fall through: run whatever was passed (e.g. `manage.py <cmd>`).
|
||||
exec "$@"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user