From cacc9f78f8f1aaec1fefc03f5db8c084f3ad7c40 Mon Sep 17 00:00:00 2001 From: Ashok Pariya Date: Wed, 11 Dec 2024 11:20:17 +0000 Subject: [PATCH 1/2] Modify Dockerfile to support multi-platform builds. These changes enable building kubemacpool container images for multiple platforms (amd64, s390x, arm64) from a single Dockerfile. Signed-off-by: Ashok Pariya ashok.pariya@ibm.com --- build/Dockerfile | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/build/Dockerfile b/build/Dockerfile index e6fc3266d..0877d5f99 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,4 +1,31 @@ +ARG BUILD_ARCH=amd64 +FROM --platform=linux/${BUILD_ARCH} quay.io/centos/centos:stream9 AS builder +ARG TARGETOS +ARG TARGETARCH +ENV TARGETOS=${TARGETOS:-linux} +ENV TARGETARCH=${TARGETARCH:-amd64} + +ARG BUILDOS +ARG BUILDARCH +ENV BUILDOS=${BUILDOS:-linux} +ENV BUILDARCH=${BUILDARCH:-amd64} + +WORKDIR /go/src/kubemacpool +RUN dnf install -y wget && dnf clean all +COPY go.mod . +COPY go.sum . +RUN GO_VERSION=$(sed -En 's/^go +(.*)$/\1/p' go.mod) && \ + wget https://dl.google.com/go/go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz && \ + tar -C /usr/local -xzf go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz && \ + rm go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz + +ENV PATH=$PATH:/usr/local/go/bin +RUN go mod download +COPY . . + +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -o build/_output/bin/manager github.com/k8snetworkplumbingwg/kubemacpool/cmd/manager + # Copy the controller-manager into a thin image -FROM registry.access.redhat.com/ubi9/ubi-minimal -COPY _output/bin/manager / +FROM --platform=linux/${TARGETARCH} registry.access.redhat.com/ubi9/ubi-minimal +COPY --from=builder /go/src/kubemacpool/build/_output/bin/manager / ENTRYPOINT ["/manager"] From 2c03979f184ca56534931406c3cd3d09ee54b99e Mon Sep 17 00:00:00 2001 From: Ashok Pariya Date: Wed, 11 Dec 2024 11:25:20 +0000 Subject: [PATCH 2/2] Add Multi-Platform support for Kubemacpool Image using make command. These changes provide multi-platform build support for the Kubemacpool CNI, enabling builds for Docker and Podman container runtimes. Signed-off-by: Ashok Pariya ashok.pariya@ibm.com --- Makefile | 33 +++++++++++------ build/Dockerfile | 2 +- hack/build-kubemacpool-docker.sh | 28 +++++++++++++++ hack/build-kubemacpool-podman.sh | 25 +++++++++++++ hack/build-multiarch-kubemacpool.sh | 19 ++++++++++ hack/init-buildx.sh | 56 +++++++++++++++++++++++++++++ hack/install-go.sh | 3 +- 7 files changed, 154 insertions(+), 12 deletions(-) create mode 100755 hack/build-kubemacpool-docker.sh create mode 100755 hack/build-kubemacpool-podman.sh create mode 100755 hack/build-multiarch-kubemacpool.sh create mode 100755 hack/init-buildx.sh diff --git a/Makefile b/Makefile index 8b16fc06d..d6469a401 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,19 @@ IMAGE_GIT_TAG ?= $(shell git describe --abbrev=8 --tags) IMG ?= $(REPO)/kubemacpool OCI_BIN ?= $(shell if podman ps >/dev/null 2>&1; then echo podman; elif docker ps >/dev/null 2>&1; then echo docker; fi) TLS_SETTING := $(if $(filter $(OCI_BIN),podman),--tls-verify=false,) +PLATFORM_LIST ?= linux/amd64,linux/s390x,linux/arm64 +ARCH := $(shell uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') +PLATFORMS ?= linux/${ARCH} +PLATFORMS := $(if $(filter all,$(PLATFORMS)),$(PLATFORM_LIST),$(PLATFORMS)) +# Define the platforms for building a multi-platform image. +# Example: +# PLATFORMS ?= linux/amd64,linux/arm64,linux/s390x +# Alternatively, you can set the PLATFORMS variable using: +# export PLATFORMS=linux/arm64,linux/s390x,linux/amd64 +# or export PLATFORMS=all to automatically include all supported platforms. +DOCKER_BUILDER ?= kubemacpool-docker-builder +KUBEMACPOOL_IMAGE_TAGGED := ${REGISTRY}/${IMG}:${IMAGE_TAG} +KUBEMACPOOL_IMAGE_GIT_TAGGED := ${REGISTRY}/${IMG}:${IMAGE_GIT_TAG} BIN_DIR = $(CURDIR)/build/_output/bin/ @@ -83,24 +96,25 @@ generate: generate-go generate-deploy generate-test generate-external check: $(GO) ./hack/check.sh -manager: $(GO) - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GO) build -o $(BIN_DIR)/manager github.com/k8snetworkplumbingwg/kubemacpool/cmd/manager - # Build the docker image -container: manager - $(OCI_BIN) build build/ -t ${REGISTRY}/${IMG}:${IMAGE_TAG} +container: + ./hack/build-multiarch-kubemacpool.sh $(ARCH) $(PLATFORMS) $(KUBEMACPOOL_IMAGE_TAGGED) $(KUBEMACPOOL_IMAGE_GIT_TAGGED) $(DOCKER_BUILDER) $(OCI_BIN) $(REGISTRY) # Push the docker image docker-push: - $(OCI_BIN) push ${TLS_SETTING} ${REGISTRY}/${IMG}:${IMAGE_TAG} + @if [ "$(OCI_BIN)" = "podman" ]; then \ + podman manifest push ${TLS_SETTING} ${REGISTRY}/${IMG}:${IMAGE_TAG} ${REGISTRY}/${IMG}:${IMAGE_TAG}; \ + fi @if [[ "${REGISTRY}" == localhost* || "${REGISTRY}" == 127.0.0.1* ]]; then \ echo "Local registry detected (${REGISTRY}). Skipping IMAGE_GIT_TAG handling."; \ else \ if skopeo inspect docker://${REGISTRY}/${IMG}:${IMAGE_GIT_TAG} >/dev/null 2>&1; then \ - echo "Tag '${IMAGE_GIT_TAG}' already exists. Skipping tagging and push."; \ + echo "Tag '${IMAGE_GIT_TAG}' already exists. Skipping tagging and push."; \ elif skopeo inspect docker://${REGISTRY}/${IMG}:${IMAGE_GIT_TAG} 2>&1 | grep -q "manifest unknown"; then \ - $(OCI_BIN) tag ${REGISTRY}/${IMG}:${IMAGE_TAG} ${REGISTRY}/${IMG}:${IMAGE_GIT_TAG}; \ - $(OCI_BIN) push ${TLS_SETTING} ${REGISTRY}/${IMG}:${IMAGE_GIT_TAG}; \ + if [ "$(OCI_BIN)" = "podman" ]; then \ + podman tag ${REGISTRY}/${IMG}:${IMAGE_TAG} ${REGISTRY}/${IMG}:${IMAGE_GIT_TAG}; \ + podman manifest push ${TLS_SETTING} ${REGISTRY}/${IMG}:${IMAGE_GIT_TAG} ${REGISTRY}/${IMG}:${IMAGE_GIT_TAG}; \ + fi \ else \ echo "Error checking for tag '${IMAGE_GIT_TAG}'. Aborting to avoid potential overwrite."; \ exit 1; \ @@ -139,7 +153,6 @@ vendor: $(GO) fmt \ vet \ check \ - manager \ container \ push \ cluster-up \ diff --git a/build/Dockerfile b/build/Dockerfile index 0877d5f99..9a74f5134 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -15,7 +15,7 @@ RUN dnf install -y wget && dnf clean all COPY go.mod . COPY go.sum . RUN GO_VERSION=$(sed -En 's/^go +(.*)$/\1/p' go.mod) && \ - wget https://dl.google.com/go/go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz && \ + wget -q https://dl.google.com/go/go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz && \ tar -C /usr/local -xzf go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz && \ rm go${GO_VERSION}.${BUILDOS}-${BUILDARCH}.tar.gz diff --git a/hack/build-kubemacpool-docker.sh b/hack/build-kubemacpool-docker.sh new file mode 100755 index 000000000..f4fb23626 --- /dev/null +++ b/hack/build-kubemacpool-docker.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +if [ -z "$ARCH" ] || [ -z "$PLATFORMS" ] || [ -z "$KUBEMACPOOL_IMAGE_TAGGED" ] || [ -z "$KUBEMACPOOL_IMAGE_GIT_TAGGED" ] || [ -z "$DOCKER_BUILDER" ] || [ -z "$REGISTRY" ]; then + echo "Error: ARCH, PLATFORMS, KUBEMACPOOL_IMAGE_TAGGED, KUBEMACPOOL_IMAGE_GIT_TAGGED and DOCKER_BUILDER must be set." + exit 1 +fi + +IFS=',' read -r -a PLATFORM_LIST <<< "$PLATFORMS" + +if [[ "${REGISTRY}" == localhost* || "${REGISTRY}" == 127.0.0.1* ]]; then + echo "Local registry detected (${REGISTRY}). Skipping $KUBEMACPOOL_IMAGE_GIT_TAGGED handling."; + BUILD_ARGS="--build-arg BUILD_ARCH=$ARCH -f build/Dockerfile -t $KUBEMACPOOL_IMAGE_TAGGED . --push" +else + if skopeo inspect docker://${KUBEMACPOOL_IMAGE_GIT_TAGGED} >/dev/null 2>&1; then + echo "Tag '${KUBEMACPOOL_IMAGE_GIT_TAGGED}' already exists in the registry. Skipping tagging with ${KUBEMACPOOL_IMAGE_GIT_TAGGED}." + BUILD_ARGS="--build-arg BUILD_ARCH=$ARCH -f build/Dockerfile -t $KUBEMACPOOL_IMAGE_TAGGED . --push" + else + BUILD_ARGS="--build-arg BUILD_ARCH=$ARCH -f build/Dockerfile -t $KUBEMACPOOL_IMAGE_TAGGED -t $KUBEMACPOOL_IMAGE_GIT_TAGGED . --push" + fi +fi + +if [ ${#PLATFORM_LIST[@]} -eq 1 ]; then + docker build --platform "$PLATFORMS" $BUILD_ARGS +else + ./hack/init-buildx.sh "$DOCKER_BUILDER" + docker buildx build --platform "$PLATFORMS" $BUILD_ARGS + docker buildx rm "$DOCKER_BUILDER" 2>/dev/null || echo "Builder ${DOCKER_BUILDER} not found or already removed, skipping." +fi diff --git a/hack/build-kubemacpool-podman.sh b/hack/build-kubemacpool-podman.sh new file mode 100755 index 000000000..dd1c33f3f --- /dev/null +++ b/hack/build-kubemacpool-podman.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ -z "$ARCH" ] || [ -z "$PLATFORMS" ] || [ -z "$KUBEMACPOOL_IMAGE_TAGGED" ] || [ -z "$KUBEMACPOOL_IMAGE_GIT_TAGGED" ]; then + echo "Error: ARCH, PLATFORMS, KUBEMACPOOL_IMAGE_TAGGED, and KUBEMACPOOL_IMAGE_GIT_TAGGED must be set." + exit 1 +fi + +IFS=',' read -r -a PLATFORM_LIST <<< "$PLATFORMS" + +# Remove any existing manifest and image +podman manifest rm "${KUBEMACPOOL_IMAGE_TAGGED}" 2>/dev/null || true +podman manifest rm "${KUBEMACPOOL_IMAGE_GIT_TAGGED}" 2>/dev/null || true +podman rmi "${KUBEMACPOOL_IMAGE_TAGGED}" 2>/dev/null || true +podman rmi "${KUBEMACPOOL_IMAGE_GIT_TAGGED}" 2>/dev/null || true +podman rmi $(podman images --filter "dangling=true" -q) 2>/dev/null || true + +podman manifest create "${KUBEMACPOOL_IMAGE_TAGGED}" + +for platform in "${PLATFORM_LIST[@]}"; do + podman build \ + --build-arg BUILD_ARCH="$ARCH" \ + --platform "$platform" \ + --manifest "${KUBEMACPOOL_IMAGE_TAGGED}" \ + -f build/Dockerfile . +done diff --git a/hack/build-multiarch-kubemacpool.sh b/hack/build-multiarch-kubemacpool.sh new file mode 100755 index 000000000..5eb1bdc58 --- /dev/null +++ b/hack/build-multiarch-kubemacpool.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +ARCH=$1 +PLATFORMS=$2 +KUBEMACPOOL_IMAGE_TAGGED=$3 +KUBEMACPOOL_IMAGE_GIT_TAGGED=$4 +DOCKER_BUILDER=$5 +OCI_BIN=$6 +REGISTRY=$7 + +if [ "$OCI_BIN" == "podman" ]; then + ARCH=$ARCH PLATFORMS=$PLATFORMS KUBEMACPOOL_IMAGE_TAGGED=$KUBEMACPOOL_IMAGE_TAGGED KUBEMACPOOL_IMAGE_GIT_TAGGED=$KUBEMACPOOL_IMAGE_GIT_TAGGED ./hack/build-kubemacpool-podman.sh +elif [ "$OCI_BIN" == "docker" ]; then + ARCH=$ARCH PLATFORMS=$PLATFORMS KUBEMACPOOL_IMAGE_TAGGED=$KUBEMACPOOL_IMAGE_TAGGED KUBEMACPOOL_IMAGE_GIT_TAGGED=$KUBEMACPOOL_IMAGE_GIT_TAGGED DOCKER_BUILDER=$DOCKER_BUILDER REGISTRY=$REGISTRY ./hack/build-kubemacpool-docker.sh +else + echo "Unsupported OCI_BIN value: $OCI_BIN" + exit 1 +fi + diff --git a/hack/init-buildx.sh b/hack/init-buildx.sh new file mode 100755 index 000000000..bff7ab0be --- /dev/null +++ b/hack/init-buildx.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +check_buildx() { + export DOCKER_CLI_EXPERIMENTAL=enabled + + if ! docker buildx > /dev/null 2>&1; then + mkdir -p ~/.docker/cli-plugins + BUILDX_VERSION=$(curl -s https://api.github.com/repos/docker/buildx/releases/latest | jq -r .tag_name) + ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') + curl -L https://github.com/docker/buildx/releases/download/"${BUILDX_VERSION}"/buildx-"${BUILDX_VERSION}".linux-"${ARCH}" --output ~/.docker/cli-plugins/docker-buildx + chmod a+x ~/.docker/cli-plugins/docker-buildx + fi +} + +create_or_use_buildx_builder() { + local builder_name=$1 + if [ -z "$builder_name" ]; then + echo "Error: Builder name is required." + exit 1 + fi + + check_buildx + + current_builder="$(docker buildx inspect "${builder_name}" 2>/dev/null)" || echo "Builder '${builder_name}' not found" + + if ! grep -q "^Driver: docker$" <<<"${current_builder}" && \ + grep -q "linux/amd64" <<<"${current_builder}" && \ + grep -q "linux/arm64" <<<"${current_builder}" && \ + grep -q "linux/s390x" <<<"${current_builder}"; then + echo "The current builder already has multi-architecture support (amd64, arm64, s390x)." + echo "Skipping setup as the builder is already configured correctly." + exit 0 + fi + + # Check if the builder already exists by parsing the output of `docker buildx ls` + # We check if the builder_name appears in the list of active builders + existing_builder=$(docker buildx ls | grep -w "$builder_name" | awk '{print $1}') + + if [ -n "$existing_builder" ]; then + echo "Builder '$builder_name' already exists." + echo "Using existing builder '$builder_name'." + docker buildx use "$builder_name" + else + echo "Creating a new Docker Buildx builder: $builder_name" + docker buildx create --driver-opt network=host --use --name "$builder_name" + echo "The new builder '$builder_name' has been created and set as active." + fi +} + +if [ $# -eq 1 ]; then + create_or_use_buildx_builder "$1" +else + echo "Usage: $0 " + echo "Example: $0 mybuilder" + exit 1 +fi diff --git a/hack/install-go.sh b/hack/install-go.sh index e7148b311..e770f827b 100755 --- a/hack/install-go.sh +++ b/hack/install-go.sh @@ -2,7 +2,8 @@ destination=$1 version=$(grep "^go " go.mod |awk '{print $2}') -tarball=go$version.linux-amd64.tar.gz +arch=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') +tarball=go$version.linux-$arch.tar.gz url=https://dl.google.com/go/ mkdir -p $destination