generated from opensafely-core/repo-template
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Dockerfile
139 lines (119 loc) · 5.29 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
# syntax=docker/dockerfile:1.2
#################################################
#
# Initial ehrQL layer with just system dependencies installed.
#
# hadolint ignore=DL3007
FROM ghcr.io/opensafely-core/base-action:latest as ehrql-dependencies
# setup default env vars for all images
# ACTION_EXEC sets the default executable for the entrypoint in the base-action image
ENV VIRTUAL_ENV=/opt/venv/ \
PYTHONPATH=/app \
PATH="/opt/venv/bin:/opt/mssql-tools/bin:$PATH" \
ACTION_EXEC=ehrql \
PYTHONUNBUFFERED=True \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONHASHSEED=0
RUN mkdir /workspace
WORKDIR /workspace
# We are going to use an apt cache on the host, so disable the default debian
# docker clean up that deletes that cache on every apt install
RUN rm -f /etc/apt/apt.conf.d/docker-clean
# Add Microsoft package archive for installing MSSQL tooling
# Add deadsnakes PPA for installing new Python versions
RUN --mount=type=cache,target=/var/cache/apt \
/usr/lib/apt/apt-helper download-file \
"https://packages.microsoft.com/keys/microsoft.asc" \
/etc/apt/trusted.gpg.d/microsoft.asc && \
/usr/lib/apt/apt-helper download-file \
"https://packages.microsoft.com/config/ubuntu/20.04/prod.list" \
/etc/apt/sources.list.d/mssql-release.list && \
echo "deb https://ppa.launchpadcontent.net/deadsnakes/ppa/ubuntu focal main" \
> /etc/apt/sources.list.d/deadsnakes-ppa.list && \
/usr/lib/apt/apt-helper download-file \
'https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xf23c5a6cf475977595c89f51ba6932366a755776' \
/etc/apt/trusted.gpg.d/deadsnakes.asc
# Install root dependencies, including Python
COPY dependencies.txt /root/dependencies.txt
# use space efficient utility from base image
RUN --mount=type=cache,target=/var/cache/apt \
/usr/bin/env ACCEPT_EULA=Y /root/docker-apt-install.sh /root/dependencies.txt
#################################################
#
# Next, use the dependencies image to create an image to build dependencies
FROM ehrql-dependencies as ehrql-builder
# install build time dependencies
COPY build-dependencies.txt /root/build-dependencies.txt
RUN /root/docker-apt-install.sh /root/build-dependencies.txt
# install everything in venv for isolation from system python libraries
# hadolint ignore=DL3013,DL3042
RUN --mount=type=cache,target=/root/.cache \
/usr/bin/python3.11 -m venv /opt/venv && \
/opt/venv/bin/python -m pip install -U pip setuptools wheel
COPY requirements.prod.txt /root/requirements.prod.txt
# hadolint ignore=DL3042
RUN --mount=type=cache,target=/root/.cache python -m pip install -r /root/requirements.prod.txt
# WARNING clever/ugly python packaging hacks alert
#
# Borrowed (with modifications) from:
# https://github.com/opensafely-core/cohort-extractor/blob/669e2d5d2e/Dockerfile#L54-L84
#
# We could just do `COPY . /app` and then `pip install /app`. However, this is
# not ideal for a number of reasons:
#
# 1) Any changes to the app files will invalidate this and all subsequent
# layers, causing them to need rebuilding. This would mean basically
# reinstalling dev dependencies every time.
#
# 2) We want to use the pinned versions of dependencies in
# requirements.prod.txt rather than the unpinned versions in setup.py.
#
# 3) We want for developers be able to mount /app with their code and it Just
# Works, without reinstalling anything.
#
# So, we do the following:
#
# 1) Copy a stripped down version of the pyproject.toml file, and install an
# empty package from it alone (a test ensured the minimal version stays in
# sync with the full version)
#
# 2) We install it without deps, as they've already been installed.
#
# 3) We have set PYTHONPATH=/app, so that code copied or mounted into /app will
# be used automatically.
#
# Note: we only really need to install it at all to use setuptools entrypoints.
RUN mkdir /app
COPY pyproject.minimal.toml /app/pyproject.toml
# hadolint ignore=DL3042
RUN --mount=type=cache,target=/root/.cache \
/opt/venv/bin/python -m pip install --no-deps /app
################################################
#
# A base image with the including the prepared venv and metadata.
FROM ehrql-dependencies as ehrql-base
# Some static metadata for this specific image, as defined by:
# https://github.com/opencontainers/image-spec/blob/master/annotations.md#pre-defined-annotation-keys
# The org.opensafely.action label is used by the jobrunner to indicate this is
# an approved action image to run.
LABEL org.opencontainers.image.title="ehrql" \
org.opencontainers.image.description="ehrQL action for opensafely.org" \
org.opencontainers.image.source="https://github.com/opensafely-core/ehrql" \
org.opensafely.action="ehrql"
COPY --from=ehrql-builder /opt/venv /opt/venv
################################################
#
# Build the actual production image from the base
FROM ehrql-base as ehrql
# Copy app code. This will be automatically picked up by the virtualenv as per
# comment above
COPY ehrql /app/ehrql
RUN python -m compileall /app/ehrql
COPY bin /app/bin
# The following build details will change.
# These are the last step to make better use of Docker's build cache,
# avoiding rebuilding image layers unnecessarily.
ARG BUILD_DATE=unknown
LABEL org.opencontainers.image.created=$BUILD_DATE
ARG GITREF=unknown
LABEL org.opencontainers.image.revision=$GITREF