# syntax=docker/dockerfile:1.9 ### Start build prep. ### This should be a separate build container for better reuse. FROM python:3.13-slim-bookworm AS build # The following does not work in Podman unless you build in Docker # compatibility mode: # You can manually prepend every RUN script with `set -ex` too. SHELL ["sh", "-exc"] # Ensure apt-get doesn't open a menu ENV DEBIAN_FRONTEND=noninteractive COPY --from=ghcr.io/astral-sh/uv:0.7.2 /uv /usr/local/bin/uv # - Silence uv complaining about not being able to use hard links, # - tell uv to byte-compile packages for faster application startups, # - prevent uv from accidentally downloading isolated Python builds, # - pick a Python, and finally declare `/app` as the target for `uv sync`. ENV UV_LINK_MODE=copy \ UV_COMPILE_BYTECODE=1 \ UV_PYTHON_DOWNLOADS=never \ UV_PYTHON=python3.13 \ UV_PROJECT_ENVIRONMENT=/app # Synchronize DEPENDENCIES without the application itself. # This layer is cached until uv.lock or pyproject.toml change, which are # only temporarily mounted into the build container since we don't need # them in the production one. # You can create `/app` using `uv venv` in a separate `RUN` # step to have it cached, but with uv it's so fast, it's not worth # it, so we let `uv sync` create it for us automagically. RUN --mount=type=cache,target=/root/.cache \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync \ --locked \ --no-dev \ --no-install-project # Now install the rest from `/src`: The APPLICATION w/o dependencies. # `/src` will NOT be copied into the runtime container. # LEAVE THIS OUT if your application is NOT a proper Python package. # COPY . /src # WORKDIR /src # RUN --mount=type=cache,target=/root/.cache \ # uv sync \ # --locked \ # --no-dev \ # --no-editable ### End build prep ########################################################################## FROM python:3.13-slim-bookworm SHELL ["sh", "-exc"] ARG ENV_FILE=.env.production ENV PATH=/app/bin:$PATH ENV PYTHONPATH=/app ENV PYTHONUNBUFFERED=1 ENV HOME=/code ENV DJANGO_SETTINGS_MODULE=django_project.settings WORKDIR /app # Don't run app as root RUN <. STOPSIGNAL SIGINT COPY --from=build --chown=app:app /app /app RUN playwright install --with-deps # If your application is NOT a proper Python package that got # pip-installed above, you need to copy your application into # the container HERE and set the WORKDIR: COPY --chown=app:app ./ /code WORKDIR /code ENV PYTHONPATH=/code # WORKDIR /app # if python-packaged RUN rm -f .env COPY ${ENV_FILE} .env COPY --chown=app:app --chmod=700 /scripts/entrypoint.sh /entrypoint.sh COPY --chown=app:app --chmod=700 /scripts/deploy.sh /deploy.sh ENTRYPOINT ["/entrypoint.sh"] USER app EXPOSE 8000 HEALTHCHECK CMD curl --fail http://localhost:8000/health/ || exit 1 CMD ["granian", "--interface", "wsgi", "django_project.wsgi", "--host", "0.0.0.0", "--port", "8000", "--workers", "1", "--respawn-failed-workers", "--workers-kill-timeout", "60"]