From eddc9356af6e491cc630c6bedb328a1077c28baa Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 26 Nov 2025 15:35:34 +0000 Subject: [PATCH] refactor: build Docker images once, retag on publish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Preflight builds multi-arch images to staging tags on GHCR - Publish workflow just retags staging → final (no rebuild) - Reduces publish time from ~10min to ~1min --- .github/workflows/create-release.yml | 60 ++++++++++++++---- .github/workflows/publish-docker.yml | 91 ++++++++-------------------- 2 files changed, 75 insertions(+), 76 deletions(-) diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index d369b62..df42162 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -63,12 +63,14 @@ jobs: echo "✓ VERSION file matches requested version ($REQUESTED_VERSION)" preflight_tests: - needs: version_guard + needs: + - extract_version + - version_guard runs-on: ubuntu-latest timeout-minutes: 90 permissions: contents: read - packages: read + packages: write env: FRONTEND_DIST: frontend-modern/dist steps: @@ -134,15 +136,51 @@ jobs: - name: Build Pulse for integration tests run: make build - - name: Log in to GHCR for build cache - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - if [ -z "${GH_TOKEN:-}" ]; then - echo "::error::GITHUB_TOKEN not available for GHCR login" - exit 1 - fi - echo "$GH_TOKEN" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push staging Docker images + uses: docker/build-push-action@v6 + with: + context: . + target: runtime + platforms: linux/amd64,linux/arm64 + push: true + provenance: false + cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse:buildcache + cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse:buildcache,mode=max + tags: | + ghcr.io/${{ github.repository_owner }}/pulse:staging-${{ needs.extract_version.outputs.tag }} + + - name: Build and push staging Docker agent image + uses: docker/build-push-action@v6 + with: + context: . + file: ./Dockerfile + target: agent_runtime + platforms: linux/amd64,linux/arm64 + push: true + provenance: false + cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:buildcache + cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:buildcache,mode=max + tags: | + ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:staging-${{ needs.extract_version.outputs.tag }} - name: Build Docker images for integration tests run: | diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml index ecbe321..006e68c 100644 --- a/.github/workflows/publish-docker.yml +++ b/.github/workflows/publish-docker.yml @@ -11,7 +11,7 @@ concurrency: jobs: publish: runs-on: ubuntu-latest - timeout-minutes: 60 + timeout-minutes: 15 permissions: contents: read packages: write @@ -26,17 +26,6 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "Publishing Docker images for ${TAG}" - - name: Checkout repository - uses: actions/checkout@v4 - with: - ref: ${{ github.event.release.tag_name }} - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Log in to Docker Hub uses: docker/login-action@v3 with: @@ -50,60 +39,32 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push Pulse server image - uses: docker/build-push-action@v6 - with: - context: . - target: runtime - platforms: linux/amd64,linux/arm64 - push: true - provenance: false - cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse:buildcache - cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse:buildcache,mode=max - tags: | - rcourtman/pulse:${{ steps.version.outputs.tag }} - rcourtman/pulse:${{ steps.version.outputs.version }} - rcourtman/pulse:latest - ghcr.io/${{ github.repository_owner }}/pulse:${{ steps.version.outputs.tag }} - ghcr.io/${{ github.repository_owner }}/pulse:${{ steps.version.outputs.version }} - ghcr.io/${{ github.repository_owner }}/pulse:latest - labels: | - org.opencontainers.image.title=Pulse - org.opencontainers.image.description=Proxmox monitoring system - org.opencontainers.image.version=${{ steps.version.outputs.tag }} - org.opencontainers.image.created=${{ github.event.release.published_at }} - org.opencontainers.image.revision=${{ github.sha }} - org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.licenses=MIT + - name: Copy staging images to final tags + run: | + TAG="${{ steps.version.outputs.tag }}" + VERSION="${{ steps.version.outputs.version }}" + STAGING_TAG="staging-${TAG}" - - name: Build and push Docker agent image - uses: docker/build-push-action@v6 - with: - context: . - file: ./Dockerfile - target: agent_runtime - platforms: linux/amd64,linux/arm64 - push: true - provenance: false - cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:buildcache - cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:buildcache,mode=max - tags: | - rcourtman/pulse-docker-agent:${{ steps.version.outputs.tag }} - rcourtman/pulse-docker-agent:${{ steps.version.outputs.version }} - rcourtman/pulse-docker-agent:latest - ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${{ steps.version.outputs.tag }} - ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${{ steps.version.outputs.version }} - ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:latest - labels: | - org.opencontainers.image.title=Pulse Docker Agent - org.opencontainers.image.description=Docker container monitoring agent for Pulse - org.opencontainers.image.version=${{ steps.version.outputs.tag }} - org.opencontainers.image.created=${{ github.event.release.published_at }} - org.opencontainers.image.revision=${{ github.sha }} - org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }} - org.opencontainers.image.licenses=MIT + echo "Copying pulse staging image to final tags..." + # Pull the staging multi-arch manifest + docker buildx imagetools create \ + --tag rcourtman/pulse:${TAG} \ + --tag rcourtman/pulse:${VERSION} \ + --tag rcourtman/pulse:latest \ + --tag ghcr.io/${{ github.repository_owner }}/pulse:${TAG} \ + --tag ghcr.io/${{ github.repository_owner }}/pulse:${VERSION} \ + --tag ghcr.io/${{ github.repository_owner }}/pulse:latest \ + ghcr.io/${{ github.repository_owner }}/pulse:${STAGING_TAG} + + echo "Copying pulse-docker-agent staging image to final tags..." + docker buildx imagetools create \ + --tag rcourtman/pulse-docker-agent:${TAG} \ + --tag rcourtman/pulse-docker-agent:${VERSION} \ + --tag rcourtman/pulse-docker-agent:latest \ + --tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${TAG} \ + --tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${VERSION} \ + --tag ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:latest \ + ghcr.io/${{ github.repository_owner }}/pulse-docker-agent:${STAGING_TAG} - name: Output image information run: |