Skip to content
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
57 changes: 48 additions & 9 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ on:
- ts-app
- vite
- xfce-vnc
architectures:
description: "Guest architectures to build"
type: choice
default: "amd64"
options:
- amd64
- arm64
- amd64,arm64

env:
REGISTRY: ghcr.io
Expand Down Expand Up @@ -137,12 +145,13 @@ jobs:

sandbox-api-build-arm64:
needs: check-changes
runs-on: ubuntu-latest
# Native arm64 runner: the binary is cgo/static-pie linked, so it cannot be
# cross-compiled from the amd64 image.
runs-on: ubuntu-24.04-arm
permissions:
contents: read
packages: write
if: needs.check-changes.outputs.sandbox-api-changed == 'true'
continue-on-error: true
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand Down Expand Up @@ -204,7 +213,7 @@ jobs:
retention-days: 1

sandbox-api:
needs: [check-changes, sandbox-api-build]
needs: [check-changes, sandbox-api-build, sandbox-api-build-arm64]
Comment thread
cursor[bot] marked this conversation as resolved.
runs-on: ubuntu-latest
permissions:
contents: read
Expand Down Expand Up @@ -253,7 +262,21 @@ jobs:
if: always() && (needs.check-changes.result == 'success') && (github.ref_name != 'main' || (github.event_name == 'workflow_dispatch' && inputs.sandbox != ''))
outputs:
sandboxes: ${{ steps.retrieve-sandbox.outputs.sandboxes }}
architectures: ${{ steps.retrieve-architectures.outputs.architectures }}
exclusions: ${{ steps.retrieve-architectures.outputs.exclusions }}
steps:
- name: Retrieve architectures
id: retrieve-architectures
shell: bash
run: |
# amd64 is always built; arm64 is opt-in through the dispatch input.
ARCHS="${{ inputs.architectures }}"
ARCHS="${ARCHS:-amd64}"
echo "architectures=$(jq -cR 'split(",")' <<< "$ARCHS")" >> $GITHUB_OUTPUT
# Images that cannot be built for arm64 yet: the vibekit CLI base
# images are published amd64-only, and jupyter-server pulls python
# packages that have no aarch64 wheels.
echo "exclusions=$(jq -cn '["jupyter-server","vibekit-claude","vibekit-codex","vibekit-gemini","vibekit-grok","vibekit-opencode"] | map({sandbox: ., arch: "arm64"})')" >> $GITHUB_OUTPUT
- name: Checkout code
uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -319,16 +342,22 @@ jobs:
fi

build-ghcr-hub:
runs-on: ubuntu-latest
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
needs:
- check-changes
- generate-matrix
- sandbox-api
# Run after sandbox-api completes (if it runs) or is skipped. Skip automatic main pushes, but allow manual dispatch for a selected sandbox.
if: always() && (github.ref_name != 'main' || (github.event_name == 'workflow_dispatch' && inputs.sandbox != '')) && needs.generate-matrix.outputs.sandboxes != '[]' && (needs.sandbox-api.result == 'success' || needs.sandbox-api.result == 'skipped')
# Run after sandbox-api succeeds, or when it was never meant to run (no
# sandbox-api change). A skipped sandbox-api caused by a failed arch build
# must not let the hub images ship against a stale sandbox-api.
# Skip automatic main pushes, but allow manual dispatch for a selected sandbox.
if: always() && (github.ref_name != 'main' || (github.event_name == 'workflow_dispatch' && inputs.sandbox != '')) && needs.generate-matrix.outputs.sandboxes != '[]' && (needs.sandbox-api.result == 'success' || (needs.sandbox-api.result == 'skipped' && needs.check-changes.outputs.sandbox-api-changed != 'true'))
strategy:
fail-fast: false
matrix:
sandbox: ${{ fromJson(needs.generate-matrix.outputs.sandboxes )}}
arch: ${{ fromJson(needs.generate-matrix.outputs.architectures )}}
exclude: ${{ fromJson(needs.generate-matrix.outputs.exclusions )}}
permissions:
contents: read
packages: write
Expand All @@ -351,6 +380,10 @@ jobs:
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.sandbox }}
# arm64 images are published under an -arm64 suffixed tag so both
# architectures of the same commit coexist in the registry.
flavor: |
suffix=${{ matrix.arch == 'arm64' && '-arm64' || '' }},onlatest=true
tags: |
type=ref,event=branch
type=sha,prefix={{branch}}-,enable=${{ !startsWith(github.ref, 'refs/tags/') }}
Expand All @@ -363,14 +396,14 @@ jobs:
with:
context: .
file: ./hub/${{ matrix.sandbox }}/Dockerfile
platforms: linux/amd64
platforms: linux/${{ matrix.arch }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
SANDBOX_VERSION=${{ startsWith(github.ref, 'refs/tags/') && 'latest' || github.ref_name == 'develop' && 'develop' || 'latest' }}
cache-from: type=gha
cache-to: type=gha,mode=max
cache-from: type=gha,scope=${{ matrix.sandbox }}-${{ matrix.arch }}
cache-to: type=gha,scope=${{ matrix.sandbox }}-${{ matrix.arch }},mode=max

build-s3-hub:
runs-on: codebuild-sandbox-${{ github.run_id }}-${{ github.run_attempt }}
Expand All @@ -390,6 +423,8 @@ jobs:
fail-fast: false
matrix:
sandbox: ${{ fromJson(needs.generate-matrix.outputs.sandboxes )}}
arch: ${{ fromJson(needs.generate-matrix.outputs.architectures )}}
Comment thread
cursor[bot] marked this conversation as resolved.
exclude: ${{ fromJson(needs.generate-matrix.outputs.exclusions )}}
steps:
- name: Checkout code
uses: actions/checkout@v4
Expand Down Expand Up @@ -417,6 +452,7 @@ jobs:
env:
SANDBOX_NAME: ${{ matrix.sandbox }}
IMAGE_TAG: ${{ steps.image-tag.outputs.tag }}
ARCH: ${{ matrix.arch }}
BL_TYPE: sandbox
BL_ENV: ${{ env.BL_ENV }}
SRC_REGISTRY: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.sandbox }}
Expand All @@ -433,6 +469,9 @@ jobs:
chmod +x ./scripts/mk3-build.sh
./scripts/mk3-build.sh
- name: Publish sandbox
# The hub store entry points at the amd64 image; arm64 artifacts are
# only registered as images (arch suffixed tag).
if: matrix.arch == 'amd64'
env:
SANDBOX_NAME: ${{ matrix.sandbox }}
TAG: latest # We want to display latest in UI, controlplane will automaticly use the latest tag
Expand Down
5 changes: 4 additions & 1 deletion hub/benchmark/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
ARG SANDBOX_VERSION=latest
FROM ghcr.io/blaxel-ai/sandbox:${SANDBOX_VERSION} AS sandbox-api

FROM alpine:3.19

COPY --from=ghcr.io/blaxel-ai/sandbox:latest /sandbox-api /usr/local/bin/sandbox-api
COPY --from=sandbox-api /sandbox-api /usr/local/bin/sandbox-api

EXPOSE 8080

Expand Down
5 changes: 4 additions & 1 deletion hub/docker-in-sandbox/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
ARG SANDBOX_VERSION=latest
FROM ghcr.io/blaxel-ai/sandbox:${SANDBOX_VERSION} AS sandbox-api

FROM alpine:3.21

RUN apk update && apk add --no-cache \
Expand Down Expand Up @@ -25,7 +28,7 @@ RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master

WORKDIR /app

COPY --from=ghcr.io/blaxel-ai/sandbox:latest /sandbox-api /usr/local/bin/sandbox-api
COPY --from=sandbox-api /sandbox-api /usr/local/bin/sandbox-api

COPY hub/docker-in-sandbox/example /app/example

Expand Down
38 changes: 29 additions & 9 deletions scripts/mk3-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -86,18 +86,36 @@ BL_TYPE="${BL_TYPE:-sandbox}"
LOG_LEVEL="${LOG_LEVEL:-debug}"
BASE_IMAGE_TAG="${BASE_IMAGE_TAG:-latest}"

# Guest architecture of the sandbox being built (amd64 or arm64).
ARCH="${ARCH:-amd64}"
case "$ARCH" in
amd64|arm64) ;;
*) echo "Error: unsupported ARCH '$ARCH' (expected amd64 or arm64)"; exit 1 ;;
esac
PLATFORM="linux/$ARCH"

# arm64 artifacts live next to the amd64 ones, under an arch suffixed tag, so
# both architectures of the same commit can coexist in S3 and in the registry.
ARCH_SUFFIX=""
if [ "$ARCH" != "amd64" ]; then
ARCH_SUFFIX="-$ARCH"
fi
ARTIFACT_TAG="${IMAGE_TAG}${ARCH_SUFFIX}"

