summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlysses Souza <ulysses.souza@docker.com>2019-04-10 21:05:02 +0200
committerUlysses Souza <ulysses.souza@docker.com>2019-04-17 16:08:33 +0200
commitc217bab7f6123de80dbd55c99c2254666d766fb3 (patch)
tree33cee429f2147025d45a3e3e4272c4c2e158151e
parent9e3d9f66811f0d21dfca65874a2937e8cf210089 (diff)
Refactor Dockerfiles for generating musl binaries
- Refactor Dockerfile to be used for tests and distribution on docker hub on debian and alpine to use for final usage and also tests - Adapt test scripts to the new Dockerfiles' structure - Adapt Jenkinsfile to add alpine to the test matrix Signed-off-by: Ulysses Souza <ulysses.souza@docker.com>
-rw-r--r--Dockerfile85
-rw-r--r--Dockerfile.run19
-rw-r--r--Jenkinsfile46
-rwxr-xr-xdocker-compose-entrypoint.sh20
-rwxr-xr-xpyinstaller/ldd13
-rwxr-xr-xscript/build/linux19
-rwxr-xr-xscript/build/linux-entrypoint37
-rwxr-xr-xscript/build/test-image15
-rwxr-xr-xscript/test/ci3
-rwxr-xr-xscript/test/default9
10 files changed, 173 insertions, 93 deletions
diff --git a/Dockerfile b/Dockerfile
index b887bcc4..1a3c501a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,36 +1,71 @@
-FROM docker:18.06.1 as docker
-FROM python:3.7.2-stretch
+ARG DOCKER_VERSION=18.09.5
+ARG PYTHON_VERSION=3.7.3
+ARG BUILD_ALPINE_VERSION=3.9
+ARG BUILD_DEBIAN_VERSION=slim-stretch
+ARG RUNTIME_ALPINE_VERSION=3.9.3
+ARG RUNTIME_DEBIAN_VERSION=stretch-20190326-slim
-RUN set -ex; \
- apt-get update -qq; \
- apt-get install -y \
- locales \
- python-dev \
- git
+ARG BUILD_PLATFORM=alpine
-COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker
+FROM docker:${DOCKER_VERSION} AS docker-cli
-# Python3 requires a valid locale
-RUN echo "en_US.UTF-8 UTF-8" > /etc/locale.gen && locale-gen
-ENV LANG en_US.UTF-8
+FROM python:${PYTHON_VERSION}-alpine${BUILD_ALPINE_VERSION} AS build-alpine
+RUN apk add --no-cache \
+ bash \
+ build-base \
+ ca-certificates \
+ curl \
+ gcc \
+ git \
+ libc-dev \
+ libffi-dev \
+ libgcc \
+ make \
+ musl-dev \
+ openssl \
+ openssl-dev \
+ python2 \
+ python2-dev \
+ zlib-dev
+ENV BUILD_BOOTLOADER=1
-RUN useradd -d /home/user -m -s /bin/bash user
-WORKDIR /code/
+FROM python:${PYTHON_VERSION}-${BUILD_DEBIAN_VERSION} AS build-debian
+RUN apt-get update && apt-get install -y \
+ curl \
+ gcc \
+ git \
+ libc-dev \
+ libgcc-6-dev \
+ make \
+ openssl \
+ python2.7-dev
+FROM build-${BUILD_PLATFORM} AS build
+COPY docker-compose-entrypoint.sh /usr/local/bin/
+ENTRYPOINT ["sh", "/usr/local/bin/docker-compose-entrypoint.sh"]
+COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
+WORKDIR /code/
# FIXME(chris-crone): virtualenv 16.3.0 breaks build, force 16.2.0 until fixed
RUN pip install virtualenv==16.2.0
RUN pip install tox==2.9.1
-ADD requirements.txt /code/
-ADD requirements-dev.txt /code/
-ADD .pre-commit-config.yaml /code/
-ADD setup.py /code/
-ADD tox.ini /code/
-ADD compose /code/compose/
-ADD README.md /code/
+COPY requirements.txt .
+COPY requirements-dev.txt .
+COPY .pre-commit-config.yaml .
+COPY tox.ini .
+COPY setup.py .
+COPY README.md .
+COPY compose compose/
RUN tox --notest
+COPY . .
+ARG GIT_COMMIT=unknown
+ENV DOCKER_COMPOSE_GITSHA=$GIT_COMMIT
+RUN script/build/linux-entrypoint
-ADD . /code/
-RUN chown -R user /code/
-
-ENTRYPOINT ["/code/.tox/py37/bin/docker-compose"]
+FROM alpine:${RUNTIME_ALPINE_VERSION} AS runtime-alpine
+FROM debian:${RUNTIME_DEBIAN_VERSION} AS runtime-debian
+FROM runtime-${BUILD_PLATFORM} AS runtime
+COPY docker-compose-entrypoint.sh /usr/local/bin/
+ENTRYPOINT ["sh", "/usr/local/bin/docker-compose-entrypoint.sh"]
+COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
+COPY --from=build /usr/local/bin/docker-compose /usr/local/bin/docker-compose
diff --git a/Dockerfile.run b/Dockerfile.run
deleted file mode 100644
index ccc86ea9..00000000
--- a/Dockerfile.run
+++ /dev/null
@@ -1,19 +0,0 @@
-FROM docker:18.06.1 as docker
-FROM alpine:3.8
-
-ENV GLIBC 2.28-r0
-
-RUN apk update && apk add --no-cache openssl ca-certificates curl libgcc && \
- curl -fsSL -o /etc/apk/keys/sgerrand.rsa.pub https://alpine-pkgs.sgerrand.com/sgerrand.rsa.pub && \
- curl -fsSL -o glibc-$GLIBC.apk https://github.com/sgerrand/alpine-pkg-glibc/releases/download/$GLIBC/glibc-$GLIBC.apk && \
- apk add --no-cache glibc-$GLIBC.apk && \
- ln -s /lib/libz.so.1 /usr/glibc-compat/lib/ && \
- ln -s /lib/libc.musl-x86_64.so.1 /usr/glibc-compat/lib && \
- ln -s /usr/lib/libgcc_s.so.1 /usr/glibc-compat/lib && \
- rm /etc/apk/keys/sgerrand.rsa.pub glibc-$GLIBC.apk && \
- apk del curl
-
-COPY --from=docker /usr/local/bin/docker /usr/local/bin/docker
-COPY dist/docker-compose-Linux-x86_64 /usr/local/bin/docker-compose
-
-ENTRYPOINT ["docker-compose"]
diff --git a/Jenkinsfile b/Jenkinsfile
index a19e8227..51fecf99 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,29 +1,32 @@
#!groovy
-def image
-
-def buildImage = { ->
+def buildImage = { String baseImage ->
+ def image
wrappedNode(label: "ubuntu && !zfs", cleanWorkspace: true) {
- stage("build image") {
+ stage("build image for \"${baseImage}\"") {
checkout(scm)
- def imageName = "dockerbuildbot/compose:${gitCommit()}"
+ def imageName = "dockerbuildbot/compose:${baseImage}-${gitCommit()}"
image = docker.image(imageName)
try {
image.pull()
} catch (Exception exc) {
- image = docker.build(imageName, ".")
- image.push()
+ sh "docker build -t ${imageName} --target build --build-arg BUILD_PLATFORM=${baseImage} ."
+ sh "docker push ${imageName}"
+ echo "${imageName}"
+ return imageName
}
}
}
+ echo "image.id: ${image.id}"
+ return image.id
}
-def get_versions = { int number ->
+def get_versions = { String imageId, int number ->
def docker_versions
wrappedNode(label: "ubuntu && !zfs") {
def result = sh(script: """docker run --rm \\
--entrypoint=/code/.tox/py27/bin/python \\
- ${image.id} \\
+ ${imageId} \\
/code/script/test/versions.py -n ${number} docker/docker-ce recent
""", returnStdout: true
)
@@ -35,6 +38,8 @@ def get_versions = { int number ->
def runTests = { Map settings ->
def dockerVersions = settings.get("dockerVersions", null)
def pythonVersions = settings.get("pythonVersions", null)
+ def baseImage = settings.get("baseImage", null)
+ def imageName = settings.get("image", null)
if (!pythonVersions) {
throw new Exception("Need Python versions to test. e.g.: `runTests(pythonVersions: 'py27,py37')`")
@@ -45,7 +50,7 @@ def runTests = { Map settings ->
{ ->
wrappedNode(label: "ubuntu && !zfs", cleanWorkspace: true) {
- stage("test python=${pythonVersions} / docker=${dockerVersions}") {
+ stage("test python=${pythonVersions} / docker=${dockerVersions} / baseImage=${baseImage}") {
checkout(scm)
def storageDriver = sh(script: 'docker info | awk -F \': \' \'$1 == "Storage Driver" { print $2; exit }\'', returnStdout: true).trim()
echo "Using local system's storage driver: ${storageDriver}"
@@ -55,13 +60,13 @@ def runTests = { Map settings ->
--privileged \\
--volume="\$(pwd)/.git:/code/.git" \\
--volume="/var/run/docker.sock:/var/run/docker.sock" \\
- -e "TAG=${image.id}" \\
+ -e "TAG=${imageName}" \\
-e "STORAGE_DRIVER=${storageDriver}" \\
-e "DOCKER_VERSIONS=${dockerVersions}" \\
-e "BUILD_NUMBER=\$BUILD_TAG" \\
-e "PY_TEST_VERSIONS=${pythonVersions}" \\
--entrypoint="script/test/ci" \\
- ${image.id} \\
+ ${imageName} \\
--verbose
"""
}
@@ -69,15 +74,16 @@ def runTests = { Map settings ->
}
}
-buildImage()
-
def testMatrix = [failFast: true]
-def docker_versions = get_versions(2)
-
-for (int i = 0; i < docker_versions.length; i++) {
- def dockerVersion = docker_versions[i]
- testMatrix["${dockerVersion}_py27"] = runTests([dockerVersions: dockerVersion, pythonVersions: "py27"])
- testMatrix["${dockerVersion}_py37"] = runTests([dockerVersions: dockerVersion, pythonVersions: "py37"])
+def baseImages = ['alpine', 'debian']
+def pythonVersions = ['py27', 'py37']
+baseImages.each { baseImage ->
+ def imageName = buildImage(baseImage)
+ get_versions(imageName, 2).each { dockerVersion ->
+ pythonVersions.each { pyVersion ->
+ testMatrix["${baseImage}_${dockerVersion}_${pyVersion}"] = runTests([baseImage: baseImage, image: imageName, dockerVersions: dockerVersion, pythonVersions: pyVersion])
+ }
+ }
}
parallel(testMatrix)
diff --git a/docker-compose-entrypoint.sh b/docker-compose-entrypoint.sh
new file mode 100755
index 00000000..84436fa0
--- /dev/null
+++ b/docker-compose-entrypoint.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+set -e
+
+# first arg is `-f` or `--some-option`
+if [ "${1#-}" != "$1" ]; then
+ set -- docker-compose "$@"
+fi
+
+# if our command is a valid Docker subcommand, let's invoke it through Docker instead
+# (this allows for "docker run docker ps", etc)
+if docker-compose help "$1" > /dev/null 2>&1; then
+ set -- docker-compose "$@"
+fi
+
+# if we have "--link some-docker:docker" and not DOCKER_HOST, let's set DOCKER_HOST automatically
+if [ -z "$DOCKER_HOST" -a "$DOCKER_PORT_2375_TCP" ]; then
+ export DOCKER_HOST='tcp://docker:2375'
+fi
+
+exec "$@"
diff --git a/pyinstaller/ldd b/pyinstaller/ldd
new file mode 100755
index 00000000..3f10ad27
--- /dev/null
+++ b/pyinstaller/ldd
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+# From http://wiki.musl-libc.org/wiki/FAQ#Q:_where_is_ldd_.3F
+#
+# Musl's dynlinker comes with ldd functionality built in. just create a
+# symlink from ld-musl-$ARCH.so to /bin/ldd. If the dynlinker was started
+# as "ldd", it will detect that and print the appropriate DSO information.
+#
+# Instead, this string replaced "ldd" with the package so that pyinstaller
+# can find the actual lib.
+exec /usr/bin/ldd "$@" | \
+ sed -r 's/([^[:space:]]+) => ldd/\1 => \/lib\/\1/g' | \
+ sed -r 's/ldd \(.*\)//g'
diff --git a/script/build/linux b/script/build/linux
index 056940ad..8de7218d 100755
--- a/script/build/linux
+++ b/script/build/linux
@@ -4,10 +4,15 @@ set -ex
./script/clean
-TAG="docker-compose"
-docker build -t "$TAG" .
-docker run \
- --rm --entrypoint="script/build/linux-entrypoint" \
- -v $(pwd)/dist:/code/dist \
- -v $(pwd)/.git:/code/.git \
- "$TAG"
+TMP_CONTAINER="tmpcontainer"
+TAG="docker/compose:tmp-glibc-linux-binary"
+DOCKER_COMPOSE_GITSHA=$(script/build/write-git-sha)
+
+docker build -t "${TAG}" . \
+ --build-arg BUILD_PLATFORM=debian \
+ --build-arg GIT_COMMIT=${DOCKER_COMPOSE_GITSHA}
+docker create --name ${TMP_CONTAINER} ${TAG}
+mkdir -p dist
+docker cp ${TMP_CONTAINER}:/usr/local/bin/docker-compose dist/docker-compose-Linux-x86_64
+docker container rm -f ${TMP_CONTAINER}
+docker image rm -f ${TAG}
diff --git a/script/build/linux-entrypoint b/script/build/linux-entrypoint
index 34c16ac6..1556bbf2 100755
--- a/script/build/linux-entrypoint
+++ b/script/build/linux-entrypoint
@@ -2,14 +2,35 @@
set -ex
-TARGET=dist/docker-compose-$(uname -s)-$(uname -m)
-VENV=/code/.tox/py37
+CODE_PATH=/code
+VENV=${CODE_PATH}/.tox/py37
-mkdir -p `pwd`/dist
-chmod 777 `pwd`/dist
+cd ${CODE_PATH}
+mkdir -p dist
+chmod 777 dist
-$VENV/bin/pip install -q -r requirements-build.txt
+${VENV}/bin/pip3 install -q -r requirements-build.txt
+
+# TODO(ulyssessouza) To check if really needed
./script/build/write-git-sha
-su -c "$VENV/bin/pyinstaller docker-compose.spec" user
-mv dist/docker-compose $TARGET
-$TARGET version
+
+export PATH="${CODE_PATH}/pyinstaller:${PATH}"
+
+if [ ! -z "${BUILD_BOOTLOADER}" ]; then
+ # Build bootloader for alpine
+ git clone --single-branch --branch master https://github.com/pyinstaller/pyinstaller.git /tmp/pyinstaller
+ cd /tmp/pyinstaller/bootloader
+ git checkout v3.4
+ ${VENV}/bin/python3 ./waf configure --no-lsb all
+ ${VENV}/bin/pip3 install ..
+ cd ${CODE_PATH}
+ rm -Rf /tmp/pyinstaller
+else
+ echo "NOT compiling bootloader!!!"
+fi
+
+${VENV}/bin/pyinstaller --exclude-module pycrypto --exclude-module PyInstaller docker-compose.spec
+ls -la dist/
+ldd dist/docker-compose
+mv dist/docker-compose /usr/local/bin
+docker-compose version
diff --git a/script/build/test-image b/script/build/test-image
index a2eb62cd..9d880c27 100755
--- a/script/build/test-image
+++ b/script/build/test-image
@@ -7,11 +7,12 @@ if [ -z "$1" ]; then
exit 1
fi
-TAG=$1
+TAG="$1"
+IMAGE="docker/compose-tests"
-docker build -t docker-compose-tests:tmp .
-ctnr_id=$(docker create --entrypoint=tox docker-compose-tests:tmp)
-docker commit $ctnr_id docker/compose-tests:latest
-docker tag docker/compose-tests:latest docker/compose-tests:$TAG
-docker rm -f $ctnr_id
-docker rmi -f docker-compose-tests:tmp
+DOCKER_COMPOSE_GITSHA=$(script/build/write-git-sha)
+docker build -t "${IMAGE}:${TAG}" . \
+ --target build \
+ --build-arg BUILD_PLATFORM=debian \
+ --build-arg GIT_COMMIT=${DOCKER_COMPOSE_GITSHA}
+docker tag ${IMAGE}:${TAG} ${IMAGE}:latest
diff --git a/script/test/ci b/script/test/ci
index 8d3aa56c..bbcedac4 100755
--- a/script/test/ci
+++ b/script/test/ci
@@ -20,6 +20,3 @@ export DOCKER_DAEMON_ARGS="--storage-driver=$STORAGE_DRIVER"
GIT_VOLUME="--volumes-from=$(hostname)"
. script/test/all
-
->&2 echo "Building Linux binary"
-. script/build/linux-entrypoint
diff --git a/script/test/default b/script/test/default
index cbb6a67c..d24b41b0 100755
--- a/script/test/default
+++ b/script/test/default
@@ -3,17 +3,18 @@
set -ex
-TAG="docker-compose:$(git rev-parse --short HEAD)"
+TAG="docker-compose:alpine-$(git rev-parse --short HEAD)"
-# By default use the Dockerfile, but can be overridden to use an alternative file
+# By default use the Dockerfile.alpine, but can be overridden to use an alternative file
# e.g DOCKERFILE=Dockerfile.armhf script/test/default
-DOCKERFILE="${DOCKERFILE:-Dockerfile}"
+DOCKERFILE="${DOCKERFILE:-Dockerfile.alpine}"
+DOCKER_BUILD_TARGET="${DOCKER_BUILD_TARGET:-build}"
rm -rf coverage-html
# Create the host directory so it's owned by $USER
mkdir -p coverage-html
-docker build -f ${DOCKERFILE} -t "$TAG" .
+docker build -f ${DOCKERFILE} -t "${TAG}" --target "${DOCKER_BUILD_TARGET}" .
GIT_VOLUME="--volume=$(pwd)/.git:/code/.git"
. script/test/all