Skip to content

Build multi-arch docker images and publish on DockerHub #922

Build multi-arch docker images and publish on DockerHub

Build multi-arch docker images and publish on DockerHub #922

Workflow file for this run

name: Build multi-arch docker images and publish on DockerHub
# Control when actions will run
on:
workflow_dispatch:
inputs:
logLevel:
type: choice
description: Log level
required: false
default: info
options:
- info
- debug
platform:
type: choice
description: 'Platform to build'
required: false
default: all
# Limit available choices for manual runs
options:
- all
- linux/amd64
- linux/arm64
- linux/arm/v7
push:
branches:
- main
- develop
tags:
- 'v*'
paths-ignore:
- '**.md'
#- '.github/workflows/**'
- 'docs/**'
pull_request:
branches:
- main
paths-ignore:
- '**.md'
#- '.github/workflows/**'
- 'docs/**'
schedule:
- cron: '0 2 * * *' # everyday at 2am
# Set environment variables
env:
DOCKERHUB_SLUG: ${{ secrets.DOCKERHUB_USERNAME }}/mopidy
# A workflow run is made up of one or more jobs that can run sequentially or in parallel (matrix)
jobs:
# Create a matrix of platforms depending on the input from workflow_dispatch or
determine_platform:
name: Determine Platform
runs-on: ubuntu-latest
outputs:
platforms: ${{ steps.set-matrix.outputs.platforms }}
steps:
- id: set-matrix
run: |
ALL_PLATFORMS=$(cat <<-END
["linux/amd64","linux/arm64","linux/arm/v7"]
END
)
if [ -z "${{ github.event.inputs.platform }}" ] || [ "${{ github.event.inputs.platform }}" == "all" ]; then
echo "PLATFORMS=${ALL_PLATFORMS}" >> $GITHUB_OUTPUT
else
SINGLE_PLATFORM="[\"${{ github.event.inputs.platform }}\"]"
echo "PLATFORMS=${SINGLE_PLATFORM}" >> $GITHUB_OUTPUT
fi
shell: bash
# Build docker image for each platform on a dedicated runner using the matrix strategy and push the image by digest
# see https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
build:
name: Build
needs: determine_platform
# The type of runner that the job will run on
runs-on: ubuntu-latest
strategy:
fail-fast: false
# List of platforms on which the job will be run in parallel.
matrix:
platform: ${{ fromJson(needs.determine_platform.outputs.platforms) }}
image:
- latest
- develop
- release
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Overwrite platform matrix value for manual runs with a selected platform
- name: Set platform matrix for manual runs with a selected platform
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.platform != 'all' }}
run: echo "PLATFORM_MATRIX=[\"${{ github.event.inputs.platform }}\"]" >> $GITHUB_ENV
# Store current platform from matrix as variable $PLATFORM_PAIR (with "/" replaced by "-")
- name: Prepare
run: |
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
# Github action to provide runner with OS information
- name: Get GitHub Actions runner OS information
uses: kenchan0130/actions-system-info@master
id: system-info
- name: Output System information
run: |
OUTPUTS=(
"CPU Core: ${{ steps.system-info.outputs.cpu-core }}"
"CPU Model: ${{ steps.system-info.outputs.cpu-model }}"
"Hostname: ${{ steps.system-info.outputs.hostname }}"
"Kernel release: ${{ steps.system-info.outputs.kernel-release }}"
"Kernel version: ${{ steps.system-info.outputs.kernel-version }}"
"Name: ${{ steps.system-info.outputs.name }}"
"Platform: ${{ steps.system-info.outputs.platform }}"
"Release: ${{ steps.system-info.outputs.release }}"
"Total memory bytes: ${{ steps.system-info.outputs.totalmem }}"
)
for OUTPUT in "${OUTPUTS[@]}";do
echo "${OUTPUT}"
done
echo "Disk Space:"
df -h
# # GitHub Action to free disk space on Ubuntu action runners.
# - name: Free Disk Space (Ubuntu)
# uses: jlumbroso/free-disk-space@main
# Github Action to get branch or tag information without the /ref/* prefix
- name: Get branch names
id: branch-name
uses: tj-actions/branch-names@v6
# Github Action to check-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout
uses: actions/checkout@v4.1.1
# GitHub Action to install QEMU static binaries (optional for more platform options in buildx)
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
# GitHub Action to set up Docker Buildx.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-flags: ${{ github.event.inputs.logLevel == 'debug' && '--debug' || '' }}
# Hack to fix Errors on arm/v7 and linux/386
# Work around for qemu bug on 32bit systems caused during rust compilation (https://github.com/JonasAlfredsson/docker-on-tmpfs?tab=readme-ov-file)
# - "Value too large for defined data type;" https://github.com/crazy-max/ghaction-docker-buildx/issues/172
# - "object not found - no match for id (SOME_HASH)" on git update
- name: Run Docker on tmpfs
if: matrix.platform == 'linux/arm/v7' || matrix.platform == 'linux/i386'
uses: JonasAlfredsson/docker-on-tmpfs@v1
with:
tmpfs_size: 10
swap_size: 10
swap_location: '/mnt/swapfile'
# GitHub Action to extract metadata (tags, labels) for Docker.
- name: Docker meta
id: docker_meta
uses: docker/metadata-action@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
images: ${{ env.DOCKERHUB_SLUG }}
labels: |
org.opencontainers.image.title=${{ env.DOCKERHUB_SLUG }}
org.opencontainers.image.description='Mopidy music server with Iris Web-UI, Spotify support and many other extensions.'
org.opencontainers.image.vendor=${{ secrets.DOCKERHUB_USERNAME }}
# GitHub Action to login to DockerHub.
- name: Login to DockerHub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# GitHub Action to build and push Docker image by digest (image identifier)
# - Use Docker-Image-Cache from GitHub Actions (gha) and cache all data (max)
- name: Build and push by digest
id: docker_build
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: ${{ matrix.platform }}
provenance: false
labels: ${{ steps.docker_meta.outputs.labels }}
tags: ${{ env.DOCKERHUB_SLUG }}
#cache-from: type=gha,scope=${{ github.repository }}-${{ github.ref_name }}-${{ matrix.platform }}-${{ matrix.image }}
#cache-to: type=gha,mode=max,scope=${{ github.repository }}-${{ github.ref_name }}-${{ matrix.platform }}-${{ matrix.image }}
outputs: type=image,name=${{ env.DOCKERHUB_SLUG }},push-by-digest=true,name-canonical=true,push=true
build-args: |
IMG_VERSION=${{ matrix.image }}
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
VCS_REF=${GITHUB_SHA::8}
# Export digest and store in GitHub artefact storage for later use in other jobs
- name: Export digest
run: |
mkdir -p /tmp/digests/${{ matrix.image }}
digest="${{ steps.docker_build.outputs.digest }}"
touch "/tmp/digests/${{ matrix.image }}/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-${{ matrix.image }}-${{ env.PLATFORM_PAIR }}
path: /tmp/digests/${{ matrix.image }}/*
if-no-files-found: error
retention-days: 1
- name: Clear digest
run: |
rm -rf /tmp/digests/${{ matrix.image }}
# This merge job will catch all digests from the build jobs, create a manifest list and push it to Docker Hub
merge:
if: ${{ github.event_name != 'pull_request' }}
name: Merge Docker manifests
strategy:
fail-fast: false
matrix:
image:
- latest
- develop
- release
runs-on: ubuntu-latest
needs:
- build
steps:
# Download digests from build jobs
- name: Download digests
uses: actions/download-artifact@v4
with:
path: /tmp/digests/${{ matrix.image }}
pattern: digests-${{ matrix.image }}-*
merge-multiple: true
# GitHub Action to set up Docker Buildx.
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# GitHub Action to extract metadata (tags, labels) for Docker.
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.DOCKERHUB_SLUG }}
tags: |
type=raw,value=${{ matrix.image }},enable=${{ github.ref_name == github.event.repository.default_branch }}
type=raw,value=dev_${{ matrix.image }},enable=${{ github.ref == format('refs/heads/{0}', 'develop') }}
type=raw,value=test_${{ matrix.image }},enable=${{ github.ref_name != github.event.repository.default_branch && github.ref != format('refs/heads/{0}', 'develop') }}
# GitHub Action to login to DockerHub.
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
# Create and push manifest list
- name: Create manifest list and push
working-directory: /tmp/digests/${{ matrix.image }}
# Extract all tags from JSON-Query $DOCKER_METADATA_OUTPUT_JSON: -t tag1 -t tag2 ...
# Add ${{ env.DOCKERHUB_SLUG }}@sha256:digest1 sha256:digest2 ...
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}') \
$(printf '${{ env.DOCKERHUB_SLUG }}@sha256:%s ' *)
# GitHub Action to build and push Docker images with Buildx.
- name: Inspect image
run: |
docker buildx imagetools inspect ${{ env.DOCKERHUB_SLUG }}:${{ steps.meta.outputs.version }}