echo "Starting mk3 build process for sandbox..."
echo "Sandbox Name: $SANDBOX_NAME"
echo "Image Tag: $IMAGE_TAG"
echo "BL Environment: $BL_ENV"
echo "BL Type: $BL_TYPE"
echo "Build ID: $BUILD_ID"
echo "Base Image Tag: $BASE_IMAGE_TAG"
echo "Platform: $PLATFORM"
echo "Artifact Tag: $ARTIFACT_TAG"
echo "Batch Job Queue: $BATCH_JOB_QUEUE"
echo "Batch Job Definition: $BATCH_JOB_DEFINITION"
echo "Batch Region: $BATCH_REGION"

OUTPUT_S3="s3://$IMAGE_BUCKET_MK3/blaxel/sbx/$SANDBOX_NAME/$IMAGE_TAG"
OUTPUT_S3="s3://$IMAGE_BUCKET_MK3/blaxel/sbx/$SANDBOX_NAME/$ARTIFACT_TAG"
echo "Target S3 location: $OUTPUT_S3"

# Check if template.json has build.slim set to false
Expand All @@ -113,9 +131,10 @@ fi

# Build container overrides with environment variables and command for the Batch job.
# Pass --image as CLI arg since metamorph may not read IMAGE env var (INPUT_S3 flow works, IMAGE flow fails).
IMAGE_REF="$SRC_REGISTRY:$BASE_IMAGE_TAG"
IMAGE_REF="$SRC_REGISTRY:${BASE_IMAGE_TAG}${ARCH_SUFFIX}"
CONTAINER_OVERRIDES=$(jq -n \
--arg image "$IMAGE_REF" \
--arg platform "$PLATFORM" \
--arg otel_enabled "false" \
--arg bl_env "$BL_ENV" \
--arg output_s3 "$OUTPUT_S3" \
Expand All @@ -128,7 +147,7 @@ CONTAINER_OVERRIDES=$(jq -n \
--arg depot_project_id "$DEPOT_PROJECT_ID" \
--arg no_slim "$NO_SLIM" \
'{
command: ["--image", $image],
command: ["--image", $image, "--platform", $platform],
environment: [
{name: "OTEL_ENABLED", value: $otel_enabled},
{name: "BL_ENV", value: $bl_env},
Expand All @@ -141,11 +160,12 @@ CONTAINER_OVERRIDES=$(jq -n \
{name: "LOG_LEVEL", value: $log_level},
{name: "DEPOT_PROJECT_ID", value: $depot_project_id},
{name: "IMAGE", value: $image},
{name: "NO_SLIM", value: $no_slim}
{name: "NO_SLIM", value: $no_slim},
{name: "PLATFORM", value: $platform}
]
}')

JOB_NAME="mk3-build-${SANDBOX_NAME}-${IMAGE_TAG//[^a-zA-Z0-9-]/-}-$(date +%s)"
JOB_NAME="mk3-build-${SANDBOX_NAME}-${ARTIFACT_TAG//[^a-zA-Z0-9-]/-}-$(date +%s)"

echo "Submitting Batch job..."
JOB_SUBMIT=$(aws batch submit-job \
Expand Down Expand Up @@ -227,10 +247,10 @@ API_PAYLOAD=$(jq -n \
--arg registry "$REGISTRY_URL" \
--arg workspace "$WORKSPACE" \
--arg repository "$SANDBOX_NAME" \
--arg mk3 "blaxel/blaxel/sbx/$SANDBOX_NAME:$IMAGE_TAG" \
--arg tag "$IMAGE_TAG" \
--arg mk3 "blaxel/blaxel/sbx/$SANDBOX_NAME:$ARTIFACT_TAG" \
--arg tag "$ARTIFACT_TAG" \
--arg registry_type "$REGISTRY_TYPE" \
--arg original "sbx/$SANDBOX_NAME:$IMAGE_TAG" \
--arg original "sbx/$SANDBOX_NAME:$ARTIFACT_TAG" \
--arg region "$BATCH_REGION" \
--arg bucket "$IMAGE_BUCKET_MK3" \
'{
Expand All @@ -249,7 +269,7 @@ echo "Calling Blaxel API to register image..."
echo "URL: $BL_API_URL/admin/images"
echo "Workspace: $WORKSPACE"
echo "Repository: $SANDBOX_NAME"
echo "Tag: $IMAGE_TAG"
echo "Tag: $ARTIFACT_TAG"
echo "Payload: $API_PAYLOAD"

# Make the API call
Expand Down