Skip to content

Commit d950201

Browse files
committed
Migrate dockerfiles to use multi-stage builds.
Summary: We previously emulated multi-staged builds using two dockerfiles, native support from Docker allows us to merge them into one, simplifying our scripts. For more details about multi-stage builds, see: https://docs.docker.com/develop/develop-images/multistage-build/ Reviewers: mehdi_amini, klimek, sammccall Reviewed By: sammccall Subscribers: llvm-commits, ioeric, cfe-commits Differential Revision: https://reviews.llvm.org/D44787 llvm-svn: 328503
1 parent 4fd4fd6 commit d950201

File tree

9 files changed

+70
-155
lines changed

9 files changed

+70
-155
lines changed

llvm/docs/Docker.rst

Lines changed: 22 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -53,24 +53,15 @@ serve as a basis for anyone who wants to create their own Docker image with
5353
LLVM components, compiled from sources. The sources are checked out from the
5454
upstream svn repository when building the image.
5555

56-
Inside each subfolder we host Dockerfiles for two images:
57-
58-
- ``build/`` image is used to compile LLVM, it installs a system compiler and all
59-
build dependencies of LLVM. After the build process is finished, the build
60-
image will have an archive with compiled components at ``/tmp/clang.tar.gz``.
61-
- ``release/`` image usually only contains LLVM components, compiled by the
62-
``build/`` image, and also libstdc++ and binutils to make image minimally
63-
useful for C++ development. The assumption is that you usually want clang to
64-
be one of the provided components.
65-
66-
To build both of those images, use ``build_docker_image.sh`` script.
67-
It will checkout LLVM sources and build clang in the ``build`` container, copy results
68-
of the build to the local filesystem and then build the ``release`` container using
69-
those. The ``build_docker_image.sh`` accepts a list of LLVM repositories to
70-
checkout, and arguments for CMake invocation.
56+
The resulting image contains only the requested LLVM components and a few extra
57+
packages to make the image minimally useful for C++ development, e.g. libstdc++
58+
and binutils.
59+
60+
The interface to run the build is ``build_docker_image.sh`` script. It accepts a
61+
list of LLVM repositories to checkout and arguments for CMake invocation.
7162

7263
If you want to write your own docker image, start with an ``example/`` subfolder.
73-
It provides incomplete Dockerfiles with (very few) FIXMEs explaining the steps
64+
It provides an incomplete Dockerfile with (very few) FIXMEs explaining the steps
7465
you need to take in order to make your Dockerfiles functional.
7566

7667
Usage
@@ -110,10 +101,10 @@ this command will do that:
110101
-DBOOTSTRAP_CMAKE_BUILD_TYPE=Release \
111102
-DCLANG_ENABLE_BOOTSTRAP=ON -DCLANG_BOOTSTRAP_TARGETS="install-clang;install-clang-headers"
112103
113-
This will produce two images, a release image ``clang-debian8:staging`` and a
114-
build image ``clang-debian8-build:staging`` from the latest upstream revision.
115-
After the image is built you can run bash inside a container based on your
116-
image like this:
104+
This will produce a new image ``clang-debian8:staging`` from the latest
105+
upstream revision.
106+
After the image is built you can run bash inside a container based on your image
107+
like this:
117108

118109
.. code-block:: bash
119110
@@ -181,19 +172,14 @@ debian8-based image using the latest ``google/stable`` sources for you:
181172
182173
Minimizing docker image size
183174
============================
184-
Due to Docker restrictions we use two images (i.e., build and release folders)
185-
for the release image to be as small as possible. It's much easier to achieve
186-
that using two images, because Docker would store a filesystem layer for each
187-
command in the Dockerfile, i.e. if you install some packages in one command,
188-
then remove those in a separate command, the size of the resulting image will
189-
still be proportinal to the size of an image with installed packages.
190-
Therefore, we strive to provide a very simple release image which only copies
191-
compiled clang and does not do anything else.
192-
193-
Docker 1.13 added a ``--squash`` flag that allows to flatten the layers of the
194-
image, i.e. remove the parts that were actually deleted. That is an easier way
195-
to produce the smallest images possible by using just a single image. We do not
196-
use it because as of today the flag is in experimental stage and not everyone
197-
may have the latest docker version available. When the flag is out of
198-
experimental stage, we should investigate replacing two images approach with
199-
just a single image, built using ``--squash`` flag.
175+
Due to how Docker's filesystem works, all intermediate writes are persisted in
176+
the resulting image, even if they are removed in the following commands.
177+
To minimize the resulting image size we use `multi-stage Docker builds
178+
<https://docs.docker.com/develop/develop-images/multistage-build/>`_.
179+
Internally Docker builds two images. The first image does all the work: installs
180+
build dependencies, checks out LLVM source code, compiles LLVM, etc.
181+
The first image is only used during build and does not have a descriptive name,
182+
i.e. it is only accessible via the hash value after the build is finished.
183+
The second image is our resulting image. It contains only the built binaries
184+
and not any build dependencies. It is also accessible via a descriptive name
185+
(specified by -d and -t flags).

llvm/utils/docker/build_docker_image.sh

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -163,19 +163,9 @@ if [ "$DOCKER_TAG" != "" ]; then
163163
DOCKER_TAG=":$DOCKER_TAG"
164164
fi
165165

166-
echo "Building from $IMAGE_SOURCE"
167-
echo "Building $DOCKER_REPOSITORY-build$DOCKER_TAG"
168-
docker build -t "$DOCKER_REPOSITORY-build$DOCKER_TAG" \
166+
echo "Building ${DOCKER_REPOSITORY}${DOCKER_TAG} from $IMAGE_SOURCE"
167+
docker build -t "${DOCKER_REPOSITORY}${DOCKER_TAG}" \
169168
--build-arg "buildscript_args=$BUILDSCRIPT_ARGS" \
170-
-f "$BUILD_DIR/$IMAGE_SOURCE/build/Dockerfile" \
169+
-f "$BUILD_DIR/$IMAGE_SOURCE/Dockerfile" \
171170
"$BUILD_DIR"
172-
173-
echo "Copying clang installation to release image sources"
174-
docker run -v "$BUILD_DIR/$IMAGE_SOURCE:/workspace" "$DOCKER_REPOSITORY-build$DOCKER_TAG" \
175-
cp /tmp/clang.tar.gz /workspace/release
176-
177-
echo "Building release image"
178-
docker build -t "${DOCKER_REPOSITORY}${DOCKER_TAG}" \
179-
"$BUILD_DIR/$IMAGE_SOURCE/release"
180-
181171
echo "Done"

