Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 20, 2025

Cross-compilation for ARM64 on AMD64 runners uses emulation, making builds extremely slow. This refactors the deployment workflow to build each platform natively in parallel, then combine via manifests.

Changes

Makefile:

  • Added PLATFORM variable and platform-specific build targets (build-{jvm,native}-platform, push-{jvm,native}-platform)
  • Added manifest creation targets (push-{jvm,native}-manifest) that combine platform-specific images

GitHub Actions workflow:

  • Replaced sequential builds with matrix strategy across ubuntu-24.04 (amd64) and ubuntu-24.04-arm (arm64) runners
  • Builds push platform-tagged images (e.g., jvm-{TAG}-linux-amd64, native-{TAG}-linux-arm64)
  • New manifest jobs combine platform images into final multi-arch tags (jvm-{TAG}, native-{TAG}, latest)

Example

build_jvm_matrix:
  strategy:
    matrix:
      include:
        - platform: linux/amd64
          runner: ubuntu-24.04
        - platform: linux/arm64
          runner: ubuntu-24.04-arm
  runs-on: ${{ matrix.runner }}
  steps:
    - name: Build and Push JVM Docker image for ${{ matrix.platform }}
      run: make push-jvm-platform PLATFORM=${{ matrix.platform }}

create_jvm_manifest:
  needs: build_jvm_matrix
  steps:
    - name: Create and Push JVM multi-platform manifest
      run: make push-jvm-manifest

Pattern adapted from v3-rust branch deployment strategy.

Original prompt

In the Makefile, the building of the docker image is done like this...

For the JVM version:

docker buildx build --platform linux/amd64,linux/arm64 -f ./src/main/docker/Dockerfile.jvm -t "${IMG_JVM}" -t "${LATEST_JVM}" ${DOCKER_EXTRA_ARGS} .

And for the Native version:

docker buildx build --platform linux/amd64,linux/arm64 -f ./src/main/docker/Dockerfile.native -t "${IMG_NATIVE}" -t "${LATEST_NATIVE}" -t "${LATEST}" ${DOCKER_EXTRA_ARGS} .

The problem is that, on top of GitHub Actions, building the linux/arm64 image on top of an amd64 node uses virtualization, therefore compilation is really slow.

Make GitHub Actions compile images in parallel for each platform, then merge them.

For the Rust version of this project (v3-rust) branch, the deployment now looks like this:

name: deploy
on:
  workflow_dispatch:

jobs:
  build_matrix:
    strategy:
      matrix:
        include:
          - platform: linux/amd64
            runner: ubuntu-24.04
          - platform: linux/arm64
            runner: ubuntu-24.04-arm
    runs-on: ${{ matrix.runner }}
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Set platform tag
        id: platform
        run: echo "tag=$(echo ${{ matrix.platform }} | tr '/' '-')" >> $GITHUB_OUTPUT

      - name: Build and Push Docker image for ${{ matrix.platform }}
        run: |
          make push-docker-platform PLATFORM=${{ matrix.platform }}
        env:
          GIT_TAG: ${{ github.ref }}

  create_manifest:
    needs: build_matrix
    runs-on: ubuntu-22.04
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Create and Push multi-platform manifest
        run: |
          make push-manifest
        env:
          GIT_TAG: ${{ github.ref }}

With this Makefile:

NAME          := ghcr.io/alexandru/github-webhook-listener
TAG           := $$(./scripts/new-version.sh)
IMG           := ${NAME}:${TAG}
LATEST        := ${NAME}:latest
PLATFORM      ?= linux/amd64,linux/arm64

test:
	cargo test

build:
	cargo build --release

init-docker:
	docker buildx inspect mybuilder || docker buildx create --name mybuilder
	docker buildx use mybuilder

build-docker: init-docker
	docker buildx build --platform linux/amd64,linux/arm64 -f ./Dockerfile -t "${IMG}" -t "${LATEST}" ${DOCKER_EXTRA_ARGS} .

push-docker:
	DOCKER_EXTRA_ARGS="--push" $(MAKE) build-docker

# Build and push for a single platform (used in matrix builds)
build-docker-platform: init-docker
	$(eval PLATFORM_TAG := $(shell echo ${PLATFORM} | tr '/' '-'))
	docker buildx build --platform ${PLATFORM} -f ./Dockerfile -t "${IMG}-${PLATFORM_TAG}" ${DOCKER_EXTRA_ARGS} .

push-docker-platform:
	DOCKER_EXTRA_ARGS="--push" $(MAKE) build-docker-platform

# Create and push multi-platform manifest combining platform-specific images
push-manifest:
	docker buildx imagetools create -t "${IMG}" -t "${LATEST}" \
		"${IMG}-linux-amd64" \
		"${IMG}-linux-arm64"

build-docker-local:
	docker build -f ./Dockerfile -t "${IMG}" -t "${LATEST}" .

run-docker: build-docker-local
	docker run -p 8080:8080 -ti ${LATEST}

clean:
	cargo clean
	rm -rf target/

That looks like a good solution, but obviously it needs to be adapted, because we have 2 Dockerfiles (JVM + GraalVM Native Image) being built for this Kotlin branch.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI changed the title [WIP] Update GitHub Actions to build Docker images in parallel Parallelize multi-arch Docker builds using native runners Nov 20, 2025
Copilot AI requested a review from alexandru November 20, 2025 05:55
@alexandru alexandru marked this pull request as ready for review November 20, 2025 06:19
@alexandru alexandru enabled auto-merge (squash) November 20, 2025 06:19
@alexandru alexandru disabled auto-merge November 20, 2025 06:19
@alexandru alexandru enabled auto-merge (squash) November 20, 2025 06:20
@alexandru alexandru disabled auto-merge November 20, 2025 06:25
@alexandru alexandru merged commit 84d3660 into v2-kotlin Nov 20, 2025
2 checks passed
@alexandru alexandru deleted the copilot/parallelize-image-builds branch November 20, 2025 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants