Repository navigation
Expand file tree
/
Copy pathDockerfile.dev
More file actions
96 lines (71 loc) · 3.73 KB
/
Copy pathDockerfile.dev
File metadata and controls
96 lines (71 loc) · 3.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# syntax=docker/dockerfile:1.10
# check=error=true
# Development-only image, used by `docker compose` (see docker-compose.yml).
# Heroku isn't involved: production builds use Dockerfile, with Docker's
# legacy (non-BuildKit) builder. BuildKit is assumed here, so we can use
# cache mounts to speed up npm and apt installs.
# Run `docker build --check -f Dockerfile.dev .` for better error messages.
# Keep dependency versions in sync with Dockerfile (Node, Python, uv).
# frontend stages
# Keep the Node version in sync with Dockerfile and .nvmrc.
FROM node:26 AS frontend-deps
# Make build & post-install scripts behave as if in CI (e.g. logging verbosity).
ARG CI=true
COPY package.json package-lock.json vite.config.ts ./
RUN --mount=type=cache,target=/root/.npm npm ci
# base stage
# Debian over alpine: it's considered more stable (different C compiler) and
# ships with the packages commonly needed for image manipulation, at the
# cost of a larger (~1.5GiB) image.
FROM python:3.14 AS base
# Keep this version in sync with the local `uv` used to generate uv.lock.
COPY --from=ghcr.io/astral-sh/uv:0.11.19 /uv /uvx /bin/
ENV VIRTUAL_ENV=/venv
RUN useradd guide --create-home && mkdir /app $VIRTUAL_ENV && chown -R guide /app $VIRTUAL_ENV
WORKDIR /app
# Defaults only: any environment variables set on Heroku override these.
# * UV_PROJECT_ENVIRONMENT - installs into $VIRTUAL_ENV instead of the
# project's default `.venv`, so it isn't clobbered by a bind mount in dev.
# * UV_LINK_MODE=copy - hardlinks break across Docker layers.
# * PYTHONUNBUFFERED - otherwise logs can be lost if the process crashes:
# https://docs.python.org/3.14/using/cmdline.html#envvar-PYTHONUNBUFFERED
# * PORT - read by Gunicorn; Heroku sets this itself and ignores EXPOSE.
ENV PATH=$VIRTUAL_ENV/bin:$PATH \
UV_PROJECT_ENVIRONMENT=$VIRTUAL_ENV \
UV_COMPILE_BYTECODE=1 \
UV_LINK_MODE=copy \
PYTHONUNBUFFERED=1 \
PORT=8000
EXPOSE 8000
# Heroku doesn't run containers as root either:
# https://devcenter.heroku.com/articles/container-registry-and-runtime#dockerfile-commands-and-runtime
USER guide
RUN python -m venv $VIRTUAL_ENV
COPY --chown=guide pyproject.toml uv.lock ./
# dev stage
# Application code isn't copied in at build time - docker-compose bind mounts
# it instead - so only rebuild this image when dependencies change
# (`docker compose build`).
FROM base AS dev
USER root
# Node's major version is kept in sync with frontend-deps above and .nvmrc.
# `just` is installed too, so the recipes in ./justfile also work from a
# shell in this container, the same way they do on the host.
RUN --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \
--mount=type=cache,target=/var/cache/apt,sharing=locked \
mkdir -p /etc/apt/keyrings \
&& apt-get --quiet --yes update \
&& apt-get --quiet --yes install --no-install-recommends ca-certificates curl gnupg \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_26.x nodistro main" > /etc/apt/sources.list.d/nodesource.list \
&& apt-get --quiet --yes update \
&& apt-get --quiet --yes install --no-install-recommends nodejs just
USER guide
ARG UV_SYNC_ARGS="--all-groups"
RUN uv sync --frozen ${UV_SYNC_ARGS}
# Reuses node_modules from frontend-deps so a freshly built container doesn't
# need to `npm ci` before assets can be built. docker-compose.yml volumes
# node_modules so it isn't shadowed by the code bind mount.
COPY --chown=guide --from=frontend-deps ./node_modules ./node_modules
COPY --chown=guide package.json package-lock.json vite.config.ts ./
CMD ["uv", "run", "python", "manage.py", "runserver", "0.0.0.0:8000"]