-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDockerfile
277 lines (210 loc) · 8.01 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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# Base image with Postgres 15 libraries
FROM python:3.10-bullseye AS dev-base-pg15
# Base image already contains bash, so we can RUN with bash
# and write "source" instead of "."
SHELL ["/bin/bash", "-c"]
# Base dependencies
RUN \
apt-get update && apt-get install -y \
# to compile python native bindings:
gcc \
# to check for distro release and codename:
lsb-release \
# Reduce image size and prevent use of potentially obsolete lists:
&& rm -rf /var/lib/apt/lists/*
# Postgres
RUN \
# The PostgreSQL client provides pg_isready for production, and pg_restore for development.
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& apt-get update && apt-get install -y libpq-dev postgresql-client-15 \
# Reduce image size and prevent use of potentially obsolete lists:
&& rm -rf /var/lib/apt/lists/*
FROM dev-base-pg15 AS dev-base
# Nicer prompt is managed by zsh themes, so disable default venv prompt:
ENV VIRTUAL_ENV_DISABLE_PROMPT=x
ENV PIP_DISABLE_PIP_VERSION_CHECK=on
# Custom but reliable way to know if running inside container, and easily fakeable:
ENV RUNNING_IN_CONTAINER=x
ARG NPM_CACHE_DIR=/tmp/npm-cache
ARG PIP_NO_CACHE_DIR=off
ARG WHO=magnet
ARG HOST_UID=2640
ARG HOST_GID=2640
ARG NODE_MAJOR=18
# Dev tools
RUN \
apt-get update && apt-get install -y \
# for Django translations:
gettext \
# commit inside container:
git \
# actually non-slim version already includes git, but sadly not all it's recommended packages
# (specifically "less"), so include them explicitly:
ca-certificates patch less ssh-client \
# required for node setup
curl gnupg \
# parse ansible outputs:
jq \
&& rm -rf /var/lib/apt/lists/*
# Node
RUN \
mkdir -p /etc/apt/keyrings \
&& 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_$NODE_MAJOR.x nodistro main" \
| tee /etc/apt/sources.list.d/nodesource.list \
&& apt-get update && apt-get install -y nodejs \
# Update npm:
&& mkdir "$NPM_CACHE_DIR" \
&& npm install --global --cache "$NPM_CACHE_DIR" npm \
# Delete but keeping the directory:
&& rm -rf "$NPM_CACHE_DIR"/* \
# Ensure npm cache can be written by unprivileged users later:
&& chown $HOST_UID:$HOST_GID "$NPM_CACHE_DIR" \
# Reduce image size and prevent use of potentially obsolete lists:
&& rm -rf /var/lib/apt/lists/*
# Poetry
RUN pip install "poetry==1.4.2"
# Create unprivileged user
RUN \
groupadd --gid $HOST_GID $WHO \
&& useradd --uid $HOST_UID --gid $HOST_GID --create-home $WHO
RUN mkdir /usr/src/app && chown -R $HOST_UID:$HOST_GID /usr/src/app
# Switch to unprivileged user
USER $WHO
WORKDIR /usr/src/app
COPY --chown=$HOST_UID:$HOST_GID scripts/ ./scripts/
# Install Poetry dev-dependencies
COPY --chown=$HOST_UID:$HOST_GID pyproject.toml poetry.lock ./
RUN poetry install --with dev --no-root
FROM dev-base as development
ARG WHO=magnet
ARG HOST_UID=2640
ARG HOST_GID=2640
USER root
# Dev utilities
RUN \
apt-get update && apt-get install -y \
# to wait for DB:
wait-for-it \
# better shell:
zsh \
# sudo
sudo \
# see container processes:
htop \
# editors:
vim nano \
# to grep for TODOs:
ripgrep \
# prevents "spawn ps ENOENT" error in lint-staged:
procps \
&& rm -rf /var/lib/apt/lists/*
COPY docker/zsh_dev docker/zsh_dev/
RUN \
# Configure oh my zsh
sudo -u $WHO docker/zsh_dev/setup_dev.sh \
# "install editable" ansible-ssh:
&& ln -s /usr/src/app/ansible/ansible-ssh /usr/local/bin/ \
# add user to sudo group, set zsh as default shell
&& usermod -aG sudo --password '' -s /bin/zsh $WHO \
# Disable initial sudo lecture
&& (umask 337; echo "Defaults lecture=never" > /etc/sudoers.d/no_lecture)
# Switch back to unprivileged user
USER $WHO
# Install ansible + collections and link `dj`.
COPY --chown=$HOST_UID:$HOST_GID requirements.yml ./
RUN \
poetry install --with=deploy-tools --no-root \
&& poetry run ansible-galaxy collection install -r requirements.yml \
# "dj" alias available from anywhere.
&& ln -s /usr/src/app/manage.py $(poetry env info --path)/bin/dj
# Prevent development container shutdown:
CMD ["sleep", "inf"]
# Use bind-mounted ansible config:
ENV ANSIBLE_CONFIG=/usr/src/app/ansible/ansible.cfg
# This stage is used to generate a static requirements.txt file for production builds
FROM dev-base as prod-py-dependency-export
WORKDIR /usr/src/app
COPY pyproject.toml poetry.lock ./
RUN poetry export --without-hashes -o requirements.txt
FROM dev-base-pg15 AS prod-py-builder
WORKDIR /usr/src/app
ARG PIP_NO_CACHE_DIR=off
COPY --from=prod-py-dependency-export /usr/src/app/requirements.txt /usr/src/app/
RUN pip install -r requirements.txt
FROM dev-base as prod-js-builder
ARG WHO=magnet
ARG HOST_UID=2640
ARG HOST_GID=2640
ENV NODE_ENV=production
COPY --chown=$HOST_UID:$HOST_GID package.json package-lock.json ./
# Empty "--omit" because devDependencies are currently required to build:
RUN npm ci --omit="" --no-audit \
&& rm -rf "$NPM_CACHE_DIR"/*
COPY --chown=$HOST_UID:$HOST_GID assets ./assets/
COPY vite.config.ts tsconfig.json .eslint* .stylelint* ./
ARG VITE_MANIFEST="manifest.json"
RUN VITE_MANIFEST="$VITE_MANIFEST" npm run build
FROM dev-base as test
ARG WHO=magnet
ARG HOST_UID=2640
ARG HOST_GID=2640
ENV NODE_ENV=ci
USER root
# node_modules for "npm run lint"
WORKDIR /usr/src/app
COPY --chown=$HOST_UID:$HOST_GID package.json package-lock.json ./
RUN npm ci --omit="" --no-audit && rm -rf "$NPM_CACHE_DIR"/*
COPY --chown=$HOST_UID:$HOST_GID . ./
RUN mkdir -p ./project/media ./project/static
RUN chown $HOST_UID:$HOST_GID /usr/src/app/project/static /usr/src/app/project/media
USER $WHO
FROM python:3.10-slim-bullseye AS production
ARG WHO=magnet
ARG HOST_UID=2640
ARG HOST_GID=2640
RUN groupadd --gid $HOST_GID $WHO \
&& useradd --uid $HOST_UID --gid $HOST_GID --create-home --shell /bin/zsh $WHO
WORKDIR /usr/src/app
COPY docker/zsh_prod docker/zsh_prod/
# System dependencies
RUN \
apt-get update && apt-get install -y --no-install-recommends \
gettext \
libssl1.1 \
libxml2 \
lsb-release \
shared-mime-info \
wait-for-it \
zsh \
curl \
gpg \
# The PostgreSQL client provides pg_isready for production, and pg_restore for development.
&& curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor > /usr/share/keyrings/postgresql.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list \
&& apt-get update && apt-get install -y libpq5 postgresql-client-15 \
# oh-my-zsh: (requires curl. "su" instead of multiple layers with RUN-USER-RUN-USER-RUN)
&& su $WHO docker/zsh_prod/setup_prod.sh \
# Reduce image size and prevent use of potentially obsolete lists:
&& apt-get remove -y curl gpg \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p ./project/media ./project/static && chown $HOST_UID:$HOST_GID ./project/static ./project/media
COPY --from=prod-py-builder /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/
COPY --from=prod-py-builder /usr/local/bin/ /usr/local/bin/
COPY --from=prod-js-builder /usr/src/app/assets/bundles/ ./assets/bundles/
COPY --chown=$HOST_UID:$HOST_GID . ./
COPY --chown=$HOST_UID:$HOST_GID ./docker/django/prod_cmd.sh ./
RUN ln -s /usr/src/app/manage.py /usr/local/bin/dj
USER $WHO
RUN django-admin compilemessages
# Set git version and build time before finishing to reduce build time
# when only minor changes are done
ARG GIT_REF="<unknown>"
ENV GIT_REF=$GIT_REF
ARG BUILD_TIME="<unknown>"
ENV BUILD_TIME=$BUILD_TIME
ARG VITE_MANIFEST="manifest.json"
ENV VITE_MANIFEST=$VITE_MANIFEST
CMD ["/usr/src/app/prod_cmd.sh"]