diff --git a/.github/workflows/build-bink-image.yaml b/.github/workflows/build-bink-image.yaml index 6ffb382..1db3d0d 100644 --- a/.github/workflows/build-bink-image.yaml +++ b/.github/workflows/build-bink-image.yaml @@ -27,24 +27,72 @@ on: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }}/bink + # internal/config/defaults.go hardcodes this local build tag regardless of + # which repository checked it out, so `make build-bink-image` always + # produces this exact ref, not one derived from IMAGE_NAME above. + LOCAL_IMAGE: ghcr.io/bootc-dev/bink/bink:latest jobs: build: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # CGO_ENABLED=1 (gpgme/btrfs/device-mapper) rules out cross-compiling + # from an amd64 host, so build each architecture on its own native + # runner instead. + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} permissions: contents: read - packages: write steps: - name: Checkout uses: actions/checkout@v7 - - name: Log in to GHCR - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) - run: podman login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ${{ env.REGISTRY }} - - name: Build bink CLI image run: make build-bink-image - - name: Push - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) - run: podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - name: Save bink CLI image + run: | + podman tag "${{ env.LOCAL_IMAGE }}" "localhost/bink:dev-${{ matrix.arch }}" + podman save -o "bink-image-${{ matrix.arch }}.tar" "localhost/bink:dev-${{ matrix.arch }}" + + - name: Upload bink CLI image + uses: actions/upload-artifact@v7 + with: + name: bink-image-${{ matrix.arch }} + path: bink-image-${{ matrix.arch }}.tar + + push: + needs: build + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Download bink CLI images + uses: actions/download-artifact@v8 + with: + pattern: bink-image-* + merge-multiple: true + + - name: Assemble manifest list + run: | + podman load -i bink-image-amd64.tar + podman load -i bink-image-arm64.tar + podman manifest create localhost/bink:dev \ + containers-storage:localhost/bink:dev-amd64 \ + containers-storage:localhost/bink:dev-arm64 + + - name: Push to GHCR + run: | + podman login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ${{ env.REGISTRY }} + # v2s2 keeps the per-architecture manifests in the same format as + # the images published before this became a manifest list, so the + # only change downstream sees is the added list layer. + podman manifest push --all --format v2s2 \ + localhost/bink:dev "docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" diff --git a/.github/workflows/build-cluster-image.yaml b/.github/workflows/build-cluster-image.yaml index 615dbf8..3514bd3 100644 --- a/.github/workflows/build-cluster-image.yaml +++ b/.github/workflows/build-cluster-image.yaml @@ -19,24 +19,71 @@ on: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }}/cluster + # internal/config/defaults.go hardcodes this local build tag regardless of + # which repository checked it out, so `make build-cluster-image` always + # produces this exact ref, not one derived from IMAGE_NAME above. + LOCAL_IMAGE: ghcr.io/bootc-dev/bink/cluster:latest jobs: build: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # The image is entirely dnf-installed RPM content, nothing to + # cross-compile, so build each architecture on its own native runner. + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} permissions: contents: read - packages: write steps: - name: Checkout uses: actions/checkout@v7 - - name: Log in to GHCR - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) - run: podman login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ${{ env.REGISTRY }} - - name: Build cluster image run: make build-cluster-image - - name: Push - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) - run: podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - name: Save cluster image + run: | + podman tag "${{ env.LOCAL_IMAGE }}" "localhost/cluster:dev-${{ matrix.arch }}" + podman save -o "cluster-image-${{ matrix.arch }}.tar" "localhost/cluster:dev-${{ matrix.arch }}" + + - name: Upload cluster image + uses: actions/upload-artifact@v7 + with: + name: cluster-image-${{ matrix.arch }} + path: cluster-image-${{ matrix.arch }}.tar + + push: + needs: build + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Download cluster images + uses: actions/download-artifact@v8 + with: + pattern: cluster-image-* + merge-multiple: true + + - name: Assemble manifest list + run: | + podman load -i cluster-image-amd64.tar + podman load -i cluster-image-arm64.tar + podman manifest create localhost/cluster:dev \ + containers-storage:localhost/cluster:dev-amd64 \ + containers-storage:localhost/cluster:dev-arm64 + + - name: Push to GHCR + run: | + podman login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ${{ env.REGISTRY }} + # v2s2 keeps the per-architecture manifests in the same format as + # the images published before this became a manifest list, so the + # only change downstream sees is the added list layer. + podman manifest push --all --format v2s2 \ + localhost/cluster:dev "docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest" diff --git a/.github/workflows/build-dns-image.yaml b/.github/workflows/build-dns-image.yaml index 4953622..79e667b 100644 --- a/.github/workflows/build-dns-image.yaml +++ b/.github/workflows/build-dns-image.yaml @@ -19,24 +19,71 @@ on: env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }}/dns + # internal/config/defaults.go hardcodes this local build tag regardless of + # which repository checked it out, so `make build-dns-image` always + # produces this exact ref, not one derived from IMAGE_NAME above. + LOCAL_IMAGE: ghcr.io/bootc-dev/bink/dns:latest jobs: build: - runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # The image is entirely microdnf-installed RPM content, nothing to + # cross-compile, so build each architecture on its own native runner. + include: + - arch: amd64 + runner: ubuntu-24.04 + - arch: arm64 + runner: ubuntu-24.04-arm + runs-on: ${{ matrix.runner }} permissions: contents: read - packages: write steps: - name: Checkout uses: actions/checkout@v7 - - name: Log in to GHCR - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) - run: podman login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ${{ env.REGISTRY }} - - name: Build DNS image run: make build-dns-image - - name: Push - if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) - run: podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + - name: Save DNS image + run: | + podman tag "${{ env.LOCAL_IMAGE }}" "localhost/dns:dev-${{ matrix.arch }}" + podman save -o "dns-image-${{ matrix.arch }}.tar" "localhost/dns:dev-${{ matrix.arch }}" + + - name: Upload DNS image + uses: actions/upload-artifact@v7 + with: + name: dns-image-${{ matrix.arch }} + path: dns-image-${{ matrix.arch }}.tar + + push: + needs: build + if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.push) + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - name: Download DNS images + uses: actions/download-artifact@v8 + with: + pattern: dns-image-* + merge-multiple: true + + - name: Assemble manifest list + run: | + podman load -i dns-image-amd64.tar + podman load -i dns-image-arm64.tar + podman manifest create localhost/dns:dev \ + containers-storage:localhost/dns:dev-amd64 \ + containers-storage:localhost/dns:dev-arm64 + + - name: Push to GHCR + run: | + podman login -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }} ${{ env.REGISTRY }} + # v2s2 keeps the per-architecture manifests in the same format as + # the images published before this became a manifest list, so the + # only change downstream sees is the added list layer. + podman manifest push --all --format v2s2 \ + localhost/dns:dev "docker://${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest"