ADR 0015: Container image
Ratification
Adopted before ADR 0018. There was no separate ratification process. Git history for this file on main is the record.
- Discussion Issue: not recorded (before ADR 0018)
- Merge PR: see git history for this file
- Accepted: as merged to
main
Context
Why this matters: Local Python (make run) is the fastest feedback loop for feature
work. Containers add a packaging boundary: the same bits you test in CI can run on a laptop, in a VM, or on
a cloud host behind a registry.
Docker stays optional for daily coding; it complements the venv workflow. We ship a Dockerfile so integration tests and release flows do not depend on a specific cloud account.
Decision
- Provide a Dockerfile that installs dependencies from the same
requirements.txtasmake install, copies application and Alembic assets, runs as non-root useruid 1000, and setsENTRYPOINTtoscripts/container_entrypoint.sh(same shell script asmake container-starton the host:alembic upgrade headthen Uvicorn). The image does not runmake(no venv layout in-container). - Default container paths: SQLite file under
/data(configurable viaSQLITE_DB_PATH), logs under/tmp/logswhen not overridden, to avoid permission issues on read-only layers. - Keep SQLite + single replica for this ADR’s scope; document that scaling out requires a shared database.
- Add Makefile helper
docker-buildand developer guidedocs/developer/0009-docker-image-and-container.html.
Scope
- In scope: image layout, entrypoint behavior,
docker rundocumentation. - Out of scope: hosted registry promotion (see ADR 0021), production ingress/TLS, replacing SQLite with PostgreSQL.
Alternatives considered
- docker-compose for the API
- Pros: simple multi-container dev.
- Cons: observability compose already exists separately; a single Dockerfile keeps one path for portable runs.
- Init container for migrations, app container without Alembic
- Pros: clearer separation in some platforms.
- Cons: duplicate image configuration for standalone
docker run; entrypoint migration keeps one path for local and registry pulls.
Consequences
Positive
- Single reproducible artifact (image) aligned with CI and release practices.
- Readiness/liveness endpoints exercise the same checks used behind load balancers and in health probes.
Trade-offs
- SQLite on a single volume is not suitable for multi-replica HA deployments.
Compatibility and migration
- Backward-compatibility impact: none for Python APIs; additive files only.
- Migration plan: N/A.
- Rollback strategy: continue with
make runwithout using the image.
Implementation plan
- Add Dockerfile,
scripts/container_entrypoint.sh,.dockerignore. - Document in developer guide and this ADR; link from ADR index.
Validation
- Technical:
docker build -t study-app-api:local .succeeds;docker runwith appropriate env returns HTTP 200 on/live. - Documentation: developer guide and ADR cross-linked.
References
- Related ADRs: 0009, 0010
- Developer guide: Docker image and container
Page history
| Date | Change | Author |
|---|---|---|
| Added Page history section (repository baseline). | Ivan Boyarkin |