-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile-api
More file actions
117 lines (96 loc) · 4.82 KB
/
Copy pathDockerfile-api
File metadata and controls
117 lines (96 loc) · 4.82 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
# Use the official Python image from the Docker Hub
FROM python:3.13-slim-bookworm AS base
ARG APP_UID=17163
ARG APP_GID=10000
RUN apt-get update && \
apt-get install -y --no-install-recommends \
openssh-client \
build-essential \
gcc \
g++ \
python3-dev \
postgresql-client && \
rm -rf /var/lib/apt/lists/*
# Set environment variables
ENV PYTHONUNBUFFERED=1 \
OMP_NUM_THREADS=1 \
MKL_NUM_THREADS=1 \
OPENBLAS_NUM_THREADS=1
# Keep the dev/docs dependency groups out of the runtime image.
#
# This MUST be an ENV, not just a `--no-default-groups` flag on the `uv sync`
# calls below: every command this image actually runs goes through `uv run`
# (the CMD, and the alembic-migrate Job's
# `uv run python -m viva_api.simulation.db_reconcile`), and `uv run` re-syncs
# the environment against `[tool.uv] default-groups = ["dev", "docs"]` before
# executing. Build-time flags alone are therefore inert — verified: a
# `--no-default-groups` build followed by a plain `uv run` reinstalls 37 dev
# packages at container start, which also makes startup depend on network
# access to the index. The env var is what the runtime `uv run` honors.
ENV UV_NO_DEFAULT_GROUPS=true
# Install uv from the GitHub Container Registry
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# create user/group
RUN groupadd -g $APP_GID appgroup && \
useradd -m -u $APP_UID -g $APP_GID appuser
# Create psql alias script
RUN echo '#!/bin/bash\nPGPASSWORD=$POSTGRES_PASSWORD psql -h $POSTGRES_HOST -p $POSTGRES_PORT -d $POSTGRES_DATABASE -U $POSTGRES_USER "$@"' > /usr/local/bin/dbshell && \
chmod +x /usr/local/bin/dbshell
# Create SSH to Slurm login node alias script
RUN echo '#!/bin/bash\nssh -i $SLURM_SUBMIT_KEY_PATH -o UserKnownHostsFile=$SLURM_SUBMIT_KNOWN_HOSTS ${SLURM_SUBMIT_USER}@${SLURM_SUBMIT_HOST} "$@"' > /usr/local/bin/slurmshell && \
chmod +x /usr/local/bin/slurmshell
# Create SSH to build machine alias script
RUN echo '#!/bin/bash\nssh -i $BUILD_NODE_KEY_PATH -o StrictHostKeyChecking=no ${BUILD_NODE_USER}@${BUILD_NODE_HOST} "$@"' > /usr/local/bin/buildshell && \
chmod +x /usr/local/bin/buildshell
USER appuser
# Set the working directory
WORKDIR /app
# Copy only the necessary files
COPY --chown=appuser:appgroup uv.lock /app/uv.lock
COPY --chown=appuser:appgroup pyproject.toml /app/pyproject.toml
# Install dependencies (--no-dev is redundant under UV_NO_DEFAULT_GROUPS but kept
# explicit; note --no-dev alone would still install the separate `docs` group)
RUN uv sync --frozen --no-install-project --no-default-groups
# Copy the rest of the application code
COPY --chown=appuser:appgroup viva_api /app/viva_api
# Back-compat shim so deployed Jobs still invoking `python -m sms_api.*` keep
# working across the sms_api -> viva_api rename (see sms_api/__init__.py).
COPY --chown=appuser:appgroup sms_api /app/sms_api
COPY --chown=appuser:appgroup app /app/app
COPY --chown=appuser:appgroup alembic /app/alembic
COPY --chown=appuser:appgroup clients /app/clients
# README.md is required: pyproject's `readme` points at it, so hatchling fails
# the project install without it. pytest.ini is NOT copied — see the note below.
COPY --chown=appuser:appgroup alembic.ini README.md /app/
COPY --chown=appuser:appgroup assets/simulations /app/assets/simulations
COPY --chown=appuser:appgroup assets/*.json /app/assets/
COPY --chown=appuser:appgroup assets/app /app/assets/app
COPY --chown=appuser:appgroup .results_cache /app/.results_cache
RUN mkdir -p /app/.results_cache && \
chown appuser:appgroup /app/.results_cache
# Sync the project
RUN uv sync --frozen --no-default-groups
# NOTE: the test suite is deliberately NOT run here, and `tests/`/`pytest.ini`
# are deliberately not copied into the image.
#
# This used to be `RUN SKIP_DOCKER_TESTS=1 uv run python -m pytest`, whose job
# was to fail the image build when tests failed. That belongs in CI, not in a
# build layer: the suite needs testcontainers (Postgres/Redis/NATS), so only the
# non-Docker subset could ever run here — hence SKIP_DOCKER_TESTS — and it
# re-ran on every layer-invalidating change for a signal CI already produces
# faster and in parallel. It is also now impossible: UV_NO_DEFAULT_GROUPS
# above means pytest is not installed in this image at all.
#
# The gate that replaced it lives in .github/workflows/build-and-push.yml,
# which runs the full suite + mypy and will not build or push an image unless
# they pass. That closes the real gap this line only nominally covered: that
# workflow takes an arbitrary `--ref` and previously built whatever was there,
# tested or not.
# Declare the volume for local cache storage
VOLUME ["/app/scratch"]
# Expose the port FastAPI will run on
EXPOSE 8000
ENV APP_DIR=/app/app
ENV ASSETS_DIR=/app/assets
# Command to run the application
CMD ["uv", "run", "uvicorn", "viva_api.api.main:app", "--host", "0.0.0.0", "--port", "8000"]