llvm/utils/docker/debian8/build/Dockerfile renamed to llvm/utils/docker/debian8/Dockerfile

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,27 @@
66
# License. See LICENSE.TXT for details.
77
#
88
#===----------------------------------------------------------------------===//
9-
# Produces an image that compiles and archives clang, based on debian8.
10-
FROM launcher.gcr.io/google/debian8:latest
11-
9+
# Stage 1. Check out LLVM source code and run the build.
10+
FROM launcher.gcr.io/google/debian8:latest as builder
1211
LABEL maintainer "LLVM Developers"
13-
1412
# Install build dependencies of llvm.
1513
# First, Update the apt's source list and include the sources of the packages.
1614
RUN grep deb /etc/apt/sources.list | \
1715
sed 's/^deb/deb-src /g' >> /etc/apt/sources.list
18-
1916
# Install compiler, python and subversion.
2017
RUN apt-get update && \
2118
apt-get install -y --no-install-recommends ca-certificates gnupg \
2219
build-essential python wget subversion unzip && \
2320
rm -rf /var/lib/apt/lists/*
24-
2521
# Install a newer ninja release. It seems the older version in the debian repos
2622
# randomly crashes when compiling llvm.
2723
RUN wget "https://github.com/ninja-build/ninja/releases/download/v1.8.2/ninja-linux.zip" && \
2824
echo "d2fea9ff33b3ef353161ed906f260d565ca55b8ca0568fa07b1d2cab90a84a07 ninja-linux.zip" \
2925
| sha256sum -c && \
3026
unzip ninja-linux.zip -d /usr/local/bin && \
3127
rm ninja-linux.zip
32-
3328
# Import public key required for verifying signature of cmake download.
3429
RUN gpg --keyserver hkp://pgp.mit.edu --recv 0x2D2CEF1034921684
35-
3630
# Download, verify and install cmake version that can compile clang into /usr/local.
3731
# (Version in debian8 repos is is too old)
3832
RUN mkdir /tmp/cmake-install && cd /tmp/cmake-install && \
@@ -47,9 +41,18 @@ RUN mkdir /tmp/cmake-install && cd /tmp/cmake-install && \
4741

4842
ADD checksums /tmp/checksums
4943
ADD scripts /tmp/scripts
50-
5144
# Arguments passed to build_install_clang.sh.
5245
ARG buildscript_args
53-
54-
# Run the build. Results of the build will be available as /tmp/clang.tar.gz.
46+
# Run the build. Results of the build will be available at /tmp/clang-install/.
5547
RUN /tmp/scripts/build_install_llvm.sh ${buildscript_args}
48+
49+
50+
# Stage 2. Produce a minimal release image with build results.
51+
FROM launcher.gcr.io/google/debian8:latest
52+
LABEL maintainer "LLVM Developers"
53+
# Install packages for minimal useful image.
54+
RUN apt-get update && \
55+
apt-get install -y --no-install-recommends libstdc++-4.9-dev binutils && \
56+
rm -rf /var/lib/apt/lists/*
57+
# Copy build results of stage 1 to /usr/local.
58+
COPY --from=builder /tmp/clang-install/ /usr/local/

llvm/utils/docker/debian8/release/Dockerfile

Lines changed: 0 additions & 21 deletions
This file was deleted.

llvm/utils/docker/example/build/Dockerfile renamed to llvm/utils/docker/example/Dockerfile

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,29 @@
99
# This is an example Dockerfile to build an image that compiles clang.
1010
# Replace FIXMEs to prepare your own image.
1111

12+
# Stage 1. Check out LLVM source code and run the build.
1213
# FIXME: Replace 'ubuntu' with your base image
13-
FROM ubuntu
14-
14+
FROM ubuntu as builder
1515
# FIXME: Change maintainer name
1616
LABEL maintainer "Maintainer <maintainer@email>"
17-
18-
# FIXME: Install llvm/clang build dependencies. Including compiler to
17+
# FIXME: Install llvm/clang build dependencies here. Including compiler to
1918
# build stage1, cmake, subversion, ninja, etc.
2019

2120
ADD checksums /tmp/checksums
2221
ADD scripts /tmp/scripts
23-
2422
# Arguments passed to build_install_clang.sh.
2523
ARG buildscript_args
26-
27-
# Run the build. Results of the build will be available as /tmp/clang.tar.gz.
24+
# Run the build. Results of the build will be available as /tmp/clang-install.
2825
RUN /tmp/scripts/build_install_llvm.sh ${buildscript_args}
26+
27+
28+
# Stage 2. Produce a minimal release image with build results.
29+
# FIXME: Replace 'ubuntu' with your base image.
30+
FROM ubuntu
31+
# FIXME: Change maintainer name.
32+
LABEL maintainer "Maintainer <maintainer@email>"
33+
# FIXME: Install all packages you want to have in your release container.
34+
# A minimal useful installation should include at least libstdc++ and binutils.
35+
36+
# Copy build results of stage 1 to /usr/local.
37+
COPY --from=builder /tmp/clang-install/ /usr/local/

llvm/utils/docker/example/release/Dockerfile

Lines changed: 0 additions & 24 deletions
This file was deleted.

llvm/utils/docker/nvidia-cuda/build/Dockerfile renamed to llvm/utils/docker/nvidia-cuda/Dockerfile

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,26 @@
66
# License. See LICENSE.TXT for details.
77
#
88
#===----------------------------------------------------------------------===//
9-
# Produces an image that compiles and archives clang, based on nvidia/cuda
10-
# image.
11-
FROM nvidia/cuda:8.0-devel
12-
9+
# Stage 1. Check out LLVM source code and run the build.
10+
FROM nvidia/cuda:8.0-devel as builder
1311
LABEL maintainer "LLVM Developers"
14-
15-
# Arguments to pass to build_install_clang.sh.
16-
ARG buildscript_args
17-
1812
# Install llvm build dependencies.
1913
RUN apt-get update && \
2014
apt-get install -y --no-install-recommends ca-certificates cmake python \
21-
subversion ninja-build && \
15+
subversion ninja-build && \
2216
rm -rf /var/lib/apt/lists/*
2317

2418
ADD checksums /tmp/checksums
2519
ADD scripts /tmp/scripts
26-
2720
# Arguments passed to build_install_clang.sh.
2821
ARG buildscript_args
29-
30-
# Run the build. Results of the build will be available as /tmp/clang.tar.gz.
22+
# Run the build. Results of the build will be available at /tmp/clang-install/.
3123
RUN /tmp/scripts/build_install_llvm.sh ${buildscript_args}
24+
25+
26+
# Stage 2. Produce a minimal release image with build results.
27+
FROM nvidia/cuda:8.0-devel
28+
LABEL maintainer "LLVM Developers"
29+
# Copy clang installation into this container.
30+
COPY --from=builder /tmp/clang-install/ /usr/local/
31+
# C++ standard library and binutils are already included in the base package.

llvm/utils/docker/nvidia-cuda/release/Dockerfile

Lines changed: 0 additions & 23 deletions
This file was deleted.

llvm/utils/docker/scripts/build_install_llvm.sh

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Usage: build_install_llvm.sh [options] -- [cmake-args]
1616
1717
Checkout svn sources and run cmake with the specified arguments. Used
1818
inside docker container.
19-
Passes additional -DCMAKE_INSTALL_PREFIX and archives the contents of
20-
the directory to /tmp/clang.tar.gz.
19+
Passes additional -DCMAKE_INSTALL_PREFIX and puts the build results into
20+
/tmp/clang-install/ directory.
2121
2222
Available options:
2323
-h|--help show this help message
@@ -244,12 +244,7 @@ ninja $CMAKE_INSTALL_TARGETS
244244

245245
popd
246246

247-
# Pack the installed clang into an archive.
248-
echo "Archiving clang installation to /tmp/clang.tar.gz"
249-
cd "$CLANG_INSTALL_DIR"
250-
tar -czf /tmp/clang.tar.gz *
251-
252247
# Cleanup.
253-
rm -rf "$CLANG_BUILD_DIR" "$CLANG_INSTALL_DIR"
248+
rm -rf "$CLANG_BUILD_DIR"
254249

255250
echo "Done"

0 commit comments

Comments
 (0)