196 lines
5.8 KiB
Bash
Executable File
196 lines
5.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
DOCKERFILE="${DOCKERFILE:-$REPO_ROOT/docker/validator-runtime.Dockerfile}"
|
|
TARGET_ARCH=""
|
|
IMAGE_TAG=""
|
|
OUT_DIR="${OUT_DIR:-$REPO_ROOT/docker-out}"
|
|
ALLOW_DIRTY=0
|
|
SAVE_IMAGE=1
|
|
LOAD_IMAGE=1
|
|
INSTALL_BINFMT=1
|
|
BUILDER_IMAGE="${BUILDER_IMAGE:-rust:1-bookworm}"
|
|
RUNTIME_IMAGE="${RUNTIME_IMAGE:-debian:bookworm-slim}"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage:
|
|
scripts/docker/build_image.sh --arch amd64|arm64 [options]
|
|
|
|
Options:
|
|
--arch <arch> Target architecture (required)
|
|
--image <tag> Image tag (default: panda-rpki-validator:<version>-<arch>)
|
|
--out-dir <path> Image archive/metadata directory (default: docker-out)
|
|
--dockerfile <path> Dockerfile path
|
|
--builder-image <tag> Builder base image (pin for a supported release)
|
|
--runtime-image <tag> Runtime base image (pin for a supported release)
|
|
--allow-dirty Permit a local build and mark tag/metadata dirty
|
|
--no-binfmt Do not install binfmt/qemu for a cross-architecture build
|
|
--no-save Do not write docker save archive
|
|
--no-load Build without loading the image into the local daemon
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
normalize_arch() {
|
|
case "$1" in
|
|
amd64|x86_64) printf '%s\n' amd64 ;;
|
|
arm64|aarch64) printf '%s\n' arm64 ;;
|
|
*) return 1 ;;
|
|
esac
|
|
}
|
|
|
|
safe_name() {
|
|
printf '%s' "$1" | tr '/:' '--'
|
|
}
|
|
|
|
while [[ "$#" -gt 0 ]]; do
|
|
case "$1" in
|
|
--arch)
|
|
TARGET_ARCH="$(normalize_arch "$2")" || { echo "unsupported architecture: $2" >&2; exit 2; }
|
|
shift 2
|
|
;;
|
|
--image)
|
|
IMAGE_TAG="$2"
|
|
shift 2
|
|
;;
|
|
--out-dir)
|
|
OUT_DIR="$2"
|
|
shift 2
|
|
;;
|
|
--dockerfile)
|
|
DOCKERFILE="$2"
|
|
shift 2
|
|
;;
|
|
--builder-image)
|
|
BUILDER_IMAGE="$2"
|
|
shift 2
|
|
;;
|
|
--runtime-image)
|
|
RUNTIME_IMAGE="$2"
|
|
shift 2
|
|
;;
|
|
--allow-dirty)
|
|
ALLOW_DIRTY=1
|
|
shift
|
|
;;
|
|
--no-binfmt)
|
|
INSTALL_BINFMT=0
|
|
shift
|
|
;;
|
|
--no-save)
|
|
SAVE_IMAGE=0
|
|
shift
|
|
;;
|
|
--no-load)
|
|
LOAD_IMAGE=0
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "unknown option: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
[[ -n "$TARGET_ARCH" ]] || { echo "--arch is required" >&2; usage >&2; exit 2; }
|
|
[[ -f "$DOCKERFILE" ]] || { echo "missing Dockerfile: $DOCKERFILE" >&2; exit 2; }
|
|
command -v docker >/dev/null 2>&1 || { echo "missing required command: docker" >&2; exit 2; }
|
|
|
|
if SOURCE_COMMIT_FULL="$(git -C "$REPO_ROOT" rev-parse --verify HEAD 2>/dev/null)"; then
|
|
:
|
|
else
|
|
SOURCE_COMMIT_FULL=unknown
|
|
fi
|
|
if SOURCE_COMMIT_SHORT="$(git -C "$REPO_ROOT" rev-parse --short=8 --verify HEAD 2>/dev/null)"; then
|
|
:
|
|
else
|
|
SOURCE_COMMIT_SHORT=unknown
|
|
fi
|
|
SOURCE_DIRTY=false
|
|
if [[ -n "$(git -C "$REPO_ROOT" status --short 2>/dev/null)" || "$SOURCE_COMMIT_FULL" == unknown ]]; then
|
|
SOURCE_DIRTY=true
|
|
fi
|
|
if [[ "$SOURCE_DIRTY" == true && "$ALLOW_DIRTY" != 1 ]]; then
|
|
echo "refusing dirty tree; pass --allow-dirty for a local development build" >&2
|
|
exit 2
|
|
fi
|
|
|
|
VERSION="$(awk -F'"' '$1 == "version = " { print $2; exit }' "$REPO_ROOT/crates/panda-rpki-validator/Cargo.toml")"
|
|
REVISION="$VERSION"
|
|
if [[ "$SOURCE_DIRTY" == true ]]; then
|
|
REVISION="${REVISION}-dirty"
|
|
fi
|
|
if [[ -z "$IMAGE_TAG" ]]; then
|
|
IMAGE_TAG="panda-rpki-validator:${REVISION}-${TARGET_ARCH}"
|
|
fi
|
|
|
|
mkdir -p "$OUT_DIR"
|
|
TARGET_PLATFORM="linux/$TARGET_ARCH"
|
|
HOST_ARCH=""
|
|
case "$(uname -m)" in
|
|
x86_64|amd64) HOST_ARCH=amd64 ;;
|
|
aarch64|arm64) HOST_ARCH=arm64 ;;
|
|
*) echo "unsupported host architecture: $(uname -m)" >&2; exit 2 ;;
|
|
esac
|
|
if [[ "$HOST_ARCH" != "$TARGET_ARCH" && "$INSTALL_BINFMT" == 1 ]]; then
|
|
echo "installing binfmt/qemu for $TARGET_ARCH"
|
|
docker run --rm --privileged tonistiigi/binfmt --install "$TARGET_ARCH"
|
|
fi
|
|
METADATA_PATH="$OUT_DIR/$(safe_name "$IMAGE_TAG").build.env"
|
|
IMAGE_TAR="$OUT_DIR/$(safe_name "$IMAGE_TAG").tar.gz"
|
|
|
|
build_args=(
|
|
--platform "$TARGET_PLATFORM"
|
|
--file "$DOCKERFILE"
|
|
--build-arg "BUILDER_IMAGE=$BUILDER_IMAGE"
|
|
--build-arg "RUNTIME_IMAGE=$RUNTIME_IMAGE"
|
|
--build-arg "SOURCE_COMMIT=$SOURCE_COMMIT_FULL"
|
|
--build-arg "SOURCE_DIRTY=$SOURCE_DIRTY"
|
|
--build-arg "BUILD_TIMESTAMP_UTC=$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
--tag "$IMAGE_TAG"
|
|
)
|
|
if [[ "$LOAD_IMAGE" == 1 ]]; then
|
|
docker buildx build --load "${build_args[@]}" "$REPO_ROOT"
|
|
else
|
|
docker buildx build "${build_args[@]}" --output "type=oci,dest=$OUT_DIR/$(safe_name "$IMAGE_TAG").oci.tar" "$REPO_ROOT"
|
|
fi
|
|
|
|
if [[ "$SAVE_IMAGE" == 1 && "$LOAD_IMAGE" == 1 ]]; then
|
|
docker save "$IMAGE_TAG" | gzip -c > "$IMAGE_TAR"
|
|
fi
|
|
|
|
IMAGE_DIGEST=""
|
|
IMAGE_ID=""
|
|
if [[ "$LOAD_IMAGE" == 1 ]]; then
|
|
IMAGE_DIGEST="$(docker image inspect --format '{{index .RepoDigests 0}}' "$IMAGE_TAG" 2>/dev/null || true)"
|
|
IMAGE_ID="$(docker image inspect --format '{{.Id}}' "$IMAGE_TAG")"
|
|
fi
|
|
BUILD_TIMESTAMP_UTC="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
{
|
|
printf 'image=%s\n' "$IMAGE_TAG"
|
|
printf 'platform=%s\n' "$TARGET_PLATFORM"
|
|
printf 'arch=%s\n' "$TARGET_ARCH"
|
|
printf 'host_arch=%s\n' "$HOST_ARCH"
|
|
printf 'binfmt_installed=%s\n' "$([[ "$HOST_ARCH" != "$TARGET_ARCH" && "$INSTALL_BINFMT" == 1 ]] && printf true || printf false)"
|
|
printf 'source_commit=%s\n' "$SOURCE_COMMIT_FULL"
|
|
printf 'source_commit_short=%s\n' "$SOURCE_COMMIT_SHORT"
|
|
printf 'source_dirty=%s\n' "$SOURCE_DIRTY"
|
|
printf 'builder_image=%s\n' "$BUILDER_IMAGE"
|
|
printf 'runtime_image=%s\n' "$RUNTIME_IMAGE"
|
|
printf 'image_digest=%s\n' "$IMAGE_DIGEST"
|
|
printf 'image_id=%s\n' "$IMAGE_ID"
|
|
printf 'archive=%s\n' "$IMAGE_TAR"
|
|
printf 'archive_sha256=%s\n' "$(sha256sum "$IMAGE_TAR" 2>/dev/null | awk '{print $1}' || true)"
|
|
printf 'built_at_utc=%s\n' "$BUILD_TIMESTAMP_UTC"
|
|
} > "$METADATA_PATH"
|
|
|
|
echo "built image=$IMAGE_TAG platform=$TARGET_PLATFORM archive=$IMAGE_TAR"
|