Skip to content

Include amd64 Docker image suffix and build it last #626

Include amd64 Docker image suffix and build it last

Include amd64 Docker image suffix and build it last #626

Workflow file for this run

name: Docker build and push
# limit concurrency
# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#examples-using-concurrency-and-the-default-behavior
concurrency: docker_mmgis_main
on:
push:
# Only activate for `master` branch
branches:
- master
- development
# Plus for all tags
tags:
- "*"
# Plus for any pull-requests
pull_request:
branches:
- master
- development
# And for any final releases
release:
types: [published]
env:
# Will be "NASA-AMMOS/MMGIS" for the main repo, for forks "user-name-of-fork/MMGIS"
# For generating the tag, all will be converted to lowercase
IMAGE_SLUG: ${{ github.repository }}
jobs:
# Generate shared tags for both architectures
# The image tag pattern is:
# for pull-requests: <PATCH_VERSION>-<DATE>-<PR_NUMBER>, eg: 1.35.2-20210125-25
# for tags: <TAG>
# for `master` branch: latest,<PATCH_VERSION>-latest,<MINOR_VERSION>-latest,<MAJOR_VERSION>-latest,<PATCH_VERSION>-<DATE>-<SHA>
# for `development` branch: development,<MAJOR_VERSION>-development,<PATCH_VERSION>-<DATE>-<SHA>
# for releases: release,<PATCH_VERSION>-release,<MINOR_VERSION>-release,<MAJOR_VERSION>-release,<PATCH_VERSION>-<DATE>-<SHA>
# Version is parsed from package.json
generate-tags:
runs-on: ubuntu-latest
if: github.event_name == 'push' || github.event_name == 'pull_request' || github.event_name == 'release'
outputs:
tags: ${{ steps.generate.outputs.TAGS }}
image-id: ${{ steps.generate.outputs.IMAGE_ID }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Generate tags
id: generate
run: |
IMAGE_ID=$(echo "ghcr.io/$IMAGE_SLUG" | tr '[A-Z]' '[a-z]')
PATCH_VERSION=$(jq .version -r ./package.json)
BRANCH_OR_TAG=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
TAGS=""
if [ "${{ github.event_name }}" == "pull_request" ]; then
PR_NUMBER=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\)/merge,\1,')
TAGS="$PATCH_VERSION-$(date +%Y%m%d)-$PR_NUMBER"
elif [[ "$BRANCH_OR_TAG" == "master" ]]; then
TAGS="latest $PATCH_VERSION-latest"
elif [[ "$BRANCH_OR_TAG" == "development" ]]; then
TAGS="development"
elif [[ "${{ github.ref }}" == "refs/tags/"* ]]; then
TAGS="$BRANCH_OR_TAG"
fi
echo "Generated tags: $TAGS"
echo "TAGS=$TAGS" >> $GITHUB_OUTPUT
echo "IMAGE_ID=$IMAGE_ID" >> $GITHUB_OUTPUT
# Build and push AMD64 image on x64 runner
build-amd64:
needs: generate-tags
runs-on: ubuntu-latest # x64 runner for native AMD64 builds
outputs: # Define the job output for the digest
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Login to GHCR
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker buildx build and push (AMD64)
run: |
IMAGE_ID=${{ needs.generate-tags.outputs.image-id }}
# This pushes the image referenced only by its digest, keeping the registry clean.
docker buildx build \
--platform linux/amd64 \
--output "type=image,name=$IMAGE_ID,push=true" \
--metadata-file metadata-amd64.json \
.
# Extracts the unique digest from the build metadata for the final manifest.
DIGEST=$(jq -r '.["containerimage.digest"]' metadata-amd64.json)
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
# Build and push ARM64 image on ARM64 runner
build-arm64:
needs: generate-tags
runs-on: ubuntu-24.04-arm # ARM64 runner for native ARM64 builds
outputs: # Define the job output for the digest
digest: ${{ steps.build.outputs.digest }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
- name: Login to GHCR
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker buildx build and push (ARM64)
run: |
IMAGE_ID=${{ needs.generate-tags.outputs.image-id }}
# Pushes the arm64 image by digest.
docker buildx build \
--platform linux/arm64 \
--output "type=image,name=$IMAGE_ID,push=true" \
--metadata-file metadata-arm64.json \
.
# Extracts the unique digest.
DIGEST=$(jq -r '.["containerimage.digest"]' metadata-arm64.json)
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
# Create and push multi-arch manifest
publish-manifest:
needs: [build-amd64, build-arm64] # Runs after both builds are successful
runs-on: ubuntu-latest
steps:
- name: Login to GHCR
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create and push manifest list using digests
run: |
IMAGE_ID=${{ needs.generate-tags.outputs.image-id }}
AMD64_DIGEST="${{ needs.build-amd64.outputs.digest }}"
ARM64_DIGEST="${{ needs.build-arm64.outputs.digest }}"
# Loops through the tags generated in the first job (e.g., "latest", "1.2.3")
for tag in ${{ needs.generate-tags.outputs.tags }}; do
echo "Creating and pushing manifest for tag: $tag"
# Creates a manifest list with pointers to the specific arch images.
docker manifest create $IMAGE_ID:$tag \
--amend $IMAGE_ID@$AMD64_DIGEST \
--amend $IMAGE_ID@$ARM64_DIGEST
# Pushes the final, user-facing multi-arch tag to the registry.
docker manifest push $IMAGE_ID:$tag
done