Add multi-architecture Docker image build
* Adds a shell script with functions to install multi-architecture docker support, as well as build, deploy, and test the shellcheck docker images for the same set of architectures for which binaries were already built and deployed as tarballs. * Hooks up the multi-architecture docker build, deploy, and test to the existing Travis CI/CD pipeline. It is organized as a separate stage which only runs if all previous steps in the already existing test stage succeed.
This commit is contained in:
parent
ff5f29f661
commit
499e0ceaba
|
@ -19,12 +19,6 @@ build_linux() {
|
||||||
do
|
do
|
||||||
cp "shellcheck" "deploy/shellcheck-$tag.linux-x86_64";
|
cp "shellcheck" "deploy/shellcheck-$tag.linux-x86_64";
|
||||||
done
|
done
|
||||||
|
|
||||||
# Linux Alpine based Docker image
|
|
||||||
name="$DOCKER_BASE-alpine"
|
|
||||||
DOCKER_BUILDS="$DOCKER_BUILDS $name"
|
|
||||||
docker build -f Dockerfile -t "$name:current" --target alpine .
|
|
||||||
docker run "$name:current" sh -c 'shellcheck --version'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
build_aarch64() {
|
build_aarch64() {
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# This script builds and deploys multi-architecture docker images from the
|
||||||
|
# binaries previously built and deployed to GCS by the Travis pipeline.
|
||||||
|
|
||||||
|
function multi_arch_docker::install_docker_buildx() {
|
||||||
|
# Install up-to-date version of docker, with buildx support.
|
||||||
|
local -r docker_apt_repo='https://download.docker.com/linux/ubuntu'
|
||||||
|
curl -fsSL "${docker_apt_repo}/gpg" | sudo apt-key add -
|
||||||
|
local -r os="$(lsb_release -cs)"
|
||||||
|
sudo add-apt-repository "deb [arch=amd64] $docker_apt_repo $os stable"
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
|
||||||
|
|
||||||
|
# Enable docker daemon experimental support (for 'pull --platform').
|
||||||
|
local -r config='/etc/docker/daemon.json'
|
||||||
|
if [[ -e "$config" ]]; then
|
||||||
|
sudo sed -i -e 's/{/{ "experimental": true, /' "$config"
|
||||||
|
else
|
||||||
|
echo '{ "experimental": true }' | sudo tee "$config"
|
||||||
|
fi
|
||||||
|
sudo systemctl restart docker
|
||||||
|
|
||||||
|
# Install QEMU multi-architecture support for docker buildx.
|
||||||
|
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
|
||||||
|
|
||||||
|
# Instantiate docker buildx builder with multi-architecture support.
|
||||||
|
export DOCKER_CLI_EXPERIMENTAL=enabled
|
||||||
|
docker buildx create --name mybuilder
|
||||||
|
docker buildx use mybuilder
|
||||||
|
# Start up buildx and verify that all is OK.
|
||||||
|
docker buildx inspect --bootstrap
|
||||||
|
}
|
||||||
|
|
||||||
|
# Log in to Docker Hub for deployment.
|
||||||
|
function multi_arch_docker::login_to_docker_hub() {
|
||||||
|
echo "$DOCKER_PASSWORD" | docker login -u="$DOCKER_USERNAME" --password-stdin
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run buildx build and push. Passed in arguments augment the command line.
|
||||||
|
function multi_arch_docker::buildx() {
|
||||||
|
mkdir -p /tmp/empty
|
||||||
|
docker buildx build \
|
||||||
|
--platform "${DOCKER_PLATFORMS// /,}" \
|
||||||
|
--push \
|
||||||
|
--progress plain \
|
||||||
|
-f Dockerfile.multi-arch \
|
||||||
|
"$@" \
|
||||||
|
/tmp/empty
|
||||||
|
rmdir /tmp/empty
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build and push plain and alpine docker images for all tags.
|
||||||
|
function multi_arch_docker::build_and_push_all() {
|
||||||
|
for tag in $TAGS; do
|
||||||
|
multi_arch_docker::buildx -t "$DOCKER_BASE:$tag" --build-arg "tag=$tag"
|
||||||
|
multi_arch_docker::buildx -t "$DOCKER_BASE-alpine:$tag" \
|
||||||
|
--build-arg "tag=$tag" --target alpine
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test all pushed docker images.
|
||||||
|
function multi_arch_docker::test_all() {
|
||||||
|
printf '%s\n' "#!/bin/sh" "echo 'hello world'" > myscript
|
||||||
|
|
||||||
|
for platform in $DOCKER_PLATFORMS; do
|
||||||
|
for tag in $TAGS; do
|
||||||
|
for ext in '-alpine' ''; do
|
||||||
|
image="${DOCKER_BASE}${ext}:${tag}"
|
||||||
|
msg="Testing docker image $image on platform $platform"
|
||||||
|
line="${msg//?/=}"
|
||||||
|
printf '\n%s\n%s\n%s\n' "${line}" "${msg}" "${line}"
|
||||||
|
docker pull -q --platform "$platform" "$image"
|
||||||
|
if [ -n "$ext" ]; then
|
||||||
|
echo -n "Image architecture: "
|
||||||
|
docker run --rm --entrypoint /bin/sh "$image" -c 'uname -m'
|
||||||
|
version=$(docker run --rm "$image" shellcheck --version \
|
||||||
|
| grep 'version:')
|
||||||
|
else
|
||||||
|
version=$(docker run --rm "$image" --version | grep 'version:')
|
||||||
|
fi
|
||||||
|
version=${version/#version: /v}
|
||||||
|
echo "shellcheck version: $version"
|
||||||
|
if [[ ! ("$tag" =~ ^(latest|stable)$) && "$tag" != "$version" ]]; then
|
||||||
|
echo "Version mismatch: shellcheck $version tagged as $tag"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -n "$ext" ]; then
|
||||||
|
docker run --rm -v "$PWD:/mnt" -w /mnt "$image" shellcheck myscript
|
||||||
|
else
|
||||||
|
docker run --rm -v "$PWD:/mnt" "$image" myscript
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function multi_arch_docker::main() {
|
||||||
|
export DOCKER_PLATFORMS='linux/amd64'
|
||||||
|
DOCKER_PLATFORMS+=' linux/arm64'
|
||||||
|
DOCKER_PLATFORMS+=' linux/arm/v6'
|
||||||
|
|
||||||
|
multi_arch_docker::install_docker_buildx
|
||||||
|
multi_arch_docker::login_to_docker_hub
|
||||||
|
multi_arch_docker::build_and_push_all
|
||||||
|
set +x
|
||||||
|
multi_arch_docker::test_all
|
||||||
|
}
|
21
.travis.yml
21
.travis.yml
|
@ -6,13 +6,19 @@ services:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- env: BUILD=linux
|
- stage: Test
|
||||||
|
env: BUILD=linux
|
||||||
- env: BUILD=windows
|
- env: BUILD=windows
|
||||||
- env: BUILD=armv6hf
|
- env: BUILD=armv6hf
|
||||||
- env: BUILD=aarch64
|
- env: BUILD=aarch64
|
||||||
- env: BUILD=osx
|
- env: BUILD=osx
|
||||||
os: osx
|
os: osx
|
||||||
|
|
||||||
|
- stage: Deploy docker image
|
||||||
|
script:
|
||||||
|
- source ./.multi_arch_docker
|
||||||
|
- set -ex; multi_arch_docker::main; set +x
|
||||||
|
|
||||||
before_install: |
|
before_install: |
|
||||||
DOCKER_BASE="$DOCKER_USERNAME/shellcheck"
|
DOCKER_BASE="$DOCKER_USERNAME/shellcheck"
|
||||||
DOCKER_BUILDS=""
|
DOCKER_BUILDS=""
|
||||||
|
@ -28,18 +34,6 @@ script:
|
||||||
- set -ex; build_"$BUILD"; set +x;
|
- set -ex; build_"$BUILD"; set +x;
|
||||||
- ./.prepare_deploy
|
- ./.prepare_deploy
|
||||||
|
|
||||||
after_success: |
|
|
||||||
if [ "$BUILD" = "linux" ]; then
|
|
||||||
docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
|
|
||||||
for repo in $DOCKER_BUILDS; do
|
|
||||||
for tag in $TAGS; do
|
|
||||||
echo "Deploying $repo:current as $repo:$tag...";
|
|
||||||
docker tag "$repo:current" "$repo:$tag" || exit 1;
|
|
||||||
docker push "$repo:$tag" || exit 1;
|
|
||||||
done;
|
|
||||||
done;
|
|
||||||
fi
|
|
||||||
|
|
||||||
after_failure: |
|
after_failure: |
|
||||||
id
|
id
|
||||||
pwd
|
pwd
|
||||||
|
@ -57,4 +51,5 @@ deploy:
|
||||||
local_dir: deploy
|
local_dir: deploy
|
||||||
on:
|
on:
|
||||||
repo: koalaman/shellcheck
|
repo: koalaman/shellcheck
|
||||||
|
condition: $TRAVIS_BUILD_STAGE_NAME = Test
|
||||||
all_branches: true
|
all_branches: true
|
||||||
|
|
|
@ -21,13 +21,6 @@ RUN cabal build Paths_ShellCheck && \
|
||||||
RUN mkdir -p /out/bin && \
|
RUN mkdir -p /out/bin && \
|
||||||
cp shellcheck /out/bin/
|
cp shellcheck /out/bin/
|
||||||
|
|
||||||
# Resulting Alpine image
|
|
||||||
FROM alpine:latest AS alpine
|
|
||||||
LABEL maintainer="Vidar Holen <vidar@vidarholen.net>"
|
|
||||||
COPY --from=build /out /
|
|
||||||
|
|
||||||
# DELETE-MARKER (Remove everything below to keep the alpine image)
|
|
||||||
|
|
||||||
# Resulting ShellCheck image
|
# Resulting ShellCheck image
|
||||||
FROM scratch
|
FROM scratch
|
||||||
LABEL maintainer="Vidar Holen <vidar@vidarholen.net>"
|
LABEL maintainer="Vidar Holen <vidar@vidarholen.net>"
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Alpine image
|
||||||
|
FROM alpine:latest AS alpine
|
||||||
|
LABEL maintainer="Vidar Holen <vidar@vidarholen.net>"
|
||||||
|
ARG tag
|
||||||
|
|
||||||
|
# Put the right binary for each architecture into place for the
|
||||||
|
# multi-architecture docker image.
|
||||||
|
RUN set -x; \
|
||||||
|
arch="$(uname -m)"; \
|
||||||
|
echo "arch is $arch"; \
|
||||||
|
if [ "${arch}" = 'armv7l' ]; then \
|
||||||
|
arch='armv6hf'; \
|
||||||
|
fi; \
|
||||||
|
url_base='https://shellcheck.storage.googleapis.com/'; \
|
||||||
|
tar_file="shellcheck-${tag}.linux.${arch}.tar.xz"; \
|
||||||
|
wget "${url_base}${tar_file}" -O - | tar xJf -; \
|
||||||
|
mv "shellcheck-${tag}/shellcheck" /bin/; \
|
||||||
|
rm -rf "shellcheck-${tag}"; \
|
||||||
|
ls -laF /bin/shellcheck
|
||||||
|
|
||||||
|
# ShellCheck image
|
||||||
|
FROM scratch
|
||||||
|
LABEL maintainer="Vidar Holen <vidar@vidarholen.net>"
|
||||||
|
WORKDIR /mnt
|
||||||
|
COPY --from=alpine /bin/shellcheck /bin/
|
||||||
|
ENTRYPOINT ["/bin/shellcheck"]
|
Loading…
Reference in New Issue