Skip to content
Merged
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
251 changes: 21 additions & 230 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,107 +1,84 @@
name: Build containers
name: Build

on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]

permissions:
contents: read
packages: write

concurrency:
group: build-containers-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
workflow_call:
inputs:
push:
required: true
type: boolean
source_sha:
required: true
type: string

jobs:
build:
if: github.ref_type != 'tag'
name: ${{ matrix.name }} (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- name: cpu
file: Dockerfile
suffix: -cpu
staging_suffix: -cpu-amd64
cache_scope: cpu-amd64
build_args: ""
platform: linux/amd64
runner: ubuntu-latest
- name: cpu
file: Dockerfile
suffix: -cpu
staging_suffix: -cpu-arm64
cache_scope: cpu-arm64
build_args: ""
platform: linux/arm64
runner: ubuntu-24.04-arm
- name: turing
file: Dockerfile.cuda
suffix: -turing
staging_suffix: -turing-amd64
cache_scope: cuda-turing
build_args: CUDA_COMPUTE_CAPS=75
platform: linux/amd64
runner: ubuntu-latest
- name: ampere
file: Dockerfile.cuda
suffix: -ampere
staging_suffix: -ampere-amd64
cache_scope: cuda-ampere
build_args: CUDA_COMPUTE_CAPS=80;86
platform: linux/amd64
runner: ubuntu-latest
- name: ada-lovelace
file: Dockerfile.cuda
suffix: -ada-lovelace
staging_suffix: -ada-lovelace-amd64
cache_scope: cuda-ada-lovelace
build_args: CUDA_COMPUTE_CAPS=89
platform: linux/amd64
runner: ubuntu-latest
- name: hopper
file: Dockerfile.cuda
suffix: -hopper
staging_suffix: -hopper-amd64
cache_scope: cuda-hopper
build_args: CUDA_COMPUTE_CAPS=90
platform: linux/amd64
runner: ubuntu-latest
- name: blackwell
file: Dockerfile.cuda
suffix: -blackwell
staging_suffix: -blackwell-amd64
cache_scope: cuda-blackwell-amd64
build_args: CUDA_COMPUTE_CAPS=100;120
platform: linux/amd64
runner: ubuntu-latest
- name: blackwell
file: Dockerfile.cuda
suffix: -blackwell
staging_suffix: -blackwell-arm64
cache_scope: cuda-blackwell-arm64
build_args: CUDA_COMPUTE_CAPS=121
platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Determine cache permissions
id: cache
env:
TRUSTED_CACHE_WRITER: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
shell: bash
run: |
if [[ "${TRUSTED_CACHE_WRITER}" == "true" ]]; then
echo "write=true" >> "${GITHUB_OUTPUT}"
echo "sccache=on" >> "${GITHUB_OUTPUT}"
else
echo "write=false" >> "${GITHUB_OUTPUT}"
echo "sccache=off" >> "${GITHUB_OUTPUT}"
fi
with:
persist-credentials: false
ref: ${{ inputs.source_sha }}
- name: Free disk space for CUDA
if: matrix.name != 'cpu'
uses: jlumbroso/free-disk-space@ceedf095f4ec1a097402bc6bd80831f2e1a6fde6 # v2.0.0
Expand All @@ -110,228 +87,42 @@ jobs:
swap-storage: false
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Configure sccache credentials
if: steps.cache.outputs.write == 'true'
if: inputs.push
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
script: |
core.exportVariable('ACTIONS_RESULTS_URL', process.env.ACTIONS_RESULTS_URL || '');
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');
- name: Log in to GHCR
if: steps.cache.outputs.write == 'true'
if: inputs.push
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
password: ${{ github.token }}
- name: Docker metadata
id: metadata
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ghcr.io/${{ github.repository }}
flavor: latest=false
tags: |
type=sha,format=short,prefix=,suffix=${{ matrix.staging_suffix }}
- name: Build ${{ matrix.name }} image for ${{ matrix.platform }}
type=raw,value=${{ inputs.source_sha }}${{ matrix.staging_suffix }}
- name: Build
uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0
with:
context: .
file: ${{ matrix.file }}
target: runtime
build-args: |
${{ matrix.build_args }}
SCCACHE_GHA_ENABLED=${{ steps.cache.outputs.sccache }}
SCCACHE_GHA_ENABLED=${{ inputs.push && 'on' || 'off' }}
secrets: |
ACTIONS_RESULTS_URL=${{ env.ACTIONS_RESULTS_URL }}
ACTIONS_RUNTIME_TOKEN=${{ env.ACTIONS_RUNTIME_TOKEN }}
platforms: ${{ matrix.platform }}
push: ${{ github.event_name != 'pull_request' }}
push: ${{ inputs.push }}
tags: ${{ steps.metadata.outputs.tags }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ matrix.name == 'cpu' && format('type=gha,scope={0}', matrix.cache_scope) || format('type=registry,ref=ghcr.io/{0}:buildcache-{1}', github.repository, matrix.cache_scope) }}
cache-to: ${{ matrix.name == 'cpu' && format('type=gha,mode=max,scope={0}', matrix.cache_scope) || (steps.cache.outputs.write == 'true' && format('type=registry,ref=ghcr.io/{0}:buildcache-{1},mode=max', github.repository, matrix.cache_scope) || '') }}

