diff --git a/.github/workflows/release_docker.yml b/.github/workflows/release_docker.yml index 5f8ef7568de..24c63f40a68 100644 --- a/.github/workflows/release_docker.yml +++ b/.github/workflows/release_docker.yml @@ -1,3 +1,4 @@ +# This workflow is based on https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners name: Publish Docker Images on: @@ -27,47 +28,102 @@ on: default: false jobs: - build-iota-node: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.iota_node == 'true' || github.event_name == 'release' - runs-on: self-hosted + prepare: + outputs: + images: ${{ steps.images.outputs.images }} + runs-on: ubuntu-24.04 + steps: + - name: Define images to build + id: images + run: | + images_array=() + + # Check iota_node: true if the input is set to true and the event is workflow_dispatch, + # or if the event is a release (in which case the job should run regardless of the input). + if [ "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.iota_node == 'true' || github.event_name == 'release' }}" == "true" ]; then + images_array+=("iota-node") + fi + + # Check iota_indexer: true if the input is set to true and the event is workflow_dispatch, + # or if the event is a release (in which case the job should run regardless of the input). + if [ "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.iota_indexer == 'true' || github.event_name == 'release' }}" == "true" ]; then + images_array+=("iota-indexer") + fi + + # Check iota_tools: true if the input is set to true and the event is workflow_dispatch, + # or if the event is a release (in which case the job should run regardless of the input). + if [ "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.iota_tools == 'true' || github.event_name == 'release' }}" == "true" ]; then + images_array+=("iota-tools") + fi + + # Check iota_graphql_rpc: true if the input is set to true and the event is workflow_dispatch, + # or if the event is a release (in which case the job should run regardless of the input). + if [ "${{ github.event_name == 'workflow_dispatch' && github.event.inputs.iota_graphql_rpc == 'true' || github.event_name == 'release' }}" == "true" ]; then + images_array+=("iota-graphql-rpc") + fi + + # Check if the images_array is empty + if [ ${#images_array[@]} -eq 0 ]; then + echo "Error: images_array is empty" + exit 1 + fi + + echo "images=[$(printf '"%s",' "${images_array[@]}" | sed 's/,$//')]" >> "$GITHUB_OUTPUT" + + build: environment: release + needs: prepare + strategy: + fail-fast: false + matrix: + image: ${{ fromJSON(needs.prepare.outputs.images) }} + os: [ + ubuntu-24.04, + ubuntu-24.04-arm, + ] + runs-on: ${{ matrix.os }} steps: - name: Checkout code uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - - name: Read Rust toolchain version from TOML - id: read_toolchain + - name: Prepare Environment Variables run: | + if [ "${{ runner.os }}" != "Linux" ]; then + echo "Error: This workflow only supports Linux runners." + exit 1 + fi + + case "${{ runner.arch }}" in + X64) + PLATFORM_ARCH="amd64" + ;; + ARM64) + PLATFORM_ARCH="arm64" + ;; + *) + echo "Error: Unsupported architecture: ${{ runner.arch }}" + exit 1 + ;; + esac + + echo "DOCKER_FILE=docker/${{ matrix.image }}/Dockerfile" >> $GITHUB_ENV + echo "DOCKER_IMAGE=iotaledger/${{ matrix.image }}" >> $GITHUB_ENV + echo "DOCKER_PLATFORM=linux/${PLATFORM_ARCH}" >> $GITHUB_ENV + echo "PLATFORM_PAIR=linux-${PLATFORM_ARCH}" >> $GITHUB_ENV + TOOLCHAIN_VERSION=$(grep -oE 'channel = "[^"]+' ./rust-toolchain.toml | sed 's/channel = "//') echo "TOOLCHAIN_VERSION=${TOOLCHAIN_VERSION}" >> $GITHUB_ENV - - name: Log Rust toolchain version - run: echo "Rust toolchain version is ${{ env.TOOLCHAIN_VERSION }}" + echo "Rust toolchain version is ${{ env.TOOLCHAIN_VERSION }}" - - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 + echo "GIT_REVISION=$(git describe --always --abbrev=12 --dirty --exclude '*')" >> $GITHUB_ENV + echo "BUILD_DATE=$(date -u +'%Y-%m-%d')" >> $GITHUB_ENV - - name: Docker meta for iota-node - id: meta-node + - name: Docker meta + id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: - images: iotaledger/iota-node - # mapping semver tags to networks - # v{MAJOR}.{MINOR}.{PATCH}-alpha -> alphanet - # v{MAJOR}.{MINOR}.{PATCH}-beta -> devnet - # v{MAJOR}.{MINOR}.{PATCH}-rc -> testnet - # v{MAJOR}.{MINOR}.{PATCH} -> mainnet - tags: | - type=raw,value={{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value={{tag}},enable=${{ github.event_name == 'release' }} - type=raw,value=alphanet,enable=${{ github.event_name == 'release' && contains(github.ref, '-alpha') }} - type=raw,value=devnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-beta') }} - type=raw,value=testnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-rc') }} - type=raw,value=mainnet,enable=${{ github.event_name == 'release' && !contains(github.ref, '-alpha') && !contains(github.ref, '-beta') && !contains(github.ref, '-rc') }} + images: ${{ env.DOCKER_IMAGE }} - name: Login to Docker Registry uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 @@ -76,136 +132,56 @@ jobs: password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} registry: ${{ secrets.DOCKER_REGISTRY_URL }} - - name: Get git revision and build date - id: git-info - run: | - echo "GIT_REVISION=$(git describe --always --abbrev=12 --dirty --exclude '*')" >> $GITHUB_ENV - echo "BUILD_DATE=$(date -u +'%Y-%m-%d')" >> $GITHUB_ENV + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - - name: Build and push Docker image for iota-node + - name: Build and push by digest + id: build-image uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 with: context: . - file: docker/iota-node/Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta-node.outputs.tags }} - push: true - pull: true + file: ${{ env.DOCKER_FILE }} + platforms: ${{ env.DOCKER_PLATFORM }} + labels: ${{ steps.meta.outputs.labels }} + outputs: type=image,"name=${{ env.DOCKER_IMAGE }}",push-by-digest=true,name-canonical=true,push=true build-args: | GIT_REVISION=${{ env.GIT_REVISION }} BUILD_DATE=${{ env.BUILD_DATE }} RUST_IMAGE_VERSION=${{ env.TOOLCHAIN_VERSION }}-bookworm - build-iota-indexer: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.iota_indexer == 'true' || github.event_name == 'release' - runs-on: self-hosted - environment: release - steps: - - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - - - name: Read Rust toolchain version from TOML - id: read_toolchain + - name: Export digest run: | - TOOLCHAIN_VERSION=$(grep -oE 'channel = "[^"]+' ./rust-toolchain.toml | sed 's/channel = "//') - echo "TOOLCHAIN_VERSION=${TOOLCHAIN_VERSION}" >> $GITHUB_ENV - - - name: Log Rust toolchain version - run: echo "Rust toolchain version is ${{ env.TOOLCHAIN_VERSION }}" - - - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + mkdir -p ${{ runner.temp }}/digests + digest="${{ steps.build-image.outputs.digest }}" + touch "${{ runner.temp }}/digests/${digest#sha256:}" - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - - - name: Docker meta for iota-indexer - id: meta-indexer - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 + - name: Upload digest + uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 with: - images: iotaledger/iota-indexer - # mapping semver tags to networks - # v{MAJOR}.{MINOR}.{PATCH}-alpha -> alphanet - # v{MAJOR}.{MINOR}.{PATCH}-beta -> devnet - # v{MAJOR}.{MINOR}.{PATCH}-rc -> testnet - # v{MAJOR}.{MINOR}.{PATCH} -> mainnet - tags: | - type=raw,value={{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value={{tag}},enable=${{ github.event_name == 'release' }} - type=raw,value=alphanet,enable=${{ github.event_name == 'release' && contains(github.ref, '-alpha') }} - type=raw,value=devnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-beta') }} - type=raw,value=testnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-rc') }} - type=raw,value=mainnet,enable=${{ github.event_name == 'release' && !contains(github.ref, '-alpha') && !contains(github.ref, '-beta') && !contains(github.ref, '-rc') }} - - - name: Login to Docker Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 - with: - username: ${{ secrets.DOCKER_REGISTRY_USERNAME }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} - registry: ${{ secrets.DOCKER_REGISTRY_URL }} - - - name: Get git revision and build date - id: git-info - run: | - echo "GIT_REVISION=$(git describe --always --abbrev=12 --dirty --exclude '*')" >> $GITHUB_ENV - echo "BUILD_DATE=$(date -u +'%Y-%m-%d')" >> $GITHUB_ENV - - - name: Build and push Docker image for iota-indexer - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 - with: - context: . - file: docker/iota-indexer/Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta-indexer.outputs.tags }} - push: true - pull: true - build-args: | - GIT_REVISION=${{ env.GIT_REVISION }} - BUILD_DATE=${{ env.BUILD_DATE }} - RUST_IMAGE_VERSION=${{ env.TOOLCHAIN_VERSION }}-bookworm - - build-iota-tools: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.iota_tools == 'true' || github.event_name == 'release' - runs-on: self-hosted - environment: release + name: digests-${{ github.sha }}-${{ matrix.image }}-${{ env.PLATFORM_PAIR }} + path: ${{ runner.temp }}/digests/* + if-no-files-found: error + retention-days: 1 + + tag: + environment: release # This will require a second approval after all `build` jobs have finished (see https://github.com/orgs/community/discussions/14417) + needs: [prepare, build] + strategy: + fail-fast: false + matrix: + image: ${{ fromJSON(needs.prepare.outputs.images) }} + runs-on: ubuntu-24.04 steps: - - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - - - name: Read Rust toolchain version from TOML - id: read_toolchain + - name: Prepare Environment Variables run: | - TOOLCHAIN_VERSION=$(grep -oE 'channel = "[^"]+' ./rust-toolchain.toml | sed 's/channel = "//') - echo "TOOLCHAIN_VERSION=${TOOLCHAIN_VERSION}" >> $GITHUB_ENV + echo "DOCKER_IMAGE=iotaledger/${{ matrix.image }}" >> $GITHUB_ENV - - name: Log Rust toolchain version - run: echo "Rust toolchain version is ${{ env.TOOLCHAIN_VERSION }}" - - - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - - - name: Docker meta for iota-tools - id: meta-tools - uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 + - name: Download digests + uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 with: - images: iotaledger/iota-tools - # mapping semver tags to networks - # v{MAJOR}.{MINOR}.{PATCH}-alpha -> alphanet - # v{MAJOR}.{MINOR}.{PATCH}-beta -> devnet - # v{MAJOR}.{MINOR}.{PATCH}-rc -> testnet - # v{MAJOR}.{MINOR}.{PATCH} -> mainnet - tags: | - type=raw,value={{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value={{tag}},enable=${{ github.event_name == 'release' }} - type=raw,value=alphanet,enable=${{ github.event_name == 'release' && contains(github.ref, '-alpha') }} - type=raw,value=devnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-beta') }} - type=raw,value=testnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-rc') }} - type=raw,value=mainnet,enable=${{ github.event_name == 'release' && !contains(github.ref, '-alpha') && !contains(github.ref, '-beta') && !contains(github.ref, '-rc') }} + path: ${{ runner.temp }}/digests + pattern: digests-${{ github.sha }}-${{ matrix.image }}-* + merge-multiple: true - name: Login to Docker Registry uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 @@ -214,54 +190,14 @@ jobs: password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} registry: ${{ secrets.DOCKER_REGISTRY_URL }} - - name: Get git revision and build date - id: git-info - run: | - echo "GIT_REVISION=$(git describe --always --abbrev=12 --dirty --exclude '*')" >> $GITHUB_ENV - echo "BUILD_DATE=$(date -u +'%Y-%m-%d')" >> $GITHUB_ENV - - - name: Build and push Docker image for iota-tools - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 - with: - context: . - file: docker/iota-tools/Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta-tools.outputs.tags }} - push: true - pull: true - build-args: | - GIT_REVISION=${{ env.GIT_REVISION }} - BUILD_DATE=${{ env.BUILD_DATE }} - RUST_IMAGE_VERSION=${{ env.TOOLCHAIN_VERSION }}-bookworm - - build-iota-graphql-rpc: - if: github.event_name == 'workflow_dispatch' && github.event.inputs.iota_graphql_rpc == 'true' || github.event_name == 'release' - runs-on: self-hosted - environment: release - steps: - - name: Checkout code - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # v4.2.1 - - - name: Read Rust toolchain version from TOML - id: read_toolchain - run: | - TOOLCHAIN_VERSION=$(grep -oE 'channel = "[^"]+' ./rust-toolchain.toml | sed 's/channel = "//') - echo "TOOLCHAIN_VERSION=${TOOLCHAIN_VERSION}" >> $GITHUB_ENV - - - name: Log Rust toolchain version - run: echo "Rust toolchain version is ${{ env.TOOLCHAIN_VERSION }}" - - - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - - name: Set up Docker Buildx uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - - name: Docker meta for iota-graphql-rpc - id: meta-tools + - name: Docker meta + id: meta uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1 with: - images: iotaledger/iota-graphql-rpc + images: ${{ env.DOCKER_IMAGE }} # mapping semver tags to networks # v{MAJOR}.{MINOR}.{PATCH}-alpha -> alphanet # v{MAJOR}.{MINOR}.{PATCH}-beta -> devnet @@ -269,36 +205,15 @@ jobs: # v{MAJOR}.{MINOR}.{PATCH} -> mainnet tags: | type=raw,value={{sha}},enable=${{ github.event_name == 'workflow_dispatch' }} - type=raw,value=latest,enable=${{ github.event_name == 'workflow_dispatch' }} type=raw,value={{tag}},enable=${{ github.event_name == 'release' }} type=raw,value=alphanet,enable=${{ github.event_name == 'release' && contains(github.ref, '-alpha') }} type=raw,value=devnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-beta') }} type=raw,value=testnet,enable=${{ github.event_name == 'release' && contains(github.ref, '-rc') }} type=raw,value=mainnet,enable=${{ github.event_name == 'release' && !contains(github.ref, '-alpha') && !contains(github.ref, '-beta') && !contains(github.ref, '-rc') }} + type=raw,value=latest,enable=${{ github.event_name == 'release' && !contains(github.ref, '-alpha') && !contains(github.ref, '-beta') && !contains(github.ref, '-rc') }} - - name: Login to Docker Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 - with: - username: ${{ secrets.DOCKER_REGISTRY_USERNAME }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWORD }} - registry: ${{ secrets.DOCKER_REGISTRY_URL }} - - - name: Get git revision and build date - id: git-info + - name: Create manifest list and push + working-directory: ${{ runner.temp }}/digests run: | - echo "GIT_REVISION=$(git describe --always --abbrev=12 --dirty --exclude '*')" >> $GITHUB_ENV - echo "BUILD_DATE=$(date -u +'%Y-%m-%d')" >> $GITHUB_ENV - - - name: Build and push Docker image for iota-graphql-rpc - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 - with: - context: . - file: docker/iota-graphql-rpc/Dockerfile - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta-tools.outputs.tags }} - push: true - pull: true - build-args: | - GIT_REVISION=${{ env.GIT_REVISION }} - BUILD_DATE=${{ env.BUILD_DATE }} - RUST_IMAGE_VERSION=${{ env.TOOLCHAIN_VERSION }}-bookworm + docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ + $(printf '${{ env.DOCKER_IMAGE }}@sha256:%s ' *)