Repository navigation
Expand file tree
/
Copy pathContainerfile
More file actions
144 lines (118 loc) · 4.87 KB
/
Copy pathContainerfile
File metadata and controls
144 lines (118 loc) · 4.87 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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# Build stage - install dependencies and build static files
FROM debian:bookworm-slim AS build
WORKDIR /app
# Install system and build dependencies
RUN apt-get -y update && apt-get install -y --no-install-recommends \
git \
binutils \
libproj-dev \
libgdal-dev \
gdal-bin \
curl \
ca-certificates \
gcc \
g++ \
make \
file \
&& rm -rf /var/lib/apt/lists/*
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# Install Bun from official image
COPY --from=oven/bun:1.3.14 /usr/local/bin/bun /usr/local/bin/bun
# Install Bun dependencies (including devDependencies for vite build)
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
# Copy Python version file so uv knows which Python to install
COPY .python-version ./
# Install Python to a path that will also work in the release image
ENV UV_PYTHON_INSTALL_DIR=/opt/uv/python
# Install Python dependencies (uv will download and manage Python). The
# lockfiles are copied in rather than bind-mounted so this builds under both
# BuildKit/docker and buildah/podman — buildah's `relabel` mount option isn't
# understood by BuildKit.
COPY uv.lock pyproject.toml ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked --no-install-project --no-default-groups
# Copy project files - only what's needed for the application
COPY uv.lock ./
COPY manage.py ./
COPY vite.config.js ./
COPY tsconfig.json ./
COPY pyproject.toml ./
COPY assets ./assets
# Type-check frontend sources before anything heavier runs
RUN bun run typecheck
COPY api ./api
COPY images ./images
COPY directories ./directories
COPY maps ./maps
COPY regions ./regions
COPY subjects ./subjects
COPY activity ./activity
COPY osm_auth ./osm_auth
COPY templates ./templates
COPY yesterdays ./yesterdays
# Install project itself (--no-default-groups keeps the docs toolchain out of
# the venv that ships in the release image)
RUN uv sync --locked --no-default-groups
# Build static files in correct order:
# 1. Create static directory first
RUN mkdir -p /app/static
# 2. Run bun build to generate Vite-bundled JS/CSS into /static
RUN bun run build
# Development stage - the full build toolchain (uv + bun) plus the runtime
# libraries the app loads at runtime, used by docker compose for local
# development. Source is bind-mounted over /app at run time; the Python venv
# lives at /opt/venv (outside /app) so the bind mount can't shadow it, and a
# fresh image build always yields fresh dependencies (no stale volume to clear).
FROM build AS dev
# Runtime libraries the build stage only carried the compile-time (-dev)
# variants of, or didn't install at all (tesseract for OCR).
RUN apt-get -y update && apt-get install -y --no-install-recommends \
tesseract-ocr \
tesseract-ocr-eng \
&& rm -rf /var/lib/apt/lists/*
# Build the project's virtualenv outside the bind-mounted source tree. Reuses
# the wheel cache populated earlier in this build, so it doesn't re-download.
ENV UV_PROJECT_ENVIRONMENT=/opt/venv
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --locked
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /app
# Final runtime image - minimal Debian
FROM debian:bookworm-slim AS release
# Create non-root user
RUN groupadd --gid 1000 app && useradd --uid 1000 --gid 1000 --create-home app
WORKDIR /app
# Install only essential runtime dependencies
RUN apt-get -y update && apt-get install -y --no-install-recommends \
libgdal32 \
libproj25 \
tesseract-ocr \
tesseract-ocr-eng \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Copy Python (managed by uv) and virtual environment from build stage
COPY --from=build /opt/uv/python /opt/uv/python
COPY --from=build --chown=app:app /app/.venv /app/.venv
# Copy only runtime-necessary files from build stage
COPY --from=build --chown=app:app /app/manage.py /app/
COPY --from=build --chown=app:app /app/pyproject.toml /app/
COPY --from=build --chown=app:app /app/uv.lock /app/
COPY --from=build --chown=app:app /app/.python-version /app/
COPY --from=build --chown=app:app /app/api /app/api
COPY --from=build --chown=app:app /app/images /app/images
COPY --from=build --chown=app:app /app/directories /app/directories
COPY --from=build --chown=app:app /app/maps /app/maps
COPY --from=build --chown=app:app /app/regions /app/regions
COPY --from=build --chown=app:app /app/subjects /app/subjects
COPY --from=build --chown=app:app /app/activity /app/activity
COPY --from=build --chown=app:app /app/osm_auth /app/osm_auth
COPY --from=build --chown=app:app /app/templates /app/templates
COPY --from=build --chown=app:app /app/yesterdays /app/yesterdays
COPY --from=build --chown=app:app /app/static /app/static
# Create writable tmp directory for PyTorch cache (needed with readOnlyRootFilesystem)
RUN mkdir -p /tmp && chown app:app /tmp
USER app
# Run the application
CMD ["/app/.venv/bin/uvicorn", "yesterdays.asgi:application", "--host", "0.0.0.0", "--port", "8000"]