Skip to content

Build amd64 and arm64 #574

Build amd64 and arm64

Build amd64 and arm64 #574

Workflow file for this run

name: Build amd64 and arm64
on:
workflow_dispatch:
inputs:
RELEASE:
description: 'AlmaLinux release'
required: true
default: '9'
type: choice
options:
- '10-kitten'
- '10'
- '9'
- 'ALL'
schedule:
# run every day at 03:00 UTC
- cron: '00 03 * * *'
# REQUIRED: Set up permissions for OIDC token and KMS access
permissions:
id-token: write
contents: read
packages: write
env:
LATEST_MAJOR: 9
IMAGE_NAME: almalinux-bootc
VERSIONS_LIST: '"9", "10-kitten", "10"'
AWS_REGION: us-east-1
AWS_ROLE_ARN: arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/bootcimages
KMS_KEY_ALIAS: cloudsig
CHAT_CHANNEL: ${{ vars.MATTERMOST_CHANNEL }}
jobs:
set-versions-matrix:
name: Set versions matrix
runs-on: ubuntu-24.04
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
date_stamp: ${{ steps.date-stamp.outputs.date_stamp }}
steps:
- name: Set matrix
id: set-matrix
run: |
# Format json for versions matrix
case ${{ github.event_name }} in
workflow_dispatch)
if [[ "${{ inputs.RELEASE }}" == "ALL" ]]; then
echo "matrix=$(jq -c <<< '[${{ env.VERSIONS_LIST }}]')" >> $GITHUB_OUTPUT
else
echo "matrix=$(jq -c <<< '["${{ inputs.RELEASE }}"]')" >> $GITHUB_OUTPUT
fi
;;
schedule)
echo "matrix=$(jq -c <<< '[${{ env.VERSIONS_LIST }}]')" >> $GITHUB_OUTPUT
;;
esac
- name: Date stamp
id: date-stamp
run: |
# date stamp
date_stamp=$(date -u '+%Y%m%d')
[ "x${date_stamp}" != "x" ] && echo "date_stamp=${date_stamp}" >> "$GITHUB_OUTPUT"
build:
name: Build image
runs-on: ${{ matrix.ARCH == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
needs: [set-versions-matrix]
strategy:
fail-fast: false
matrix:
VERSION_MAJOR: ${{ fromJSON(needs.set-versions-matrix.outputs.matrix) }}
ARCH: [amd64, arm64, amd64/v2]
exclude:
- VERSION_MAJOR: 9
ARCH: amd64/v2
env:
PLATFORM: linux/${{ matrix.ARCH }}
DATE_STAMP: ${{ needs.set-versions-matrix.outputs.date_stamp }}
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/shared-steps
name: Build and Push
with:
VERSION_MAJOR: ${{ matrix.VERSION_MAJOR }}
DATE_STAMP: ${{ env.DATE_STAMP }}
IMAGE_REGISTRY: ${{ secrets.IMAGE_REGISTRY }}
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
KMS_KEY_ALIAS: ${{ env.KMS_KEY_ALIAS }}
AWS_ROLE_ARN: ${{ env.AWS_ROLE_ARN }}
AWS_REGION: ${{ env.AWS_REGION }}
push-manifest:
if: ${{ always() && contains(join(needs.*.result, ','), 'success') }}
name: Push manifest
needs: [set-versions-matrix, build]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
VERSION_MAJOR: ${{ fromJSON(needs.set-versions-matrix.outputs.matrix) }}
env:
DATE_STAMP: ${{ needs.set-versions-matrix.outputs.date_stamp }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Fetch Build Outputs
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
pattern: ${{ env.IMAGE_NAME }}_${{ matrix.VERSION_MAJOR }}_*
merge-multiple: true
path: /tmp/artifacts
- name: Load Outputs
id: load-outputs
run: |
if [[ ! -d /tmp/artifacts ]]; then
echo "No artifacts found, skipping manifest creation"
echo "skip=1" >> "$GITHUB_ENV"
exit
fi
ls -lR /tmp/artifacts/
jq -sc add /tmp/artifacts/*.json > merged.json
echo "DIGESTS_JSON=$(cat merged.json)" >> $GITHUB_OUTPUT
jq '.' merged.json
- name: Sanity check
if: ${{ env.skip != 1 }}
id: check
env:
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }}
run: |
[[ "${{ matrix.VERSION_MAJOR }}" == "9" ]] && EXPECTED=2 || EXPECTED=3
# Ensure we have the correct number of digests
if [[ $(echo ${DIGESTS_JSON} | jq 'length') -ne $EXPECTED ]]; then
echo "Expected $EXPECTED digests, found $(echo ${DIGESTS_JSON} | jq 'length')"
exit 1
fi
# Ensure all versions match
COUNT=$(echo ${DIGESTS_JSON} | jq '[.[] | .version] | unique | length')
if [[ $COUNT -ne 1 ]]; then
echo "Versions do not match across all platforms"
echo ${DIGESTS_JSON} | jq '[.[] | .version]'
exit 1
fi
echo "id=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .id] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "version-id=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .version] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "long-version=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .long_version] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "vendor=$(echo ${DIGESTS_JSON} | jq -r '[.[] | .vendor] | unique | .[0]')" >> $GITHUB_OUTPUT
echo "date=$(date -u +%Y\-%m\-%d\T%H\:%M\:%S\Z)" >> $GITHUB_OUTPUT
- name: Login to registry (docker)
if: ${{ env.skip != 1 }}
uses: docker/login-action@v3
with:
registry: ${{ secrets.IMAGE_REGISTRY }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASSWORD }}
- name: Image Metadata
if: ${{ env.skip != 1 }}
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
id: metadata
with:
tags: |
type=raw,value=latest,enable=${{ matrix.VERSION_MAJOR == env.LATEST_MAJOR }}
type=raw,value=${{ matrix.VERSION_MAJOR }}
type=raw,value=${{ steps.check.outputs.version-id }},enable=${{ matrix.VERSION_MAJOR != '10-kitten' }}
type=raw,value=${{ steps.check.outputs.version-id }}-${{ env.DATE_STAMP }}
type=raw,value=${{ steps.check.outputs.long-version }}
labels: |
redhat.id=${{ steps.check.outputs.id }}
redhat.version-id=${{ steps.check.outputs.version-id }}
version=${{ steps.check.outputs.version-id }}
release=${{ steps.check.outputs.version-id }}
org.opencontainers.image.created=${{ steps.check.outputs.date }}
org.opencontainers.image.source=${{ github.repositoryUrl }}
org.opencontainers.image.title=${{ env.IMAGE_NAME }}
org.opencontainers.image.url=${{ github.event.repository.html_url }}
org.opencontainers.image.version=${{ steps.check.outputs.long-version }}
org.opencontainers.image.vendor=AlmaLinux OS Foundation
org.opencontainers.image.description=AlmaLinux Bootable Container Image
- name: Get a newer podman (from debian trixie)
if: ${{ env.skip != 1 }}
run: |
set -eux
echo 'deb [trusted=yes] https://ftp.debian.org/debian/ trixie main' | sudo tee /etc/apt/sources.list.d/trixie.list
sudo apt update
sudo apt install -y crun/trixie podman/trixie
- name: Create Manifest
if: ${{ env.skip != 1 }}
id: create-manifest
run: |
IMAGE_DEST=${{ secrets.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
podman manifest create ${IMAGE_DEST}
echo "MANIFEST=${IMAGE_DEST}" >> $GITHUB_OUTPUT
- name: Populate Manifest
if: ${{ env.skip != 1 }}
env:
MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }}
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }}
LABELS: ${{ steps.metadata.outputs.labels }}
run: |
IMAGE_DEST=${{ secrets.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
for platform in $(echo $DIGESTS_JSON | jq -r '. | to_entries | .[].key'); do
digest=$(echo $DIGESTS_JSON | jq -r ".[\"$platform\"].digest")
echo "Adding ${IMAGE_DEST}@$digest for $platform"
if [[ "$platform" = */v* ]]; then
podman manifest add $MANIFEST ${IMAGE_DEST}@$digest --arch ${platform%/*} --variant ${platform#*/}
else
podman manifest add $MANIFEST ${IMAGE_DEST}@$digest --arch $platform
fi
done
# Apply the labels to the manifest (separated by newlines)
while IFS= read -r label; do
echo "Applying label $label to manifest"
podman manifest annotate --index --annotation "$label" $MANIFEST
done <<< "$LABELS"
- name: Push Manifest
if: ${{ env.skip != 1 }}
id: push_manifest
env:
MANIFEST: ${{ steps.create-manifest.outputs.MANIFEST }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: |
IMAGE_DEST=${{ secrets.IMAGE_REGISTRY }}/${{ env.IMAGE_NAME }}
while IFS= read -r tag; do
for i in {1..5}; do
podman manifest push --all=false --digestfile=/tmp/digestfile $MANIFEST ${IMAGE_DEST}:$tag && break || sleep $((10*i))
done
[ -f /tmp/digestfile ] || exit 1
done <<< "$TAGS"
DIGEST=$(cat /tmp/digestfile)
echo "digest=$DIGEST" >> $GITHUB_OUTPUT
echo "image=${IMAGE_DEST}" >> $GITHUB_OUTPUT
echo "Pushed manifest to ${IMAGE_DEST} with digest $DIGEST"
podman manifest inspect ${IMAGE_DEST}
- name: Sign Manifest
if: ${{ env.skip != 1 }}
uses: ./.github/actions/sign
with:
image-ref: ${{ steps.push_manifest.outputs.image }}@${{ steps.push_manifest.outputs.digest }}
KMS_KEY_ALIAS: ${{ env.KMS_KEY_ALIAS }}
AWS_ROLE_ARN: ${{ env.AWS_ROLE_ARN }}
AWS_REGION: ${{ env.AWS_REGION }}
- name: Format output for notification
if: ${{ env.skip != 1 }}
id: format
env:
DIGESTS_JSON: ${{ steps.load-outputs.outputs.DIGESTS_JSON }}
TAGS: ${{ steps.metadata.outputs.tags }}
run: |
echo "arches=$(echo "$DIGESTS_JSON" | jq -r '[keys[] | "linux/" + .] | sort | join(", ")')" >> $GITHUB_OUTPUT
# Add two spaces before each tag (starting from the second line) so that it is formatted correctly in the notification
{
echo 'tags<<EOF'
printf "$TAGS" | awk 'NR==1{print; next} {print " " $0}'
echo EOF
} >> $GITHUB_OUTPUT
- name: Notify AlmaLinux Chat
if: ${{ env.skip != 1 }}
uses: mattermost/action-mattermost-notify@master
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MM_WEBHOOK_URL }}
MATTERMOST_CHANNEL: ${{ env.CHAT_CHANNEL }}
MATTERMOST_USERNAME: 'github'
TEXT: |-
**AlmaLinux OS ${{ steps.check.outputs.version-id }}** Bootc Image, build `${{ steps.check.outputs.long-version }}`, built by [GitHub Actions](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})
:almalinux: **${{ steps.push_manifest.outputs.image }}**
- Platforms:
```
${{ steps.format.outputs.arches }}
```
- Tags:
```
${{ steps.format.outputs.tags }}
```