Skip to content

Instantly share code, notes, and snippets.

@shanduur
Last active March 10, 2023 19:41
Show Gist options
  • Save shanduur/1aa06b85e2f6f061393a05ed940da4e5 to your computer and use it in GitHub Desktop.
Save shanduur/1aa06b85e2f6f061393a05ed940da4e5 to your computer and use it in GitHub Desktop.
#!/bin/bash -e
echo 'This script is used to build and push multi-arch images to a container registry.'
echo ''
echo 'The script is intended to be used in a CI/CD pipeline.'
echo ''
echo 'The following variables can be set:'
echo ''
echo '| variable | value | default value | required |'
echo '|----------------|---------------------------------------------------|-------------------------------|-----------------------------|'
echo '| EXECUTOR | podman or docker | podman or docker if available | optional |'
echo '| REGISTRY | docker.io, quay.io, ... | docker.io | optional |'
echo '| REPOSITORY | e.g. example-project | not set | required |'
echo '| IMAGE_NAME | e.g. example | not set | required |'
echo '| IMAGE_TAG | e.g. v1.0.0 | latest commit sha | optional |'
echo '| GIT_SHA | e.g. 1234567890abcdef | latest commit sha | required, if git is missing |'
echo '| CONTEXT | e.g. ./example | . | optional |'
echo '| CONTAINERFILE | e.g. ./example/Dockerfile | Dockerfile | optional |'
echo '| PUSH | if set, the image will be pushed to the registry | not set | optional |'
echo '| ROBOT_USERNAME | username for the registry | not set | required, if PUSH is set |'
echo '| ROBOT_PASSWORD | password for the registry | not set | required, if PUSH is set |'
echo '| DEBUG | if set, the script will be executed in debug mode | not set | optional |'
echo ''
echo 'All arguments after the first one will be passed to the build command as build-args.'
echo 'They should be in the format: ARG=VALUE'
echo ''
echo 'example: ./build.sh ARG1=VALUE1 ARG2=VALUE2'
echo ''
echo "starting build"
# Validate if required variables are set
if [[ -z "${EXECUTOR}" ]]; then
echo "EXECUTOR not set"
if which podman ; then
echo "using podman as EXECUTOR"
EXECUTOR=$(which podman)
elif which docker ; then
echo "using docker as EXECUTOR"
EXECUTOR=$(which docker)
else
echo "no executor found on the system"
exit 1
fi
fi
if [[ -n "${DEBUG}" ]]; then
set -x
if [[ "${EXECUTOR}" == "podman" ]]; then
EXTRA_FLAGS=(--log-level=debug)
fi
fi
if [[ -z "${GIT_SHA}" ]]; then
GIT_SHA=$(git rev-parse HEAD)
fi
if [[ -z "${REGISTRY}" ]]; then
echo "REGISTRY not set"
echo "using docker.io"
REGISTRY='docker.io'
fi
if [[ -z "${REPOSITORY}" ]]; then
echo "REPOSITORY not set"
exit 1
fi
if [[ -z "${IMAGE_NAME}" ]]; then
echo "IMAGE_NAME not set"
exit 1
fi
# combine variables to easier refer to the image
IMAGE="${REGISTRY}"/"${REPOSITORY}"/"${IMAGE_NAME}"
if [[ -z "${IMAGE_TAG}" ]]; then
echo "IMAGE_TAG not set"
echo "tagging '${GIT_SHA}'"
IMAGE_TAG="${GIT_SHA}"
else
# validate if the tag is correct SEMVER without additional info
if [[ "${IMAGE_TAG}" =~ ^v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$ ]]; then
LATEST=1
fi
fi
if [[ -z "${CONTEXT}" ]]; then
echo "CONTEXT not set"
echo "using '.'"
CONTEXT='.'
fi
if [[ -z "${CONTAINERFILE}" ]]; then
echo "CONTAINERFILE not set"
echo "using 'Dockerfile'"
CONTAINERFILE='Dockerfile'
fi
BUILD_ARGS=()
for ARG in "${@}"; do
# add args to list
BUILD_ARGS+=("--build-arg=${ARG}")
done
for ARCH in amd64 arm64; do
"${EXECUTOR}" build \
--tag="${IMAGE}":"${GIT_SHA}"-"${ARCH}" \
--platform="linux/${ARCH}" \
--file "${CONTAINERFILE}" \
"${BUILD_ARGS[@]}" \
--pull \
--rm \
"${EXTRA_FLAGS[@]}" \
"${CONTEXT}"
done
if [[ -n "${PUSH}" ]]; then
# Login into the container registry:
"${EXECUTOR}" login \
"${EXTRA_FLAGS[@]}" \
--username "${ROBOT_USERNAME}" \
--password "${ROBOT_PASSWORD}" \
"${REGISTRY}"
# Set manifest name
export MANIFEST_NAME="${IMAGE}":"${IMAGE_TAG}"
MANIFESTS=()
for ARCH in amd64 arm64; do
MANIFESTS+=("${IMAGE}":"${GIT_SHA}"-"${ARCH}")
done
# Create a multi-architecture manifest
if ! "${EXECUTOR}" manifest create --amend "${MANIFEST_NAME}" "${MANIFESTS[@]}"; then
echo "creation of manifest failed"
exit 1
fi
for ARCH in amd64 arm64; do
"${EXECUTOR}" manifest add \
"${EXTRA_FLAGS[@]}" \
"${MANIFEST_NAME}" \
"${IMAGE}":"${GIT_SHA}"-"${ARCH}"
done
# Push the full manifest, with all CPU Architectures, with IMAGE_TAG tag
"${EXECUTOR}" manifest push \
--all \
"${EXTRA_FLAGS[@]}" \
"${MANIFEST_NAME}" \
docker://"${IMAGE}":"${IMAGE_TAG}";
if [[ -n "${LATEST}" ]]; then
# Push the full manifest, with all CPU Architectures, with latest tag
"${EXECUTOR}" manifest push \
--all \
"${EXTRA_FLAGS[@]}" \
"${MANIFEST_NAME}" \
docker://"${IMAGE}":latest;
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment