mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-30 13:35:10 +02:00
We have cases where a workflow can fails in a middle step, if it happens, we were not able to retry the workflow, because of immutable images error. This commit makes the immutable error not blocking, if athe workflow fails, we can retry it without the need to change the image tag.
167 lines
6.3 KiB
YAML
167 lines
6.3 KiB
YAML
name: Build and Push Container Image
|
|
description: Build and push a container image based on the input arguments provided
|
|
|
|
"on":
|
|
workflow_call:
|
|
inputs:
|
|
image_name:
|
|
type: string
|
|
required: true
|
|
description: The suffix for the image name, without the registry and without the repository path.
|
|
context:
|
|
type: string
|
|
required: true
|
|
description: The path to the context to start `docker build` into.
|
|
file:
|
|
type: string
|
|
required: true
|
|
description: The path to the Dockerfile
|
|
target:
|
|
type: string
|
|
required: false
|
|
default: ""
|
|
description: The Dockerfile target stage to build the image for.
|
|
should_push:
|
|
type: boolean
|
|
required: false
|
|
default: false
|
|
description: if the image should be pushed on the docker registry
|
|
docker_user:
|
|
type: string
|
|
required: false
|
|
default: ""
|
|
description: The docker_user ARGUMENT to pass to the build step
|
|
arm64_reuse_amd64_build_arg:
|
|
type: string
|
|
required: false
|
|
default: ""
|
|
description: "Build arg name to pass first amd64 tag to arm64 build (skips arch-independent build steps)"
|
|
|
|
jobs:
|
|
build-and-push:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
- name: Set up QEMU
|
|
uses: docker/setup-qemu-action@v3
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v3
|
|
- name: Login to DockerHub
|
|
if: ${{ inputs.should_push }}
|
|
uses: docker/login-action@v3
|
|
with:
|
|
username: ${{ secrets.DOCKER_HUB_USER }}
|
|
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
|
|
- name: Extract metadata (tags, labels) for Docker
|
|
id: meta
|
|
uses: docker/metadata-action@v5
|
|
with:
|
|
images: ${{ inputs.image_name }}
|
|
- name: Generate platform-specific tags
|
|
id: platform-tags
|
|
run: |
|
|
AMD64_TAGS=$(echo "${{ steps.meta.outputs.tags }}" | sed 's/$/-amd64/')
|
|
ARM64_TAGS=$(echo "${{ steps.meta.outputs.tags }}" | sed 's/$/-arm64/')
|
|
FIRST_AMD64_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -1)-amd64
|
|
FIRST_ARM64_TAG=$(echo "${{ steps.meta.outputs.tags }}" | head -1)-arm64
|
|
{
|
|
echo "amd64<<EOF"
|
|
echo "$AMD64_TAGS"
|
|
echo "EOF"
|
|
echo "arm64<<EOF"
|
|
echo "$ARM64_TAGS"
|
|
echo "EOF"
|
|
echo "amd64_first=$FIRST_AMD64_TAG"
|
|
echo "arm64_first=$FIRST_ARM64_TAG"
|
|
} >> "$GITHUB_OUTPUT"
|
|
# - name: Run trivy scan
|
|
# if: ${{ vars.TRIVY_SCAN_ENABLED }} == 'true'
|
|
# uses: numerique-gouv/action-trivy-cache@main
|
|
# with:
|
|
# docker-build-args: "--target ${{ inputs.target }} -f ${{ inputs.file }}"
|
|
# docker-image-name: "docker.io/${{ inputs.image_name }}:${{ github.sha }}"
|
|
# trivyignores: ./.github/.trivyignore
|
|
- name: Build and push (amd64)
|
|
id: build-amd64
|
|
continue-on-error: true
|
|
if: ${{ inputs.should_push || vars.TRIVY_SCAN_ENABLED != 'true' }}
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ${{ inputs.context }}
|
|
file: ${{ inputs.file }}
|
|
target: ${{ inputs.target }}
|
|
platforms: linux/amd64
|
|
build-args: |
|
|
DOCKER_USER=${{ inputs.docker_user }}
|
|
PUBLISH_AS_MIT=false
|
|
push: ${{ inputs.should_push }}
|
|
provenance: false
|
|
tags: ${{ steps.platform-tags.outputs.amd64 }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
- name: Handle immutable tag error (amd64)
|
|
if: steps.build-amd64.outcome == 'failure'
|
|
run: |
|
|
if docker buildx imagetools inspect "${{ steps.platform-tags.outputs.amd64_first }}" > /dev/null 2>&1; then
|
|
echo "AMD64 tag already exists in immutable registry, treating as success"
|
|
else
|
|
echo "AMD64 build failed"
|
|
exit 1
|
|
fi
|
|
- name: Build and push (arm64)
|
|
id: build-arm64
|
|
continue-on-error: true
|
|
if: ${{ inputs.should_push }}
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: ${{ inputs.context }}
|
|
file: ${{ inputs.file }}
|
|
target: ${{ inputs.target }}
|
|
platforms: linux/arm64
|
|
build-args: |
|
|
DOCKER_USER=${{ inputs.docker_user }}
|
|
PUBLISH_AS_MIT=false
|
|
${{ inputs.arm64_reuse_amd64_build_arg && format('{0}={1}', inputs.arm64_reuse_amd64_build_arg, steps.platform-tags.outputs.amd64_first) || '' }}
|
|
push: ${{ inputs.should_push }}
|
|
provenance: false
|
|
tags: ${{ steps.platform-tags.outputs.arm64 }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
- name: Handle immutable tag error (arm64)
|
|
if: steps.build-arm64.outcome == 'failure'
|
|
run: |
|
|
if docker buildx imagetools inspect "${{ steps.platform-tags.outputs.arm64_first }}" > /dev/null 2>&1; then
|
|
echo "ARM64 tag already exists in immutable registry, treating as success"
|
|
else
|
|
echo "ARM64 build failed"
|
|
exit 1
|
|
fi
|
|
- name: Create multi-arch manifests
|
|
if: ${{ inputs.should_push }}
|
|
id: create-manifest
|
|
run: |
|
|
IMAGE="${{ inputs.image_name }}"
|
|
readarray -t TAGS <<< "${{ steps.meta.outputs.tags }}"
|
|
FIRST_TAG=""
|
|
for tag in "${TAGS[@]}"; do
|
|
[ -z "$tag" ] && continue
|
|
docker buildx imagetools create -t "$tag" \
|
|
"${tag}-amd64" "${tag}-arm64"
|
|
if [ -z "$FIRST_TAG" ]; then
|
|
FIRST_TAG="$tag"
|
|
fi
|
|
done
|
|
# Get the digest of the multi-arch manifest for attestation
|
|
# Note: --format '{{.Manifest.Digest}}' is broken (docker/buildx#1175),
|
|
# so we compute it from the raw manifest JSON instead.
|
|
if [ -n "$FIRST_TAG" ]; then
|
|
DIGEST="sha256:$(docker buildx imagetools inspect "$FIRST_TAG" --raw | sha256sum | awk '{print $1}')"
|
|
echo "digest=$DIGEST" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
- name: Cleanup Docker after build
|
|
if: always()
|
|
run: |
|
|
docker system prune -af
|
|
docker volume prune -f
|