Skip to content

Commit f8b4e0a

Browse files
authored
Merge pull request #64 from validatedpatterns/publish-arm64-amd64-images-to-both-quay-orgs
use separate workflows for amd64 and arm64
2 parents f32edbb + a9f0b8a commit f8b4e0a

2 files changed

Lines changed: 166 additions & 49 deletions

File tree

.github/workflows/container-test.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
name: "Container build and test"
33

44
on:
5-
pull_request:
6-
branches: ["main"]
5+
workflow_call:
76

87
permissions: read-all
98

Lines changed: 165 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,190 @@
11
---
22
name: Docker build and push to quay
3-
permissions: read-all
43

54
on:
65
push:
7-
branches: ['main']
8-
tags: ['v*.*.*']
6+
branches: ["main"]
7+
# Publish semver tags as releases.
8+
tags: ["v*.*.*"]
9+
pull_request:
10+
branches: ["main"]
11+
12+
workflow_dispatch:
13+
14+
repository_dispatch:
15+
types: [dependency-updated]
916

1017
env:
18+
# Use docker.io for Docker Hub if empty
1119
REGISTRY: quay.io
20+
# Generic image name for build artifacts, will be retagged for specific repos
21+
QUAY_IMAGE_NAME: localhost/utility-container
1222

1323
jobs:
14-
build-container-and-push:
15-
runs-on: ubuntu-latest
24+
test:
25+
uses: ./.github/workflows/container-test.yml
26+
27+
build-container:
28+
needs: [test]
1629
strategy:
1730
matrix:
18-
image:
19-
- name: hybridcloudpatterns/utility-container
20-
username_secret: LEGACY_QUAY_USERNAME
21-
password_secret: LEGACY_QUAY_PASSWORD
22-
- name: validatedpatterns/utility-container
31+
include:
32+
- targetarch: amd64
33+
runner: ubuntu-latest
34+
platform: linux/amd64
35+
alttargetarch: x86_64
36+
opttargetarch: ""
37+
extrarpms: ""
38+
- targetarch: arm64
39+
runner: ubuntu-24.04-arm
40+
platform: linux/arm64
41+
alttargetarch: aarch64
42+
opttargetarch: "arm64-"
43+
extrarpms: "gcc python3-devel glibc-devel libxcrypt-devel"
44+
45+
runs-on: ${{ matrix.runner }}
46+
permissions:
47+
contents: read
48+
49+
steps:
50+
- name: Checkout repository
51+
uses: actions/checkout@v5
52+
53+
# Set up BuildKit Docker container builder for docker save functionality
54+
# https://github.com/docker/setup-buildx-action
55+
- name: Set up Docker Buildx
56+
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
57+
58+
# https://github.com/docker/build-push-action
59+
# Build Docker image with Buildx. We always disable the cache as
60+
# it sometimes would not pull the new git changes for the cluster_utils,v1
61+
- name: Build Docker image
62+
id: build-and-push
63+
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
64+
with:
65+
context: .
66+
file: Containerfile
67+
platforms: ${{ matrix.platform }}
68+
push: false
69+
tags: ${{ env.REGISTRY }}/${{ env.QUAY_IMAGE_NAME }}:build-${{ github.run_id }}-${{ matrix.targetarch }}
70+
no-cache: true
71+
outputs: type=docker,dest=/tmp/image-${{ matrix.targetarch }}.tar
72+
build-args: |
73+
TARGETARCH=${{ matrix.targetarch }}
74+
ALTTARGETARCH=${{ matrix.alttargetarch }}
75+
OPTTARGETARCH=${{ matrix.opttargetarch }}
76+
EXTRARPMS=${{ matrix.extrarpms }}
77+
78+
# Upload image as artifact
79+
- name: Upload image artifact
80+
if: github.event_name != 'pull_request'
81+
uses: actions/upload-artifact@v4
82+
with:
83+
name: image-${{ matrix.targetarch }}-${{ github.run_id }}
84+
path: /tmp/image-${{ matrix.targetarch }}.tar
85+
retention-days: 1
86+
87+
create-multiarch-manifest:
88+
needs: [build-container]
89+
if: github.event_name != 'pull_request'
90+
strategy:
91+
matrix:
92+
include:
93+
- image_name: validatedpatterns/utility-container
2394
username_secret: QUAY_USERNAME
2495
password_secret: QUAY_PASSWORD
96+
- image_name: hybridcloudpatterns/utility-container
97+
username_secret: LEGACY_QUAY_USERNAME
98+
password_secret: LEGACY_QUAY_PASSWORD
99+
100+
runs-on: ubuntu-latest
25101
permissions:
26102
contents: read
27-
packages: write
28103
# This is used to complete the identity challenge
29104
# with sigstore/fulcio when running outside of PRs.
30105
id-token: write
31106

32107
steps:
33-
- name: Checkout repository
34-
uses: actions/checkout@v5
108+
# Download image artifacts
109+
- name: Download AMD64 image
110+
uses: actions/download-artifact@v4
111+
with:
112+
name: image-amd64-${{ github.run_id }}
113+
path: /tmp/
114+
115+
- name: Download ARM64 image
116+
uses: actions/download-artifact@v4
117+
with:
118+
name: image-arm64-${{ github.run_id }}
119+
path: /tmp/
35120