assemble:
if: github.event_name == 'push' && github.ref_type != 'tag'
needs: build
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: cpu
suffix: -cpu
source_suffixes: |-
-cpu-amd64
-cpu-arm64
expected_platforms: |-
linux/amd64
linux/arm64
- name: turing
suffix: -turing
source_suffixes: -turing-amd64
expected_platforms: linux/amd64
- name: ampere
suffix: -ampere
source_suffixes: -ampere-amd64
expected_platforms: linux/amd64
- name: ada-lovelace
suffix: -ada-lovelace
source_suffixes: -ada-lovelace-amd64
expected_platforms: linux/amd64
- name: hopper
suffix: -hopper
source_suffixes: -hopper-amd64
expected_platforms: linux/amd64
- name: blackwell
suffix: -blackwell
source_suffixes: |-
-blackwell-amd64
-blackwell-arm64
expected_platforms: |-
linux/amd64
linux/arm64
steps:
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Log in to GHCR
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: metadata
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ghcr.io/${{ github.repository }}
flavor: latest=false
tags: |
type=sha,format=short,prefix=,suffix=${{ matrix.suffix }},priority=300
type=sha,format=short,prefix=,priority=300,enable=${{ matrix.name == 'cpu' }}
type=raw,value=latest${{ matrix.suffix }}
type=raw,value=latest,enable=${{ matrix.name == 'cpu' }}
- name: Assemble ${{ matrix.name }} image
env:
DESTINATION_TAGS: ${{ steps.metadata.outputs.tags }}
EXPECTED_PLATFORMS: ${{ matrix.expected_platforms }}
SOURCE_SUFFIXES: ${{ matrix.source_suffixes }}
shell: bash
run: |
set -euo pipefail

sources=()
while IFS= read -r source_suffix; do
if [[ -n "${source_suffix}" ]]; then
sources+=("ghcr.io/${GITHUB_REPOSITORY}:${GITHUB_SHA:0:7}${source_suffix}")
fi
done <<< "${SOURCE_SUFFIXES}"

create_args=()
while IFS= read -r destination_tag; do
if [[ -n "${destination_tag}" ]]; then
create_args+=(--tag "${destination_tag}")
fi
done <<< "${DESTINATION_TAGS}"

docker buildx imagetools create "${create_args[@]}" "${sources[@]}"

first_destination="${DESTINATION_TAGS%%$'\n'*}"
expected_platforms="$(printf '%s\n' "${EXPECTED_PLATFORMS}" | sort)"
actual_platforms="$(
docker buildx imagetools inspect "${first_destination}" --raw |
jq -r '.manifests[].platform | select(.architecture != "unknown") | "\(.os)/\(.architecture)"' |
sort -u
)"
if [[ "${actual_platforms}" != "${expected_platforms}" ]]; then
echo "Platform mismatch for ${first_destination}" >&2
echo "Expected:" >&2
printf '%s\n' "${expected_platforms}" >&2
echo "Actual:" >&2
printf '%s\n' "${actual_platforms}" >&2
exit 1
fi

promote:
if: github.ref_type == 'tag'
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: cpu
suffix: -cpu
- name: turing
suffix: -turing
- name: ampere
suffix: -ampere
- name: ada-lovelace
suffix: -ada-lovelace
- name: hopper
suffix: -hopper
- name: blackwell
suffix: -blackwell
steps:
- uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1
- name: Log in to GHCR
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker metadata
id: metadata
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: ghcr.io/${{ github.repository }}
flavor: latest=false
tags: |
type=semver,pattern={{version}},suffix=${{ matrix.suffix }}
type=semver,pattern={{version}},enable=${{ matrix.name == 'cpu' }}
type=raw,value=latest${{ matrix.suffix }}
type=raw,value=latest,enable=${{ matrix.name == 'cpu' }}
- name: Promote ${{ matrix.name }} image
env:
DESTINATION_TAGS: ${{ steps.metadata.outputs.tags }}
shell: bash
run: |
set -euo pipefail

source_tag="ghcr.io/${GITHUB_REPOSITORY}:${GITHUB_SHA:0:7}${{ matrix.suffix }}"
source_digest=""

for attempt in {1..60}; do
if source_digest="$(docker buildx imagetools inspect "${source_tag}" --format '{{json .Manifest}}' 2>/dev/null | jq -r '.digest')" \
&& [[ "${source_digest}" == sha256:* ]]; then
break
fi

if [[ "${attempt}" -eq 60 ]]; then
echo "Source image ${source_tag} was not published within 20 minutes" >&2
exit 1
fi

echo "Waiting for ${source_tag} to be published (attempt ${attempt}/60)"
sleep 20
done

immutable_source="ghcr.io/${GITHUB_REPOSITORY}@${source_digest}"
create_args=()
while IFS= read -r destination_tag; do
if [[ -n "${destination_tag}" ]]; then
create_args+=(--tag "${destination_tag}")
fi
done <<< "${DESTINATION_TAGS}"

docker buildx imagetools create "${create_args[@]}" "${immutable_source}"

while IFS= read -r destination_tag; do
if [[ -z "${destination_tag}" ]]; then
continue
fi

destination_digest="$(docker buildx imagetools inspect "${destination_tag}" --format '{{json .Manifest}}' | jq -r '.digest')"
if [[ "${destination_digest}" != "${source_digest}" ]]; then
echo "Digest mismatch for ${destination_tag}: expected ${source_digest}, got ${destination_digest}" >&2
exit 1
fi
done <<< "${DESTINATION_TAGS}"
cache-to: ${{ matrix.name == 'cpu' && format('type=gha,mode=max,scope={0}', matrix.cache_scope) || (inputs.push && format('type=registry,ref=ghcr.io/{0}:buildcache-{1},mode=max', github.repository, matrix.cache_scope) || '') }}
Loading
Loading