-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
56 lines (44 loc) · 1.99 KB
/
Copy pathDockerfile
File metadata and controls
56 lines (44 loc) · 1.99 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
# syntax=docker/dockerfile:1.7
# The backend serves the SPA itself (app.frontend on repo-root dist/), so the
# image carries its own frontend build — one artifact, no tag-sync with a
# separately-shipped UI.
FROM node:22-alpine@sha256:16e22a550f3863206a3f701448c45f7912c6896a62de43add43bb9c86130c3e2 AS spa
WORKDIR /app/frontend
COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
FROM python:3.11-slim@sha256:e031123e3d85762b141ad1cbc56452ba69c6e722ebf2f042cc0dc86c47c0d8b3
# Debian package revisions vary by architecture; the base image is immutable and
# Dependabot advances its digest so rebuilds pick up the matching security set.
# hadolint ignore=DL3008
RUN apt-get update \
&& apt-get install -y --no-install-recommends git ca-certificates tini \
&& rm -rf /var/lib/apt/lists/*
COPY --from=docker.io/astral/uv:0.10.9@sha256:10902f58a1606787602f303954cea099626a4adb02acbac4c69920fe9d278f82 /uv /uvx /usr/local/bin/
ENV UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
UV_PYTHON_DOWNLOADS=never \
PYTHONUNBUFFERED=1 \
PATH="/app/.venv/bin:$PATH"
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-dev
COPY README.md LICENSE ./
COPY backend/ ./backend/
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-dev
# Same height as a dev checkout: repo-root dist/ (vite's outDir).
COPY --from=spa /app/dist ./dist
ENV DRUKS_DATA_DIR=/app/data
RUN mkdir -p /app/data
# We run as a non-root, arbitrary uid (the deploy user — see the compose
# `user:`). Such a uid has no /etc/passwd entry, so getpass.getuser() — which
# asyncssh calls on every SSH connect — would raise. Declaring a username lets
# it resolve from the environment instead. Cosmetic: the real SSH user is
# passed per connection.
ENV USER=druks LOGNAME=druks
EXPOSE 8001
ENTRYPOINT ["tini", "--"]
CMD ["uvicorn", "druks.api.app:app", "--host", "127.0.0.1", "--port", "8001"]