36-
- name: Set up QEMU
37-
uses: docker/setup-qemu-action@v3
121+
# Load images into Docker and retag for this repo
122+
- name: Load and retag images
123+
run: |
124+
docker load --input /tmp/image-amd64.tar
125+
docker load --input /tmp/image-arm64.tar
126+
127+
# Retag loaded images for this specific repo
128+
OLD_IMAGE_BASE="${{ env.REGISTRY }}/${{ env.QUAY_IMAGE_NAME }}"
129+
NEW_IMAGE_BASE="${{ env.REGISTRY }}/${{ matrix.image_name }}"
130+
131+
docker tag "${OLD_IMAGE_BASE}:build-${{ github.run_id }}-amd64" "${NEW_IMAGE_BASE}:build-${{ github.run_id }}-amd64"
132+
docker tag "${OLD_IMAGE_BASE}:build-${{ github.run_id }}-arm64" "${NEW_IMAGE_BASE}:build-${{ github.run_id }}-arm64"
38133
39134
# Install the cosign tool
40135
# https://github.com/sigstore/cosign-installer
41136
- name: Install cosign
42137
uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2
43138
with:
44-
cosign-release: 'v2.2.4'
139+
cosign-release: "v2.2.4"
45140

46-
# Set up BuildKit Docker container builder to be able to build
47-
# multi-platform images and export cache
48-
# https://github.com/docker/setup-buildx-action
49-
- name: Set up Docker Buildx
50-
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
51-
52-
# Login against a Docker registry
53-
# https://github.com/docker/login-action
54141
- name: Log into registry ${{ env.REGISTRY }}
55142
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
56143
with:
57144
registry: ${{ env.REGISTRY }}
58-
username: ${{ secrets[matrix.image.username_secret] }}
59-
password: ${{ secrets[matrix.image.password_secret] }}
145+
username: ${{ secrets[matrix.username_secret] }}
146+
password: ${{ secrets[matrix.password_secret] }}
147+
148+
# Push individual architecture images to registry
149+
- name: Push architecture-specific images
150+
run: |
151+
IMAGE_BASE="${{ env.REGISTRY }}/${{ matrix.image_name }}"
152+
docker push "${IMAGE_BASE}:build-${{ github.run_id }}-amd64"
153+
docker push "${IMAGE_BASE}:build-${{ github.run_id }}-arm64"
60154
61-
# Extract metadata (tags, labels) for Docker
62-
# https://github.com/docker/metadata-action
63-
- name: Extract Docker metadata
155+
# Extract metadata for multi-arch manifest
156+
- name: Extract Docker metadata for manifest
64157
id: meta
65158
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f # v5.8.0
66159
with:
67-
images: ${{ env.REGISTRY }}/${{ matrix.image.name }}
160+
images: ${{ env.REGISTRY }}/${{ matrix.image_name }}
161+
flavor: |
162+
latest=${{ github.ref == 'refs/heads/main' }}
68163
69-
# Build and push Docker image with Buildx
70-
# https://github.com/docker/build-push-action
71-
- name: Build and push Docker image
72-
id: build-and-push
73-
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
74-
with:
75-
context: .
76-
file: Containerfile
77-
platforms: linux/amd64,linux/arm64
78-
push: true
79-
tags: ${{ steps.meta.outputs.tags }}
80-
labels: ${{ steps.meta.outputs.labels }}
81-
cache-from: type=gha
82-
cache-to: type=gha,mode=max
83-
84-
# Sign the resulting Docker image digest.
164+
# Create and push multi-arch manifest
165+
- name: Create and push multi-arch manifest
166+
id: push-manifest
167+
run: |
168+
IMAGE_BASE="${{ env.REGISTRY }}/${{ matrix.image_name }}"
169+
170+
# Get the tags from metadata
171+
TAGS="${{ steps.meta.outputs.tags }}"
172+
173+
for TAG in $TAGS; do
174+
echo "Creating manifest for: $TAG"
175+
176+
# Use docker buildx imagetools to create multi-arch manifest
177+
docker buildx imagetools create -t "$TAG" \
178+
"${IMAGE_BASE}:build-${{ github.run_id }}-amd64" \
179+
"${IMAGE_BASE}:build-${{ github.run_id }}-arm64"
180+
done
181+
182+
# Get the digest of the first tag for signing
183+
FIRST_TAG=$(echo "$TAGS" | head -n1)
184+
DIGEST=$(docker buildx imagetools inspect "$FIRST_TAG" --format '{{json .}}' | jq -r '.manifest.digest')
185+
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
186+
187+
# Sign the resulting Docker image digest
85188
# This will only write to the public Rekor transparency log when the Docker
86189
# repository is public to avoid leaking data. If you would like to publish
87190
# transparency data even for private images, pass --force to cosign below.
@@ -90,7 +193,22 @@ jobs:
90193
env:
91194
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
92195
TAGS: ${{ steps.meta.outputs.tags }}
93-
DIGEST: ${{ steps.build-and-push.outputs.digest }}
196+
DIGEST: ${{ steps.push-manifest.outputs.digest }}
94197
# This step uses the identity token to provision an ephemeral certificate
95198
# against the sigstore community Fulcio instance.
96199
run: echo "${TAGS}" | xargs -I "{}" cosign sign --yes "{}@${DIGEST}"
200+
201+
# Clean up temporary architecture-specific images
202+
- name: Clean up temporary images
203+
if: always()
204+
run: |
205+
IMAGE_BASE="${{ env.REGISTRY }}/${{ matrix.image_name }}"
206+
207+
# Try to delete temporary images, ignore errors if they don't exist
208+
docker run --rm quay.io/skopeo/stable delete \
209+
--creds "${{ secrets[matrix.username_secret] }}:${{ secrets[matrix.password_secret] }}" \
210+
docker://"${IMAGE_BASE}:build-${{ github.run_id }}-amd64" || true
211+
212+
docker run --rm quay.io/skopeo/stable delete \
213+
--creds "${{ secrets[matrix.username_secret] }}:${{ secrets[matrix.password_secret] }}" \
214+
docker://"${IMAGE_BASE}:build-${{ github.run_id }}-arm64" || true

0 commit comments

Comments
 (0)