diff --git a/Makefile b/Makefile index bff28459..fb8b8e72 100644 --- a/Makefile +++ b/Makefile @@ -2,25 +2,69 @@ TOP := $(dir $(abspath $(firstword $(MAKEFILE_LIST)))) HOST_ARCH ?= $(shell uname -m) DOCKER_ARCH ?= $(lastword $(subst :, ,$(filter $(HOST_ARCH):%,x86_64:amd64 aarch64:arm64))) +DOCKER_ALT_ARCH ?= $(lastword $(subst :, ,$(filter $(HOST_ARCH):%,x86_64:arm64 aarch64:amd64))) UPSTREAM_SOURCE_FALLBACK ?= false VERSION := $(shell cat $(TOP)VERSION) SHORT_SHA := $(shell git rev-parse --short=8 HEAD) -IMAGE_NAME ?= bottlerocket-sdk:$(VERSION)-$(SHORT_SHA)-$(DOCKER_ARCH) +REGISTRY ?= +REPOSITORY ?= bottlerocket-sdk +IMAGE_NAME ?= $(REPOSITORY):$(VERSION)-$(SHORT_SHA)-$(DOCKER_ARCH) +IMAGE_ALT_NAME ?= $(REPOSITORY):$(VERSION)-$(SHORT_SHA)-$(DOCKER_ALT_ARCH) +MANIFEST ?= $(REPOSITORY):$(VERSION) -all: sdk +BUILDX_BUILDER ?= sdk-builder -sdk: - @DOCKER_BUILDKIT=1 docker build . \ - --tag $(IMAGE_NAME) \ - --target sdk-golden \ - --build-arg HOST_ARCH=$(HOST_ARCH) \ - --build-arg UPSTREAM_SOURCE_FALLBACK=$(UPSTREAM_SOURCE_FALLBACK) +BUILDX_BUILD_ARGS = $\ + --build-arg HOST_ARCH=$(HOST_ARCH) $\ + --build-arg UPSTREAM_SOURCE_FALLBACK=$(UPSTREAM_SOURCE_FALLBACK) $\ + --target sdk-golden $\ + --provenance=false $\ + --sbom=false $\ + --builder $(BUILDX_BUILDER) -publish: +BUILDX_LOAD_ARGS = $\ + --tag $(IMAGE_NAME) \ + --load + +BUILDX_PUSH_ARGS = $\ + --output $\ + type=registry,name=$(REGISTRY)/$(IMAGE_NAME),$\ + compression=zstd,compression-level=22,force-compression=true,$\ + oci-mediatypes=true,platform=linux/$(DOCKER_ARCH) + +all: build + +builder: + @docker buildx create \ + --name $(BUILDX_BUILDER) \ + --driver docker-container \ + --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=-1 \ + --driver-opt env.BUILDKIT_STEP_LOG_MAX_SPEED=-1 \ + --node $(BUILDX_BUILDER)0 + +build: builder + @docker buildx build . \ + $(BUILDX_BUILD_ARGS) \ + $(BUILDX_LOAD_ARGS) + +build-push: builder @test $${REGISTRY?not set!} - @test $${REPOSITORY?not set!} - $(TOP)publish-sdk --registry=$(REGISTRY) --repository=$(REPOSITORY) --tag=$(VERSION) --short-sha=$(SHORT_SHA) + @docker buildx build . \ + $(BUILDX_BUILD_ARGS) \ + $(BUILDX_PUSH_ARGS) + +publish: build-push + @if docker buildx imagetools inspect $(REGISTRY)/$(IMAGE_ALT_NAME) >/dev/null 2>&1 ; then \ + docker buildx imagetools create \ + --tag $(REGISTRY)/$(MANIFEST) \ + $(REGISTRY)/$(IMAGE_NAME) \ + $(REGISTRY)/$(IMAGE_ALT_NAME) ; \ + else \ + docker buildx imagetools create \ + --tag $(REGISTRY)/$(MANIFEST) \ + $(REGISTRY)/$(IMAGE_NAME) ; \ + fi -.PHONY: all sdk publish +.PHONY: all builder build build-push publish diff --git a/publish-sdk b/publish-sdk deleted file mode 100755 index 5cfe31e7..00000000 --- a/publish-sdk +++ /dev/null @@ -1,143 +0,0 @@ -#!/bin/bash - -set -e -o pipefail -shopt -qs failglob - -SKIP_MANIFEST="${SKIP_MANIFEST:-'false'}" -ONLY_MANIFEST="${ONLY_MANIFEST:-'false'}" - -for opt in "$@"; do - optarg="$(expr "${opt}" : '[^=]*=\(.*\)')" - case "${opt}" in - --tag=*) TAG="${optarg}" ;; - --registry=*) REGISTRY="${optarg}" ;; - --repository=*) REPOSITORY="${optarg}" ;; - --short-sha=*) SHORT_SHA="${optarg,,}" ;; - --skip-manifest=*) SKIP_MANIFEST="${optarg,,}" ;; - --only-manifest=*) ONLY_MANIFEST="${optarg,,}" ;; - esac -done - -for required_arg in TAG REGISTRY REPOSITORY SHORT_SHA; do - [ -z "${!required_arg}" ] && echo "${required_arg} not set!" >&2 && exit 1 -done - -ECR_OPERATIONS=0 -MIN_ECR_OPERATIONS=1 -if [[ "${SKIP_MANIFEST}" == "true" ]] && [[ "${ONLY_MANIFEST}" == "true" ]] ; then - echo "nothing to do" >&2 && exit 2 -elif [[ "${SKIP_MANIFEST}" == "true" ]] || [[ "${ONLY_MANIFEST}" == "true" ]] ; then - ((--MIN_ECR_OPERATIONS)) -fi - -update_image() { - set -u - - local local_image="${1:?}" - local remote_image="${2:?}" - - local host_arch - host_arch="$(uname -m)" - - local docker_arch - case "${host_arch}" in - x86_64) docker_arch="amd64" ;; - aarch64) docker_arch="arm64" ;; - *) echo "unknown host arch ${host_arch}" >&2 && exit 1 ;; - esac - - local alt_arch - case "${host_arch}" in - x86_64) alt_arch="aarch64" ;; - aarch64) alt_arch="x86_64" ;; - *) echo "unknown host arch ${host_arch}" >&2 && exit 1 ;; - esac - - local alt_docker_arch - case "${docker_arch}" in - amd64) alt_docker_arch="arm64" ;; - arm64) alt_docker_arch="amd64" ;; - esac - - local local_host_arch_image="${local_image}-${SHORT_SHA}-${docker_arch}" - local remote_host_arch_image="${remote_image}-${SHORT_SHA}-${docker_arch}" - local remote_alt_arch_image="${remote_image}-${SHORT_SHA}-${alt_docker_arch}" - - if [[ "${ONLY_MANIFEST}" != "true" ]]; then - if ! docker image inspect "${local_host_arch_image}" >/dev/null 2>&1 ; then - echo "did not find ${local_host_arch_image}, skipping it ..." >&2 - return - fi - - if ! docker tag "${local_host_arch_image}" "${remote_host_arch_image}" ; then - echo "failed to tag ${remote_host_arch_image}" >&2 && exit 1 - fi - - # push the image, if it exists locally - if ! docker push "${remote_host_arch_image}" ; then - echo "failed to push ${remote_host_arch_image}" >&2 && exit 1 - fi - ((++ECR_OPERATIONS)) - fi - - # return early to skip manifest generation steps - [[ "${SKIP_MANIFEST}" == "true" ]] && return - - # clean up any cached local copy of the manifest - manifest_dir="${HOME}/.docker/manifests" - mkdir -p "${manifest_dir}" - find "${manifest_dir}" -type f -delete - find "${manifest_dir}" -mindepth 1 -type d -delete - - if ! docker manifest inspect "${remote_alt_arch_image}" >/dev/null 2>&1 ; then - echo "could not find ${remote_alt_arch_image}, skipping manifest creation" >&2 - return - fi - - local image="${remote_image##*/}" - local repo="${image%:*}" - - # clean up any remote (ECR) copy of the manifest - if [[ "${REGISTRY}" =~ ^public\.ecr\.aws\/ ]]; then - aws ecr-public batch-delete-image \ - --repository-name "${repo}" \ - --image-ids imageTag="${TAG}" \ - --region "us-east-1" - elif [[ "${REGISTRY}" =~ ^[0-9]+\.dkr\.ecr\.([a-z0-9-]+)\.amazonaws\.com$ ]]; then - aws ecr batch-delete-image \ - --repository-name "${repo}" \ - --image-ids imageTag="${TAG}" \ - --region "${BASH_REMATCH[1]}" - fi - - if ! docker manifest create "${remote_image}" \ - "${remote_host_arch_image}" "${remote_alt_arch_image}" ; then - echo "failed to create manifest ${remote_image}" >&2 && exit 1 - fi - - if ! docker manifest annotate "${remote_image}" \ - "${remote_host_arch_image}" --arch "${docker_arch}" ; then - echo "failed to annotate manifest ${remote_image} with ${remote_host_arch_image}" >&2 && exit 1 - fi - - if ! docker manifest annotate "${remote_image}" \ - "${remote_alt_arch_image}" --arch "${alt_docker_arch}" ; then - echo "failed to annotate manifest ${remote_image} with ${remote_alt_arch_image}" >&2 && exit 1 - fi - - # push the manifest and remove the local cache - if ! docker manifest push --purge "${remote_image}" ; then - echo "failed to push ${remote_image}" >&2 && exit 1 - fi - ((++ECR_OPERATIONS)) -} - -local_sdk="bottlerocket-sdk:${TAG}" -remote_sdk="${REGISTRY}/${REPOSITORY}:${TAG}" -update_image "${local_sdk}" "${remote_sdk}" - -if [[ ${ECR_OPERATIONS} -lt ${MIN_ECR_OPERATIONS} ]]; then - echo "no containers or manifests were pushed" >&2 && exit 1 -else - exit 0 -fi