-
Notifications
You must be signed in to change notification settings - Fork 2
/
Dockerfile
175 lines (159 loc) · 5.83 KB
/
Dockerfile
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# Copyright (c) Humanitarian OpenStreetMap Team
# This file is part of fmtm-splitter.
#
# fmtm-splitter is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# fmtm-splitter is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with fmtm-splitter. If not, see <https:#www.gnu.org/licenses/>.
#
ARG PYTHON_IMG_TAG=3.12
ARG UV_IMG_TAG=0.5.2
FROM ghcr.io/astral-sh/uv:${UV_IMG_TAG} AS uv
# Includes all labels and timezone info to extend from
FROM docker.io/python:${PYTHON_IMG_TAG}-slim-bookworm AS base
ARG APP_VERSION
ARG COMMIT_REF
ARG PYTHON_IMG_TAG
LABEL org.hotosm.fmtm.app-name="fmtm-splitter" \
org.hotosm.fmtm.app-version="${APP_VERSION}" \
org.hotosm.fmtm.git-commit-ref="${COMMIT_REF:-none}" \
org.hotosm.fmtm.python-img-tag="${PYTHON_IMG_TAG}" \
org.hotosm.fmtm.maintainer="[email protected]" \
org.hotosm.fmtm.api-port="8000"
RUN apt-get update --quiet \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install -y --quiet --no-install-recommends \
"locales" "ca-certificates" \
&& DEBIAN_FRONTEND=noninteractive apt-get upgrade -y \
&& rm -rf /var/lib/apt/lists/* \
&& update-ca-certificates
# Set locale & env vars
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
# - 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,
# - use a temp dir instead of cache during install,
# - select system python version,
# - declare `/opt/python` as the target for `uv sync` (i.e. instead of .venv).
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US:en \
LC_ALL=en_US.UTF-8 \
UV_LINK_MODE=copy \
UV_COMPILE_BYTECODE=1 \
UV_PYTHON_DOWNLOADS=never \
UV_NO_CACHE=1 \
UV_PYTHON="python$PYTHON_IMG_TAG" \
UV_PROJECT_ENVIRONMENT=/opt/python
STOPSIGNAL SIGINT
# Build stage will all dependencies required to build Python wheels
FROM base AS build
ARG API
RUN apt-get update --quiet \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install -y --quiet --no-install-recommends \
"build-essential" \
"gcc" \
"libpq-dev" \
&& rm -rf /var/lib/apt/lists/*
COPY --from=uv /uv /usr/local/bin/uv
COPY pyproject.toml uv.lock /_lock/
# Ensure caching & install with or without api dependencies
# FIXME add --locked & --no-dev flag to uv sync below
RUN --mount=type=cache,target=/root/.cache <<EOT
uv sync \
--project /_lock \
--no-dev \
$(if [ -z "$API" ]; then \
echo ""; \
else \
echo "--group api"; \
fi)
EOT
# Run stage will minimal dependencies required to run Python libraries
FROM base AS runtime
ARG PYTHON_IMG_TAG
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONFAULTHANDLER=1 \
PATH="/opt/python/bin:$PATH" \
PYTHONPATH="/opt" \
PYTHON_LIB="/opt/python/lib/python$PYTHON_IMG_TAG/site-packages" \
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt \
CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
RUN apt-get update --quiet \
&& DEBIAN_FRONTEND=noninteractive \
apt-get install -y --quiet --no-install-recommends \
"nano" \
"curl" \
"mime-support" \
"postgresql-client" \
&& rm -rf /var/lib/apt/lists/*
COPY entrypoint.sh /container-entrypoint.sh
ENTRYPOINT ["/container-entrypoint.sh"]
WORKDIR /opt
# Copy Python deps from build to runtime
COPY --from=build /opt/python /opt/python
# Add fmtm-splitter module to Python packages
COPY "fmtm_splitter/" "/opt/python/lib/python$PYTHON_IMG_TAG/site-packages/fmtm_splitter/"
# Add non-root user, permissions
RUN useradd -u 1001 -m -c "user account" -d /home/appuser -s /bin/false appuser \
&& chown -R appuser:appuser /opt /home/appuser \
&& chmod +x /container-entrypoint.sh
# Stage to use during local development
FROM runtime AS debug
ARG API
COPY --from=uv /uv /usr/local/bin/uv
COPY pyproject.toml uv.lock /_lock/
RUN --mount=type=cache,target=/root/.cache <<EOT
uv sync \
--project /_lock \
--group debug \
--group test \
--group docs \
--group dev \
$(if [ -z "$API" ]; then \
echo ""; \
else \
echo "--group api"; \
fi)
EOT
# Used during CI workflows (as root), with docs/test dependencies pre-installed
FROM debug AS ci
# NOTE tests are added at runtime via a bind mount
# Override entrypoint, as not possible in Github action
ENTRYPOINT [""]
CMD [""]
# Override CMD for API debug
FROM debug AS api-debug
# Add API code
COPY api/ /opt/api/
CMD ["python", "-Xfrozen_modules=off", "-m", "debugpy", \
"--listen", "0.0.0.0:5678", "-m", "uvicorn", "api.main:app", \
"--host", "0.0.0.0", "--port", "8000", "--workers", "1", \
"--reload", "--log-level", "critical", "--no-access-log"]
# Final stage used during API deployment
FROM runtime AS api-prod
# Add API code & fmtm-splitter module
COPY api/ /opt/api/
# Change to non-root user
USER appuser
# Sanity check to see if build succeeded
RUN python -V \
&& python -Im site \
&& python -c 'import api.main'
# Note: 1 worker (process) per container, behind load balancer
CMD ["uvicorn", "api.main:app", "--host", "0.0.0.0", "--port", "8000", \
"--workers", "1", "--log-level", "critical", "--no-access-log"]
# Final stage to distribute fmtm-splitter in a container
FROM api-prod AS prod
# Change to non-root user
CMD ["bash"]