Files
OpenShell/.github/workflows/docker-build.yml
dependabot[bot] e9ac0ee691 chore(deps): bump actions/checkout from 7.0.0 to 7.0.1 (#2381)
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0...3d3c42e5aac5ba805825da76410c181273ba90b1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-07-21 12:57:18 +00:00

306 lines
10 KiB
YAML

name: Docker Build
on:
workflow_call:
inputs:
component:
description: "Component to build (gateway, supervisor, cli)"
required: true
type: string
timeout-minutes:
description: "Per-arch Docker image job timeout in minutes"
required: false
type: number
default: 20
push:
description: "Push image to registry"
required: false
type: boolean
default: true
platform:
description: "Target platform(s) for Docker build"
required: false
type: string
default: "linux/amd64,linux/arm64"
runner:
description: "Deprecated; per-arch native runners are selected automatically"
required: false
type: string
default: "linux-amd64-cpu8"
cargo-version:
description: "Pre-computed cargo version (skips internal git-based computation)"
required: false
type: string
default: ""
image-tag:
description: "Image tag base to build/push (defaults to the GitHub SHA)"
required: false
type: string
default: ""
checkout-ref:
description: "Git ref to check out for build inputs (defaults to the workflow SHA)"
required: false
type: string
default: ""
publish-manifest:
description: "Push the bare-SHA manifest. Set false for single-arch branch workflows."
required: false
type: boolean
default: true
env:
MISE_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: read
packages: write
defaults:
run:
shell: bash
jobs:
resolve:
name: Resolve build plan
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.resolve.outputs.matrix }}
platform_count: ${{ steps.resolve.outputs.platform_count }}
arches: ${{ steps.resolve.outputs.arches }}
binary_component: ${{ steps.resolve.outputs.binary_component }}
binary_name: ${{ steps.resolve.outputs.binary_name }}
artifact_prefix: ${{ steps.resolve.outputs.artifact_prefix }}
image_tag_base: ${{ steps.resolve.outputs.image_tag_base }}
features: ${{ steps.resolve.outputs.features }}
has_image: ${{ steps.resolve.outputs.has_image }}
steps:
- name: Resolve component and platform matrix
id: resolve
run: |
set -euo pipefail
component="${{ inputs.component }}"
case "$component" in
gateway)
binary_component=gateway
binary_name=openshell-gateway
features="bundled-z3"
has_image=true
;;
supervisor)
binary_component=sandbox
binary_name=openshell-sandbox
features=""
has_image=true
;;
cli)
binary_component=cli
binary_name=openshell
features=""
has_image=false
;;
*)
echo "unsupported component: $component" >&2
exit 1
;;
esac
image_tag_base="${{ inputs['image-tag'] }}"
if [[ -z "$image_tag_base" ]]; then
image_tag_base="$GITHUB_SHA"
fi
platform_input="${{ inputs.platform }}"
platform_input="${platform_input//[[:space:]]/}"
if [[ -z "$platform_input" ]]; then
echo "platform input must not be empty" >&2
exit 1
fi
IFS=',' read -r -a platforms <<< "$platform_input"
matrix='{"include":['
arches=()
count=0
for platform in "${platforms[@]}"; do
case "$platform" in
linux/amd64)
arch=amd64
runner=linux-amd64-cpu8
;;
linux/arm64)
arch=arm64
runner=linux-arm64-cpu8
;;
*)
echo "unsupported platform: $platform" >&2
echo "supported platforms: linux/amd64, linux/arm64" >&2
exit 1
;;
esac
if [[ $count -gt 0 ]]; then
matrix+=','
fi
matrix+='{"platform":"'"$platform"'","arch":"'"$arch"'","runner":"'"$runner"'"}'
arches+=("$arch")
count=$((count + 1))
done
matrix+=']}'
{
echo "matrix=$matrix"
echo "platform_count=$count"
echo "arches=${arches[*]}"
echo "binary_component=$binary_component"
echo "binary_name=$binary_name"
echo "artifact_prefix=rust-binary-${component}"
echo "image_tag_base=$image_tag_base"
echo "features=$features"
echo "has_image=$has_image"
} >> "$GITHUB_OUTPUT"
rust-binary:
name: Rust ${{ needs.resolve.outputs.binary_component }} (${{ matrix.arch }})
needs: resolve
permissions:
contents: read
packages: read
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.resolve.outputs.matrix) }}
uses: ./.github/workflows/rust-native-build.yml
with:
component: ${{ needs.resolve.outputs.binary_component }}
arch: ${{ matrix.arch }}
cargo-version: ${{ inputs['cargo-version'] }}
image-tag: ${{ needs.resolve.outputs.image_tag_base }}
checkout-ref: ${{ inputs['checkout-ref'] }}
features: ${{ needs.resolve.outputs.features }}
artifact-name: ${{ needs.resolve.outputs.artifact_prefix }}-linux-${{ matrix.arch }}
secrets: inherit
build:
name: Build ${{ inputs.component }} (${{ matrix.arch }})
needs: [resolve, rust-binary]
if: needs.resolve.outputs.has_image == 'true'
runs-on: ${{ matrix.runner }}
timeout-minutes: ${{ inputs['timeout-minutes'] }}
strategy:
fail-fast: false
matrix: ${{ fromJSON(needs.resolve.outputs.matrix) }}
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
options: --privileged
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# Expose the nv-gha-runners buildkitd.toml registry mirror config
# inside the container so setup-buildx can read it.
- /etc/buildkit:/etc/buildkit:ro
env:
IMAGE_TAG: ${{ format('{0}-{1}', needs.resolve.outputs.image_tag_base, matrix.arch) }}
IMAGE_REGISTRY: ghcr.io/nvidia/openshell
DOCKER_PUSH: ${{ inputs.push && '1' || '0' }}
DOCKER_PLATFORM: ${{ matrix.platform }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ inputs['checkout-ref'] || github.sha }}
fetch-depth: 0
- name: Mark workspace safe for git
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
- name: Install tools
run: mise install --locked
- name: Log in to GHCR
if: ${{ inputs.push }}
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
- name: Set up buildx (local driver)
uses: ./.github/actions/setup-buildx
with:
buildkitd-config: /etc/buildkit/buildkitd.toml
- name: Download Rust binary artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: ${{ needs.resolve.outputs.artifact_prefix }}-linux-${{ matrix.arch }}
path: prebuilt-rust-binary
- name: Stage Rust binary in Docker build context
run: |
set -euo pipefail
binary="${{ needs.resolve.outputs.binary_name }}"
download_dir="prebuilt-rust-binary"
stage="deploy/docker/.build/prebuilt-binaries/${{ matrix.arch }}"
found="$(find "$download_dir" -type f -name "$binary" -print -quit)"
if [[ -z "$found" ]]; then
echo "missing downloaded artifact file: $binary" >&2
find "$download_dir" -maxdepth 4 -type f -print >&2 || true
exit 1
fi
mkdir -p "$stage"
install -m 0755 "$found" "$stage/$binary"
ls -lh "$stage/"
- name: Build ${{ inputs.component }} image
env:
DOCKER_BUILDER: openshell
run: |
set -euo pipefail
mise exec -- tasks/scripts/docker-build-image.sh "${{ inputs.component }}" \
--cache-from "type=gha,scope=${{ inputs.component }}-${{ matrix.arch }}" \
--cache-to "type=gha,mode=max,scope=${{ inputs.component }}-${{ matrix.arch }}"
- name: Smoke check ${{ inputs.component }} image
run: |
set -euo pipefail
image="${IMAGE_REGISTRY}/${{ inputs.component }}:${IMAGE_TAG}"
case "${{ inputs.component }}" in
gateway)
output="$(docker run --rm --platform "${{ matrix.platform }}" "$image" --version)"
echo "$output"
grep -q '^openshell-gateway ' <<<"$output"
;;
supervisor)
output="$(docker run --rm --platform "${{ matrix.platform }}" --entrypoint /openshell-sandbox "$image" --version)"
echo "$output"
grep -q '^openshell-sandbox ' <<<"$output"
;;
esac
merge:
name: Merge ${{ inputs.component }} manifest
needs: [resolve, build]
if: ${{ inputs.push && inputs['publish-manifest'] && needs.resolve.outputs.has_image == 'true' }}
runs-on: linux-amd64-cpu8
timeout-minutes: 10
container:
image: ghcr.io/nvidia/openshell/ci:latest
credentials:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
volumes:
- /var/run/docker.sock:/var/run/docker.sock
steps:
- name: Log in to GHCR
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
- name: Create multi-arch manifest
run: |
set -euo pipefail
image="ghcr.io/nvidia/openshell/${{ inputs.component }}"
refs=()
for arch in ${{ needs.resolve.outputs.arches }}; do
refs+=("${image}:${{ needs.resolve.outputs.image_tag_base }}-${arch}")
done
docker buildx imagetools create \
--prefer-index=false \
-t "${image}:${{ needs.resolve.outputs.image_tag_base }}" \
"${refs[@]}"