7f640649b9
So a deploy never needs a manual `alembic upgrade head`: - Backend image gains an entrypoint that runs `alembic upgrade head` before uvicorn when RUN_MIGRATIONS=1 (set on the backend service). This self-migrates even on a Watchtower in-place image swap, which doesn't re-run one-shot jobs. - A one-shot `migrate` service covers the `docker compose up` path; backend and worker depend on it completing, which also serializes it with the backend entrypoint so alembic never runs concurrently. `upgrade head` is idempotent. Activating this needs the updated compose on the host once (Watchtower only swaps images, not the compose file / env). After that, migrations are automatic. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
32 lines
1.0 KiB
Docker
32 lines
1.0 KiB
Docker
# syntax=docker/dockerfile:1
|
|
|
|
# uv-managed Python image keeps the toolchain reproducible. Pinned to 3.13 for
|
|
# broad wheel availability (asyncpg etc.); bump when 3.14 wheels are ubiquitous.
|
|
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
|
|
|
|
ENV PYTHONUNBUFFERED=1 \
|
|
PYTHONDONTWRITEBYTECODE=1 \
|
|
UV_COMPILE_BYTECODE=1 \
|
|
UV_LINK_MODE=copy
|
|
|
|
WORKDIR /app
|
|
|
|
# Dependencies first for layer caching. uv.lock is optional on first build;
|
|
# `uv sync` resolves and writes it if absent.
|
|
COPY pyproject.toml uv.lock* ./
|
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
uv sync --no-dev
|
|
|
|
# Application source + migrations (project is package=false, no install step).
|
|
COPY app ./app
|
|
COPY alembic.ini ./alembic.ini
|
|
COPY migrations ./migrations
|
|
COPY docker-entrypoint.sh ./docker-entrypoint.sh
|
|
RUN chmod +x ./docker-entrypoint.sh
|
|
|
|
EXPOSE 8000
|
|
|
|
# The entrypoint runs migrations first when RUN_MIGRATIONS=1, then the command.
|
|
ENTRYPOINT ["./docker-entrypoint.sh"]
|
|
CMD ["uv", "run", "--no-dev", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|