|
a |
|
b/Dockerfile |
|
|
1 |
# syntax=docker/dockerfile:1.2 |
|
|
2 |
################################################# |
|
|
3 |
# |
|
|
4 |
# Initial ehrQL layer with just system dependencies installed. |
|
|
5 |
# |
|
|
6 |
# hadolint ignore=DL3007 |
|
|
7 |
FROM ghcr.io/opensafely-core/base-action:latest as ehrql-dependencies |
|
|
8 |
|
|
|
9 |
|
|
|
10 |
# setup default env vars for all images |
|
|
11 |
# ACTION_EXEC sets the default executable for the entrypoint in the base-action image |
|
|
12 |
ENV VIRTUAL_ENV=/opt/venv/ \ |
|
|
13 |
PYTHONPATH=/app \ |
|
|
14 |
PATH="/opt/venv/bin:/opt/mssql-tools/bin:$PATH" \ |
|
|
15 |
ACTION_EXEC=ehrql \ |
|
|
16 |
PYTHONUNBUFFERED=True \ |
|
|
17 |
PYTHONDONTWRITEBYTECODE=1 \ |
|
|
18 |
PYTHONHASHSEED=0 |
|
|
19 |
|
|
|
20 |
RUN mkdir /workspace |
|
|
21 |
WORKDIR /workspace |
|
|
22 |
|
|
|
23 |
# We are going to use an apt cache on the host, so disable the default debian |
|
|
24 |
# docker clean up that deletes that cache on every apt install |
|
|
25 |
RUN rm -f /etc/apt/apt.conf.d/docker-clean |
|
|
26 |
|
|
|
27 |
# Add Microsoft package archive for installing MSSQL tooling |
|
|
28 |
# Add deadsnakes PPA for installing new Python versions |
|
|
29 |
RUN --mount=type=cache,target=/var/cache/apt \ |
|
|
30 |
/usr/lib/apt/apt-helper download-file \ |
|
|
31 |
"https://packages.microsoft.com/keys/microsoft.asc" \ |
|
|
32 |
/etc/apt/trusted.gpg.d/microsoft.asc && \ |
|
|
33 |
/usr/lib/apt/apt-helper download-file \ |
|
|
34 |
"https://packages.microsoft.com/config/ubuntu/20.04/prod.list" \ |
|
|
35 |
/etc/apt/sources.list.d/mssql-release.list && \ |
|
|
36 |
echo "deb https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu focal main" \ |
|
|
37 |
> /etc/apt/sources.list.d/deadsnakes-ppa.list && \ |
|
|
38 |
/usr/lib/apt/apt-helper download-file \ |
|
|
39 |
'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xf23c5a6cf475977595c89f51ba6932366a755776' \ |
|
|
40 |
/etc/apt/trusted.gpg.d/deadsnakes.asc |
|
|
41 |
|
|
|
42 |
# Install root dependencies, including Python |
|
|
43 |
COPY dependencies.txt /root/dependencies.txt |
|
|
44 |
# use space efficient utility from base image |
|
|
45 |
RUN --mount=type=cache,target=/var/cache/apt \ |
|
|
46 |
/usr/bin/env ACCEPT_EULA=Y /root/docker-apt-install.sh /root/dependencies.txt |
|
|
47 |
|
|
|
48 |
################################################# |
|
|
49 |
# |
|
|
50 |
# Next, use the dependencies image to create an image to build dependencies |
|
|
51 |
FROM ehrql-dependencies as ehrql-builder |
|
|
52 |
|
|
|
53 |
# install build time dependencies |
|
|
54 |
COPY build-dependencies.txt /root/build-dependencies.txt |
|
|
55 |
RUN /root/docker-apt-install.sh /root/build-dependencies.txt |
|
|
56 |
|
|
|
57 |
|
|
|
58 |
# install everything in venv for isolation from system python libraries |
|
|
59 |
# hadolint ignore=DL3013,DL3042 |
|
|
60 |
RUN --mount=type=cache,target=/root/.cache \ |
|
|
61 |
/usr/bin/python3.11 -m venv /opt/venv && \ |
|
|
62 |
/opt/venv/bin/python -m pip install -U pip setuptools wheel |
|
|
63 |
|
|
|
64 |
COPY requirements.prod.txt /root/requirements.prod.txt |
|
|
65 |
# hadolint ignore=DL3042 |
|
|
66 |
RUN --mount=type=cache,target=/root/.cache python -m pip install -r /root/requirements.prod.txt |
|
|
67 |
|
|
|
68 |
# WARNING clever/ugly python packaging hacks alert |
|
|
69 |
# |
|
|
70 |
# Borrowed (with modifications) from: |
|
|
71 |
# https://github.com/opensafely-core/cohort-extractor/blob/669e2d5d2e/Dockerfile#L54-L84 |
|
|
72 |
# |
|
|
73 |
# We could just do `COPY . /app` and then `pip install /app`. However, this is |
|
|
74 |
# not ideal for a number of reasons: |
|
|
75 |
# |
|
|
76 |
# 1) Any changes to the app files will invalidate this and all subsequent |
|
|
77 |
# layers, causing them to need rebuilding. This would mean basically |
|
|
78 |
# reinstalling dev dependencies every time. |
|
|
79 |
# |
|
|
80 |
# 2) We want to use the pinned versions of dependencies in |
|
|
81 |
# requirements.prod.txt rather than the unpinned versions in setup.py. |
|
|
82 |
# |
|
|
83 |
# 3) We want for developers be able to mount /app with their code and it Just |
|
|
84 |
# Works, without reinstalling anything. |
|
|
85 |
# |
|
|
86 |
# So, we do the following: |
|
|
87 |
# |
|
|
88 |
# 1) Copy a stripped down version of the pyproject.toml file, and install an |
|
|
89 |
# empty package from it alone (a test ensured the minimal version stays in |
|
|
90 |
# sync with the full version) |
|
|
91 |
# |
|
|
92 |
# 2) We install it without deps, as they've already been installed. |
|
|
93 |
# |
|
|
94 |
# 3) We have set PYTHONPATH=/app, so that code copied or mounted into /app will |
|
|
95 |
# be used automatically. |
|
|
96 |
# |
|
|
97 |
# Note: we only really need to install it at all to use setuptools entrypoints. |
|
|
98 |
RUN mkdir /app |
|
|
99 |
COPY pyproject.minimal.toml /app/pyproject.toml |
|
|
100 |
# hadolint ignore=DL3042 |
|
|
101 |
RUN --mount=type=cache,target=/root/.cache \ |
|
|
102 |
/opt/venv/bin/python -m pip install --no-deps /app |
|
|
103 |
|
|
|
104 |
|
|
|
105 |
################################################ |
|
|
106 |
# |
|
|
107 |
# A base image with the including the prepared venv and metadata. |
|
|
108 |
FROM ehrql-dependencies as ehrql-base |
|
|
109 |
|
|
|
110 |
# Some static metadata for this specific image, as defined by: |
|
|
111 |
# https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys |
|
|
112 |
# The org.opensafely.action label is used by the jobrunner to indicate this is |
|
|
113 |
# an approved action image to run. |
|
|
114 |
LABEL org.opencontainers.image.title="ehrql" \ |
|
|
115 |
org.opencontainers.image.description="ehrQL action for opensafely.org" \ |
|
|
116 |
org.opencontainers.image.source="https://github.com/opensafely-core/ehrql" \ |
|
|
117 |
org.opensafely.action="ehrql" |
|
|
118 |
|
|
|
119 |
COPY --from=ehrql-builder /opt/venv /opt/venv |
|
|
120 |
|
|
|
121 |
|
|
|
122 |
################################################ |
|
|
123 |
# |
|
|
124 |
# Build the actual production image from the base |
|
|
125 |
FROM ehrql-base as ehrql |
|
|
126 |
|
|
|
127 |
# Copy app code. This will be automatically picked up by the virtualenv as per |
|
|
128 |
# comment above |
|
|
129 |
COPY ehrql /app/ehrql |
|
|
130 |
RUN python -m compileall /app/ehrql |
|
|
131 |
COPY bin /app/bin |
|
|
132 |
|
|
|
133 |
# The following build details will change. |
|
|
134 |
# These are the last step to make better use of Docker's build cache, |
|
|
135 |
# avoiding rebuilding image layers unnecessarily. |
|
|
136 |
ARG BUILD_DATE=unknown |
|
|
137 |
LABEL org.opencontainers.image.created=$BUILD_DATE |
|
|
138 |
ARG GITREF=unknown |
|
|
139 |
LABEL org.opencontainers.image.revision=$GITREF |