-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Speedup the building of Docker images #18038
Open
sandhose
wants to merge
5
commits into
develop
Choose a base branch
from
quenting/docker/speedup
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
7ee03ee
Speed up the building of the Docker image
sandhose 0eed69a
Update MarkupSafe to have up-to-date binary distributions
sandhose d113209
TEMP: build the docker image in the PR
sandhose a1d7e3c
Newsfile.
sandhose ea7a677
Recursivly fetch dependencies
sandhose File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Speed up the building of the Docker image. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -20,45 +20,16 @@ | |||||
# `poetry export | pip install -r /dev/stdin`, but beware: we have experienced bugs in | ||||||
# in `poetry export` in the past. | ||||||
|
||||||
ARG DEBIAN_VERSION=bookworm | ||||||
ARG PYTHON_VERSION=3.12 | ||||||
ARG POETRY_VERSION=1.8.3 | ||||||
|
||||||
### | ||||||
### Stage 0: generate requirements.txt | ||||||
### | ||||||
# We hardcode the use of Debian bookworm here because this could change upstream | ||||||
# and other Dockerfiles used for testing are expecting bookworm. | ||||||
FROM docker.io/library/python:${PYTHON_VERSION}-slim-bookworm AS requirements | ||||||
|
||||||
# RUN --mount is specific to buildkit and is documented at | ||||||
# https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/syntax.md#build-mounts-run---mount. | ||||||
# Here we use it to set up a cache for apt (and below for pip), to improve | ||||||
# rebuild speeds on slow connections. | ||||||
RUN \ | ||||||
--mount=type=cache,target=/var/cache/apt,sharing=locked \ | ||||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \ | ||||||
apt-get update -qq && apt-get install -yqq \ | ||||||
build-essential curl git libffi-dev libssl-dev pkg-config \ | ||||||
&& rm -rf /var/lib/apt/lists/* | ||||||
|
||||||
# Install rust and ensure its in the PATH. | ||||||
# (Rust may be needed to compile `cryptography`---which is one of poetry's | ||||||
# dependencies---on platforms that don't have a `cryptography` wheel. | ||||||
ENV RUSTUP_HOME=/rust | ||||||
ENV CARGO_HOME=/cargo | ||||||
ENV PATH=/cargo/bin:/rust/bin:$PATH | ||||||
RUN mkdir /rust /cargo | ||||||
|
||||||
RUN curl -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --default-toolchain stable --profile minimal | ||||||
|
||||||
# arm64 builds consume a lot of memory if `CARGO_NET_GIT_FETCH_WITH_CLI` is not | ||||||
# set to true, so we expose it as a build-arg. | ||||||
ARG CARGO_NET_GIT_FETCH_WITH_CLI=false | ||||||
ENV CARGO_NET_GIT_FETCH_WITH_CLI=$CARGO_NET_GIT_FETCH_WITH_CLI | ||||||
|
||||||
# We install poetry in its own build stage to avoid its dependencies conflicting with | ||||||
# synapse's dependencies. | ||||||
RUN --mount=type=cache,target=/root/.cache/pip \ | ||||||
pip install --user "poetry==1.3.2" | ||||||
### This stage is platform-agnostic, so we can use the build platform in case of cross-compilation. | ||||||
### | ||||||
FROM --platform=$BUILDPLATFORM ghcr.io/astral-sh/uv:python${PYTHON_VERSION}-${DEBIAN_VERSION} AS requirements | ||||||
|
||||||
WORKDIR /synapse | ||||||
|
||||||
|
@@ -78,38 +49,20 @@ ARG TEST_ONLY_IGNORE_POETRY_LOCKFILE | |||||
# Export the dependencies, but only if we're actually going to use the Poetry lockfile. | ||||||
# Otherwise, just create an empty requirements file so that the Dockerfile can | ||||||
# proceed. | ||||||
RUN if [ -z "$TEST_ONLY_IGNORE_POETRY_LOCKFILE" ]; then \ | ||||||
/root/.local/bin/poetry export --extras all -o /synapse/requirements.txt ${TEST_ONLY_SKIP_DEP_HASH_VERIFICATION:+--without-hashes}; \ | ||||||
ARG POETRY_VERSION | ||||||
RUN --mount=type=cache,target=/root/.cache/uv \ | ||||||
if [ -z "$TEST_ONLY_IGNORE_POETRY_LOCKFILE" ]; then \ | ||||||
uvx poetry@${POETRY_VERSION} export --extras all -o /synapse/requirements.txt ${TEST_ONLY_SKIP_DEP_HASH_VERIFICATION:+--without-hashes}; \ | ||||||
else \ | ||||||
touch /synapse/requirements.txt; \ | ||||||
touch /synapse/requirements.txt; \ | ||||||
fi | ||||||
|
||||||
### | ||||||
### Stage 1: builder | ||||||
### | ||||||
FROM docker.io/library/python:${PYTHON_VERSION}-slim-bookworm AS builder | ||||||
|
||||||
# install the OS build deps | ||||||
RUN \ | ||||||
--mount=type=cache,target=/var/cache/apt,sharing=locked \ | ||||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \ | ||||||
apt-get update -qq && apt-get install -yqq \ | ||||||
build-essential \ | ||||||
libffi-dev \ | ||||||
libjpeg-dev \ | ||||||
libpq-dev \ | ||||||
libssl-dev \ | ||||||
libwebp-dev \ | ||||||
libxml++2.6-dev \ | ||||||
libxslt1-dev \ | ||||||
openssl \ | ||||||
zlib1g-dev \ | ||||||
git \ | ||||||
curl \ | ||||||
libicu-dev \ | ||||||
pkg-config \ | ||||||
&& rm -rf /var/lib/apt/lists/* | ||||||
FROM ghcr.io/astral-sh/uv:python${PYTHON_VERSION}-${DEBIAN_VERSION} AS builder | ||||||
|
||||||
ENV UV_LINK_MODE=copy | ||||||
|
||||||
# Install rust and ensure its in the PATH | ||||||
ENV RUSTUP_HOME=/rust | ||||||
|
@@ -119,7 +72,6 @@ RUN mkdir /rust /cargo | |||||
|
||||||
RUN curl -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --default-toolchain stable --profile minimal | ||||||
|
||||||
|
||||||
# arm64 builds consume a lot of memory if `CARGO_NET_GIT_FETCH_WITH_CLI` is not | ||||||
# set to true, so we expose it as a build-arg. | ||||||
ARG CARGO_NET_GIT_FETCH_WITH_CLI=false | ||||||
|
@@ -131,8 +83,8 @@ ENV CARGO_NET_GIT_FETCH_WITH_CLI=$CARGO_NET_GIT_FETCH_WITH_CLI | |||||
# | ||||||
# This is aiming at installing the `[tool.poetry.depdendencies]` from pyproject.toml. | ||||||
COPY --from=requirements /synapse/requirements.txt /synapse/ | ||||||
RUN --mount=type=cache,target=/root/.cache/pip \ | ||||||
pip install --prefix="/install" --no-deps --no-warn-script-location -r /synapse/requirements.txt | ||||||
RUN --mount=type=cache,target=/root/.cache/uv \ | ||||||
uv pip install --prefix="/install" --no-deps -r /synapse/requirements.txt | ||||||
|
||||||
# Copy over the rest of the synapse source code. | ||||||
COPY synapse /synapse/synapse/ | ||||||
|
@@ -146,41 +98,85 @@ ARG TEST_ONLY_IGNORE_POETRY_LOCKFILE | |||||
# Install the synapse package itself. | ||||||
# If we have populated requirements.txt, we don't install any dependencies | ||||||
# as we should already have those from the previous `pip install` step. | ||||||
RUN --mount=type=cache,target=/synapse/target,sharing=locked \ | ||||||
RUN \ | ||||||
--mount=type=cache,target=/root/.cache/uv \ | ||||||
--mount=type=cache,target=/synapse/target,sharing=locked \ | ||||||
--mount=type=cache,target=${CARGO_HOME}/registry,sharing=locked \ | ||||||
if [ -z "$TEST_ONLY_IGNORE_POETRY_LOCKFILE" ]; then \ | ||||||
pip install --prefix="/install" --no-deps --no-warn-script-location /synapse[all]; \ | ||||||
uv pip install --prefix="/install" --no-deps /synapse[all]; \ | ||||||
else \ | ||||||
pip install --prefix="/install" --no-warn-script-location /synapse[all]; \ | ||||||
uv pip install --prefix="/install" /synapse[all]; \ | ||||||
fi | ||||||
|
||||||
### | ||||||
### Stage 2: runtime | ||||||
### Stage 2: runtime dependencies download for ARM64 and AMD64 | ||||||
### | ||||||
FROM --platform=$BUILDPLATFORM docker.io/library/debian:${DEBIAN_VERSION} AS runtime-deps | ||||||
|
||||||
FROM docker.io/library/python:${PYTHON_VERSION}-slim-bookworm | ||||||
# Tell apt to keep downloaded package files, as we're using cache mounts. | ||||||
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache | ||||||
|
||||||
LABEL org.opencontainers.image.url='https://matrix.org/docs/projects/server/synapse' | ||||||
LABEL org.opencontainers.image.documentation='https://github.com/element-hq/synapse/blob/master/docker/README.md' | ||||||
LABEL org.opencontainers.image.source='https://github.com/element-hq/synapse.git' | ||||||
LABEL org.opencontainers.image.licenses='AGPL-3.0-or-later' | ||||||
# Add both target architectures | ||||||
RUN dpkg --add-architecture arm64 | ||||||
RUN dpkg --add-architecture amd64 | ||||||
|
||||||
# Fetch the runtime dependencies debs for both architectures | ||||||
# We do that by building a recursive list of packages we need to download with `apt-cache depends` | ||||||
# and then downloading them with `apt-get download`. | ||||||
RUN \ | ||||||
--mount=type=cache,target=/var/cache/apt,sharing=locked \ | ||||||
--mount=type=cache,target=/var/lib/apt,sharing=locked \ | ||||||
apt-get update -qq && apt-get install -yqq \ | ||||||
curl \ | ||||||
gosu \ | ||||||
libjpeg62-turbo \ | ||||||
libpq5 \ | ||||||
libwebp7 \ | ||||||
xmlsec1 \ | ||||||
libjemalloc2 \ | ||||||
libicu72 \ | ||||||
libssl-dev \ | ||||||
openssl \ | ||||||
&& rm -rf /var/lib/apt/lists/* | ||||||
apt-get update -qq && \ | ||||||
apt-get install -y --no-install-recommends rsync && \ | ||||||
apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances --no-pre-depends \ | ||||||
curl \ | ||||||
gosu \ | ||||||
libjpeg62-turbo \ | ||||||
libpq5 \ | ||||||
libwebp7 \ | ||||||
xmlsec1 \ | ||||||
libjemalloc2 \ | ||||||
libicu \ | ||||||
| grep '^\w' > /tmp/pkg-list && \ | ||||||
for arch in arm64 amd64; do \ | ||||||
mkdir -p /tmp/debs-${arch} && \ | ||||||
cd /tmp/debs-${arch} && \ | ||||||
apt-get download $(sed "s/$/:${arch}/" /tmp/pkg-list); \ | ||||||
done | ||||||
|
||||||
# Extract the debs for each architecture | ||||||
# On the runtime image, /lib is a symlink to /usr/lib, so we need to copy the | ||||||
# libraries to the right place, else the `COPY` won't work. | ||||||
# On amd64, we'll also have a /lib64 folder with ld-linux-x86-64.so.2, which is | ||||||
# already present in the runtime image. | ||||||
RUN \ | ||||||
for arch in arm64 amd64; do \ | ||||||
mkdir -p /install-${arch}/var/lib/dpkg/status.d/ && \ | ||||||
for deb in /tmp/debs-${arch}/*.deb; do \ | ||||||
package_name=$(dpkg-deb -I ${deb} | awk '/^ Package: .*$/ {print $2}'); \ | ||||||
echo "Process: ${package_name}"; \ | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
dpkg --ctrl-tarfile $deb | tar -Ox ./control > /install-${arch}/var/lib/dpkg/status.d/${package_name}; \ | ||||||
dpkg --extract $deb /install-${arch} || exit 10; \ | ||||||
done; \ | ||||||
rsync -avr /install-${arch}/lib/ /install-${arch}/usr/lib; \ | ||||||
rm -rf /install-${arch}/lib /install-${arch}/lib64; \ | ||||||
done | ||||||
|
||||||
|
||||||
### | ||||||
### Stage 3: runtime | ||||||
### | ||||||
|
||||||
FROM docker.io/library/python:${PYTHON_VERSION}-slim-${DEBIAN_VERSION} | ||||||
|
||||||
ARG TARGETARCH | ||||||
|
||||||
LABEL org.opencontainers.image.url='https://matrix.org/docs/projects/server/synapse' | ||||||
LABEL org.opencontainers.image.documentation='https://github.com/element-hq/synapse/blob/master/docker/README.md' | ||||||
LABEL org.opencontainers.image.source='https://github.com/element-hq/synapse.git' | ||||||
LABEL org.opencontainers.image.licenses='AGPL-3.0-or-later' | ||||||
|
||||||
COPY --from=runtime-deps /install-${TARGETARCH} / | ||||||
COPY --from=builder /install /usr/local | ||||||
COPY ./docker/start.py /start.py | ||||||
COPY ./docker/conf /conf | ||||||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you leave a comment explaining why this is useful?