Skip to content

Docker: distribute build across multiple runners #863

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 194 additions & 31 deletions .github/workflows/docker-ghcrio.yml
Original file line number Diff line number Diff line change
@@ -1,71 +1,234 @@
#
# Based on:
#
# Docker docs: Distribute build across multiple runners
# https://docs.docker.com/build/ci/github-actions/multi-platform/#distribute-build-across-multiple-runners
#

name: Upload Docker images to GitHub Container Registry (ghcr.io)

on:
release:
types: [published]
types:
- released

push:
branches: [ master, main ]
tags: [ 'v*' ]
branches:
- master
- main

pull_request:
branches: [ master, main ]
branches:
- master
- main

workflow_dispatch:
inputs:
ref:
description: Git tag to push the image
required: true
type: string

jobs:
docker:
name: Build images
prepare:
name: Prepare
runs-on: ubuntu-latest
outputs:
github_repository: ${{ steps.vars.outputs.github_repository }}
publish_image: ${{ steps.vars.outputs.publish_image }}
semver_value: ${{ steps.vars.outputs.semver_value }}
steps:
- id: vars
name: Prepare outputs
run: |
function prepend() { while read line; do echo "${1}${line}"; done; }
readonly NOTICE_VAR='::notice title=Setting variable::'

github_repository=${{ github.repository }}
echo "github_repository=${github_repository,,}" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"

if [ "${{ github.event_name }}" = "release" ]; then
echo "publish_image=true" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "publish_image=true" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
echo "semver_value=,value=${{ inputs.ref }}" | tee -a $GITHUB_OUTPUT | prepend "$NOTICE_VAR"
fi

build:
name: Build image
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
needs:
- prepare
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up QEMU
if: github.event_name != 'pull_request'
uses: docker/setup-qemu-action@v3
with:
platforms: arm,arm64
cache-image: false
fetch-tags: true

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}

mbuild:
name: Build image
needs:
- prepare
if: github.event_name != 'pull_request'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform:
- platform: linux/amd64
- platform: linux/arm64
qemu: arm64
- platform: linux/arm/v7
qemu: arm
- platform: linux/arm/v6
qemu: arm
steps:
- name: Prepare
id: prepare
run: |
platform=${{ matrix.platform.platform }}
echo "platform_pair=${platform//\//-}" | tee -a $GITHUB_OUTPUT

- name: Check out code
if: github.event_name == 'workflow_dispatch'
uses: actions/checkout@v4
with:
ref: ${{ inputs.ref }}
fetch-tags: true

- name: Check out code
if: github.event_name != 'workflow_dispatch'
uses: actions/checkout@v4
with:
fetch-tags: true

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
# create latest tag for branch events
flavor: |
latest=${{ github.event_name == 'push' && github.ref_type == 'branch' }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.{{minor}}.{{patch}}
env:
DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
if: ${{ matrix.platform.qemu }}
with:
platforms: ${{ matrix.platform.qemu }}
cache-image: false

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
if: needs.prepare.outputs.publish_image
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build
if: github.event_name == 'pull_request'
if: ${{ ! needs.prepare.outputs.publish_image }}
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64
platforms: ${{ matrix.platform.platform }}
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}

- name: Build and push
if: github.event_name != 'pull_request'
if: needs.prepare.outputs.publish_image
uses: docker/build-push-action@v6
id: build
with:
context: .
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
platforms: ${{ matrix.platform.platform }}
labels: ${{ steps.meta.outputs.labels }}
annotations: ${{ steps.meta.outputs.annotations }}
cache-from: type=gha
cache-to: type=gha,mode=max
outputs: type=image,"name=ghcr.io/${{ needs.prepare.outputs.github_repository }}",push-by-digest=true,name-canonical=true,push=true

- name: Export digest
if: needs.prepare.outputs.publish_image
run: |
mkdir -p ${{ runner.temp }}/digests
digest='${{ steps.build.outputs.digest }}'
touch "${{ runner.temp }}/digests/${digest#sha256:}"

- name: Upload digest
if: needs.prepare.outputs.publish_image
uses: actions/upload-artifact@v4
with:
name: digests-${{ steps.prepare.outputs.platform_pair }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
compression-level: 0

merge:
name: Merge images
runs-on: ubuntu-latest
needs:
- prepare
- mbuild
if: needs.prepare.outputs.publish_image
steps:
- name: Download digests
uses: actions/download-artifact@v4
with:
path: ${{ runner.temp }}/digests
pattern: digests-*
merge-multiple: true

- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
flavor: |
latest=${{ github.event_name == 'workflow_dispatch' && 'false' || 'auto' }}
tags: |
type=semver,pattern={{version}}${{ needs.prepare.outputs.semver_value }}
type=semver,pattern={{major}}.{{minor}}${{ needs.prepare.outputs.semver_value }}
type=semver,pattern={{major}}.{{minor}}.{{patch}}${{ needs.prepare.outputs.semver_value }}

- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf 'ghcr.io/${{ needs.prepare.outputs.github_repository }}@sha256:%s ' *)

- name: Inspect image
run: docker buildx imagetools inspect ghcr.io/${{ needs.prepare.outputs.github_repository }}:${{ steps.meta.outputs.version }}


5 changes: 3 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
FROM golang:alpine AS builder
ARG TARGETARCH
ARG GOCACHE=/tmp

RUN apk --no-cache add --update make gcc git musl-dev

USER nobody:nogroup
WORKDIR /usr/local/src/carbonapi
COPY --chown=nobody:nogroup . .
RUN --network=none make clean
RUN --mount=type=cache,id=go-cache,target=/.cache,sharing=locked,uid=65534,gid=65534 make nocairo
RUN --mount=type=cache,id=go-cache,target=/.cache,sharing=locked,uid=65534,gid=65534 <<EOT
RUN make nocairo
RUN <<EOT
if [ "${TARGETARCH:-unknown}" = "amd64" ]; then
make test_nocairo
else
Expand Down
4 changes: 2 additions & 2 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Copyright (c) 2013-2018 Damian Gryski <[email protected]>
2018 Google LLC
Copyright (c) 2013-2018 Damian Gryski <[email protected]> Google LLC
Copyright (c) 2020- Go-Graphite project

All rights reserved.

Expand Down
Loading