From ca1d94c5d4bda729ece153e9254e0da36cf715c1 Mon Sep 17 00:00:00 2001 From: Brandon Palm Date: Tue, 26 Mar 2024 15:56:57 -0500 Subject: [PATCH] Enable multi-platform image builds --- .github/workflows/pre-main.yaml | 26 ++++++++++++++++-- .github/workflows/tnf-image.yaml | 12 ++++++--- Dockerfile | 45 ++++++++++++++++++++++++-------- Makefile | 43 ++++++++++++++++++++++++++---- 4 files changed, 105 insertions(+), 21 deletions(-) diff --git a/.github/workflows/pre-main.yaml b/.github/workflows/pre-main.yaml index 5a3c803d6..04b619c67 100644 --- a/.github/workflows/pre-main.yaml +++ b/.github/workflows/pre-main.yaml @@ -483,9 +483,31 @@ jobs: username: ${{ secrets.QUAY_ROBOT_USERNAME }} password: ${{ secrets.QUAY_ROBOT_TOKEN }} - - name: (if on main and upstream) Push the newly built image to Quay.io + - name: Build the `cnf-certification-test` images for multi-platform (x86) if: ${{ github.ref == 'refs/heads/main' && github.repository_owner == 'test-network-function' }} - run: docker push --all-tags ${REGISTRY}/${TNF_IMAGE_NAME} + uses: nick-fields/retry@v3 + with: + timeout_minutes: 90 + max_attempts: 3 + command: make build-image-local-x86 + env: + IMAGE_TAG: ${TNF_IMAGE_TAG} + + - name: Build the `cnf-certification-test` images for multi-platform (arm64) + if: ${{ github.ref == 'refs/heads/main' && github.repository_owner == 'test-network-function' }} + uses: nick-fields/retry@v3 + with: + timeout_minutes: 90 + max_attempts: 3 + command: make build-image-local-arm + env: + IMAGE_TAG: ${TNF_IMAGE_TAG} + + - name: Create and push the manifest list for the `cnf-certification-test` image + if: ${{ github.ref == 'refs/heads/main' && github.repository_owner == 'test-network-function' }} + run: | + make create-manifest-local + docker manifest push ${REGISTRY}/${TNF_IMAGE_NAME}:${TNF_IMAGE_TAG} check-all-dependencies-are-merged: name: Check all the PR dependencies are merged diff --git a/.github/workflows/tnf-image.yaml b/.github/workflows/tnf-image.yaml index a6bc53341..3cbdb1fa3 100644 --- a/.github/workflows/tnf-image.yaml +++ b/.github/workflows/tnf-image.yaml @@ -115,12 +115,18 @@ jobs: with: ref: ${{ env.TNF_VERSION }} - - name: Build the `cnf-certification-test` image + - name: Build the `cnf-certification-test` images (both amd64 and arm64) run: | make build-image-tnf env: TNF_VERSION: ${{ env.TNF_VERSION }} + - name: Create docker manifest for the `cnf-certification-test` image + run: | + make create-manifest-tnf + env: + TNF_VERSION: ${{ env.TNF_VERSION }} + # Push the new TNF image to Quay.io. - name: Authenticate against Quay.io uses: docker/login-action@v3 @@ -131,8 +137,8 @@ jobs: username: ${{ secrets.QUAY_ROBOT_USERNAME }} password: ${{ secrets.QUAY_ROBOT_TOKEN }} - - name: Push the newly built image to Quay.io - run: docker push --all-tags ${REGISTRY}/${TNF_IMAGE_NAME} + - name: Push the newly built image manifest to Quay.io + run: docker manifest push ${REGISTRY}/${TNF_IMAGE_NAME} - name: If failed to create the image, send alert msg to dev team. if: ${{ failure() }} diff --git a/Dockerfile b/Dockerfile index c290996f0..525060fb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,17 +19,28 @@ RUN \ && dnf clean all --assumeyes --disableplugin=subscription-manager \ && rm -rf /var/cache/yum +# Set environment specific variables +ENV \ + OPERATOR_SDK_X86_FILENAME=operator-sdk_linux_amd64 \ + OPERATOR_SDK_ARM_FILENAME=operator-sdk_linux_arm64 + # Install Go binary and set the PATH ENV \ GO_DL_URL=https://golang.org/dl \ - GO_BIN_TAR=go1.22.1.linux-amd64.tar.gz \ GOPATH=/root/go -ENV GO_BIN_URL_x86_64=${GO_DL_URL}/${GO_BIN_TAR} +ENV GO_BIN_URL_x86_64=${GO_DL_URL}/go1.22.1.linux-amd64.tar.gz +ENV GO_BIN_URL_aarch64=${GO_DL_URL}/go1.22.1.linux-arm64.tar.gz + +# Determine the CPU architecture and download the appropriate Go binary RUN \ if [ "$(uname -m)" = x86_64 ]; then \ wget --directory-prefix=${TEMP_DIR} ${GO_BIN_URL_x86_64} --quiet \ && rm -rf /usr/local/go \ - && tar -C /usr/local -xzf ${TEMP_DIR}/${GO_BIN_TAR}; \ + && tar -C /usr/local -xzf ${TEMP_DIR}/go1.22.1.linux-amd64.tar.gz; \ + elif [ "$(uname -m)" = aarch64 ]; then \ + wget --directory-prefix=${TEMP_DIR} ${GO_BIN_URL_aarch64} --quiet \ + && rm -rf /usr/local/go \ + && tar -C /usr/local -xzf ${TEMP_DIR}/go1.22.1.linux-arm64.tar.gz; \ else \ echo "CPU architecture is not supported." && exit 1; \ fi @@ -40,16 +51,28 @@ ENV \ OPERATOR_SDK_DL_URL=https://github.com/operator-framework/operator-sdk/releases/download/v1.34.1 \ OSDK_BIN=/usr/local/osdk/bin -# Either use Wget or Curl but not both. +RUN \ + mkdir -p ${OSDK_BIN} + # hadolint ignore=DL4001 RUN \ - mkdir -p ${OSDK_BIN} \ - && curl \ - --location \ - --remote-name \ - ${OPERATOR_SDK_DL_URL}/operator-sdk_linux_amd64 \ - && mv operator-sdk_linux_amd64 ${OSDK_BIN}/operator-sdk \ - && chmod +x ${OSDK_BIN}/operator-sdk + if [ "$(uname -m)" = x86_64 ]; then \ + curl \ + --location \ + --remote-name \ + ${OPERATOR_SDK_DL_URL}/${OPERATOR_SDK_X86_FILENAME} \ + && mv ${OPERATOR_SDK_X86_FILENAME} ${OSDK_BIN}/operator-sdk \ + && chmod +x ${OSDK_BIN}/operator-sdk; \ + elif [ "$(uname -m)" = aarch64 ]; then \ + curl \ + --location \ + --remote-name \ + ${OPERATOR_SDK_DL_URL}/${OPERATOR_SDK_ARM_FILENAME} \ + && mv ${OPERATOR_SDK_ARM_FILENAME} ${OSDK_BIN}/operator-sdk \ + && chmod +x ${OSDK_BIN}/operator-sdk; \ + else \ + echo "CPU architecture is not supported." && exit 1; \ + fi # Copy all of the files into the source directory and then switch contexts COPY . ${TNF_SRC_DIR} diff --git a/Makefile b/Makefile index 0e140474c..7a5937967 100644 --- a/Makefile +++ b/Makefile @@ -152,19 +152,52 @@ get-db: delete-db: rm -rf ${REPO_DIR}/offline-db +# Runs against whatever architecture the host is build-image-local: docker build --pull --no-cache \ -t ${REGISTRY_LOCAL}/${TNF_IMAGE_NAME}:${IMAGE_TAG} \ -t ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG} \ -f Dockerfile . -build-image-tnf: - docker build --pull --no-cache \ - -t ${REGISTRY_LOCAL}/${TNF_IMAGE_NAME}:${IMAGE_TAG} \ - -t ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG} \ - -t ${REGISTRY}/${TNF_IMAGE_NAME}:${TNF_VERSION} \ +build-image-local-x86: + docker build --pull --no-cache --platform linux/amd64 \ + -t ${REGISTRY_LOCAL}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-amd64 \ + -t ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-amd64 \ + -f Dockerfile . + +build-image-local-arm: + docker build --pull --no-cache --platform linux/arm64 \ + -t ${REGISTRY_LOCAL}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-arm64 \ + -t ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-arm64 \ + -f Dockerfile . + +create-manifest-local: + docker manifest create ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG} \ + ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-amd64 \ + ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-arm64 + +# Multi-platform build for releases +build-image-tnf: build-image-tnf-x86 build-image-tnf-arm + +build-image-tnf-x86: + docker build --pull --no-cache --platform linux/amd64 \ + -t ${REGISTRY_LOCAL}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-amd64 \ + -t ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-amd64 \ + -t ${REGISTRY}/${TNF_IMAGE_NAME}:${TNF_VERSION}-linux-amd64 \ -f Dockerfile . +build-image-tnf-arm: + docker build --pull --no-cache --platform linux/arm64 \ + -t ${REGISTRY_LOCAL}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-arm64 \ + -t ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-arm64 \ + -t ${REGISTRY}/${TNF_IMAGE_NAME}:${TNF_VERSION}-linux-arm64 \ + -f Dockerfile . + +create-manifest-tnf: + docker manifest create ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG} \ + ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-amd64 \ + ${REGISTRY}/${TNF_IMAGE_NAME}:${IMAGE_TAG}-linux-arm64 + results-html: script/get-results-html.sh ${PARSER_RELEASE}