Skip to content
This repository was archived by the owner on Jul 23, 2025. It is now read-only.

Commit 40e3d4f

Browse files
committed
feat: Publish arm64 images as well
This adjusts the publish-dockers workflow to also publish arm64 images. It attempts to build all templates in both amd64 and arm64, but allows the arm64 builds to fail since some of our templates (specifically meta-reference-gpu) fail to build on arm64. After building and pushing the architecture-specific images, it pushes a manifest list for all the architectures we built to the default image location. Before, we'd end up with images like `distribution-remote-vllm` that contained only the amd64 image. Now, `distribution-remote-vllm` contains a manifest list that contains both amd64 and arm64 images. We still publish single manifest, architecture-specific images at `distribution-remote-vllm-amd64` and `distribution-remote-vllm-arm64` for really old clients, someone that specifically needs an arch-specific image, and because it's the simplest way to run these GitHub workflows as individual steps where we separate arch-specific image building from manifest list publishing in GitHub Actions. Signed-off-by: Ben Browning <[email protected]>
1 parent b2c94c1 commit 40e3d4f

File tree

6 files changed

+225
-43
lines changed

6 files changed

+225
-43
lines changed

.github/workflows/publish-dockers.yaml

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,14 @@ on:
1111
description: 'Optional comma-separated templates to publish'
1212
required: false
1313
type: string
14+
dockerhub_organization:
15+
description: 'DockerHub organization'
16+
required: false
17+
type: string
18+
default: llamastack
1419

1520
jobs:
16-
publish-docker-images:
21+
publish-docker-images-amd64:
1722
runs-on: ubuntu-latest
1823
steps:
1924
- uses: actions/checkout@v4
@@ -23,3 +28,34 @@ jobs:
2328
templates: ${{ inputs.templates }}
2429
dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }}
2530
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
31+
dockerhub_organization: ${{ inputs.dockerhub_organization }}
32+
arch: amd64
33+
34+
publish-docker-images-arm64:
35+
runs-on: ubuntu-24.04-arm
36+
steps:
37+
- uses: actions/checkout@v4
38+
- uses: ./actions/publish-dockers
39+
with:
40+
version: ${{ inputs.version }}
41+
templates: ${{ inputs.templates }}
42+
dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }}
43+
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
44+
dockerhub_organization: ${{ inputs.dockerhub_organization }}
45+
continue_on_error: true
46+
arch: arm64
47+
48+
publish-docker-manifest-lists:
49+
needs:
50+
- publish-docker-images-amd64
51+
- publish-docker-images-arm64
52+
runs-on: ubuntu-latest
53+
steps:
54+
- uses: actions/checkout@v4
55+
- uses: ./actions/publish-docker-manifest-lists
56+
with:
57+
version: ${{ inputs.version }}
58+
templates: ${{ inputs.templates }}
59+
dockerhub_username: ${{ secrets.DOCKERHUB_USERNAME }}
60+
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
61+
dockerhub_organization: ${{ inputs.dockerhub_organization }}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: 'Publish Docker Manifest Lists'
2+
description: 'Publish Docker manifest lists; architecture-specific images must already be published'
3+
inputs:
4+
version:
5+
description: 'Version number (e.g. 0.1.1rc2, 0.1.1.dev20250201)'
6+
required: true
7+
type: string
8+
templates:
9+
description: 'Optional comma-separated templates to publish'
10+
required: false
11+
type: string
12+
dockerhub_username:
13+
description: 'DockerHub username'
14+
required: true
15+
type: string
16+
dockerhub_token:
17+
description: 'DockerHub token'
18+
required: true
19+
type: string
20+
dockerhub_organization:
21+
description: 'DockerHub organization'
22+
required: false
23+
type: string
24+
default: llamastack
25+
runs:
26+
using: 'composite'
27+
steps:
28+
- uses: actions/setup-python@v5
29+
with:
30+
python-version: '3.11'
31+
- uses: astral-sh/setup-uv@v6
32+
with:
33+
python-version: '3.11'
34+
enable-cache: false
35+
36+
- uses: docker/setup-buildx-action@v3
37+
- uses: docker/login-action@v3
38+
with:
39+
username: ${{ inputs.dockerhub_username }}
40+
password: ${{ inputs.dockerhub_token }}
41+
42+
- name: Publish manifest lists
43+
shell: bash
44+
env:
45+
VERSION: ${{ inputs.version }}
46+
TEMPLATES: ${{ inputs.templates }}
47+
DOCKERHUB_ORGANIZATION: ${{ inputs.dockerhub_organization }}
48+
run: |
49+
chmod +x ${{ github.action_path }}/main.sh
50+
${{ github.action_path }}/main.sh
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
THIS_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
6+
source $THIS_DIR/../publish-dockers/common.sh
7+
8+
set -x
9+
10+
push_manifest_list() {
11+
template=$1
12+
13+
echo "Pushing multi-arch manifest list for template $template"
14+
if [ "$PYPI_SOURCE" = "testpypi" ]; then
15+
manifests="$DOCKERHUB_ORGANIZATION/distribution-$template:test-${VERSION}-amd64"
16+
has_arm64_image=$(docker buildx imagetools inspect $DOCKERHUB_ORGANIZATION/distribution-$template:test-${VERSION}-arm64 > /dev/null 2>&1; echo $?)
17+
if [ "$has_arm64_image" -eq 0 ]; then
18+
manifests="$manifests $DOCKERHUB_ORGANIZATION/distribution-$template:test-${VERSION}-arm64"
19+
fi
20+
docker buildx imagetools create \
21+
-t $DOCKERHUB_ORGANIZATION/distribution-$template:test-${VERSION} \
22+
$manifests
23+
else
24+
manifests="$DOCKERHUB_ORGANIZATION/distribution-$template:${VERSION}-amd64"
25+
has_arm64_image=$(docker buildx imagetools inspect $DOCKERHUB_ORGANIZATION/distribution-$template:${VERSION}-arm64 > /dev/null 2>&1; echo $?)
26+
if [ "$has_arm64_image" -eq 0 ]; then
27+
manifests="$manifests $DOCKERHUB_ORGANIZATION/distribution-$template:${VERSION}-arm64"
28+
fi
29+
docker buildx imagetools create \
30+
-t $DOCKERHUB_ORGANIZATION/distribution-$template:${VERSION} \
31+
$manifests
32+
docker buildx imagetools create \
33+
-t $DOCKERHUB_ORGANIZATION/distribution-$template:latest \
34+
$manifests
35+
fi
36+
}
37+
38+
for template in "${TEMPLATES[@]}"; do
39+
push_manifest_list $template
40+
done
41+
42+
echo "Done"

actions/publish-dockers/action.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,21 @@ inputs:
1717
description: 'DockerHub token'
1818
required: true
1919
type: string
20+
dockerhub_organization:
21+
description: 'DockerHub organization'
22+
required: false
23+
type: string
24+
default: llamastack
25+
continue_on_error:
26+
description: 'Whether to continue or exit when individual templates fail to build'
27+
required: false
28+
type: string
29+
default: false
30+
arch:
31+
description: Architecture we're building for (amd64 or arm64)
32+
required: true
33+
type: string
34+
default: amd64
2035
runs:
2136
using: 'composite'
2237
steps:
@@ -39,6 +54,9 @@ runs:
3954
env:
4055
VERSION: ${{ inputs.version }}
4156
TEMPLATES: ${{ inputs.templates }}
57+
DOCKERHUB_ORGANIZATION: ${{ inputs.dockerhub_organization }}
58+
CONTINUE_ON_ERROR: ${{ inputs.continue_on_error }}
59+
ARCH: ${{ inputs.arch }}
4260
run: |
4361
chmod +x ${{ github.action_path }}/main.sh
4462
${{ github.action_path }}/main.sh

actions/publish-dockers/common.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
3+
# This file is shared between the publish-dockers and
4+
# publish-docker-manifest-lists actions. It should only contain content
5+
# that is common to both actions.
6+
7+
if [ -z "$VERSION" ]; then
8+
echo "You must set the VERSION environment variable" >&2
9+
exit 1
10+
fi
11+
12+
DOCKERHUB_ORGANIZATION=${DOCKERHUB_ORGANIZATION:-llamastack}
13+
TEMPLATES=${TEMPLATES:-}
14+
15+
if [ -z "$TEMPLATES" ]; then
16+
TEMPLATES=(starter tgi meta-reference-gpu postgres-demo)
17+
else
18+
TEMPLATES=(${TEMPLATES//,/ })
19+
fi
20+
21+
release_exists() {
22+
local source=$1
23+
releases=$(curl -s https://${source}.org/pypi/llama-stack/json | jq -r '.releases | keys[]')
24+
for release in $releases; do
25+
if [ x"$release" = x"$VERSION" ]; then
26+
return 0
27+
fi
28+
done
29+
return 1
30+
}
31+
32+
if release_exists "test.pypi"; then
33+
echo "Version $VERSION found in test.pypi"
34+
PYPI_SOURCE="testpypi"
35+
elif release_exists "pypi"; then
36+
echo "Version $VERSION found in pypi"
37+
PYPI_SOURCE="pypi"
38+
else
39+
echo "Version $VERSION not found in either test.pypi or pypi" >&2
40+
exit 1
41+
fi

actions/publish-dockers/main.sh

Lines changed: 37 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,15 @@
11
#!/bin/bash
22

3-
if [ -z "$VERSION" ]; then
4-
echo "You must set the VERSION environment variable" >&2
5-
exit 1
6-
fi
7-
TEMPLATES=${TEMPLATES:-}
8-
93
set -euo pipefail
104

11-
release_exists() {
12-
local source=$1
13-
releases=$(curl -s https://${source}.org/pypi/llama-stack/json | jq -r '.releases | keys[]')
14-
for release in $releases; do
15-
if [ x"$release" = x"$VERSION" ]; then
16-
return 0
17-
fi
18-
done
19-
return 1
20-
}
5+
THIS_DIR="$(cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")" && pwd)"
6+
source $THIS_DIR/common.sh
7+
8+
CONTINUE_ON_ERROR=${CONTINUE_ON_ERROR:-}
9+
ARCH=${ARCH:-amd64}
2110

22-
if release_exists "test.pypi"; then
23-
echo "Version $VERSION found in test.pypi"
24-
PYPI_SOURCE="testpypi"
25-
elif release_exists "pypi"; then
26-
echo "Version $VERSION found in pypi"
27-
PYPI_SOURCE="pypi"
28-
else
29-
echo "Version $VERSION not found in either test.pypi or pypi" >&2
30-
exit 1
31-
fi
11+
# `llama stack build` uses the `BUILD_PLATFORM` as the architecture to build
12+
export BUILD_PLATFORM="linux/$ARCH"
3213

3314
set -x
3415
TMPDIR=$(mktemp -d)
@@ -44,35 +25,49 @@ uv pip install --index-url https://test.pypi.org/simple/ \
4425
which llama
4526
llama stack list-apis
4627

28+
last_build_error="false"
29+
handle_build_error() {
30+
template=$1
31+
last_build_error="true"
32+
33+
echo "Error building template $template" >&2
34+
if [ "$CONTINUE_ON_ERROR" = "true" ]; then
35+
echo "Continuing on error" >&2
36+
else
37+
echo "Stopping on error" >&2
38+
exit 1
39+
fi
40+
}
41+
4742
build_and_push_docker() {
4843
template=$1
44+
last_build_error="false"
4945

50-
echo "Building and pushing docker for template $template"
46+
echo "Building docker image for template $template and platform $BUILD_PLATFORM"
5147
if [ "$PYPI_SOURCE" = "testpypi" ]; then
52-
TEST_PYPI_VERSION=${VERSION} llama stack build --template $template --image-type container
48+
TEST_PYPI_VERSION=${VERSION} llama stack build --template $template --image-type container || handle_build_error $template
5349
else
54-
PYPI_VERSION=${VERSION} llama stack build --template $template --image-type container
50+
PYPI_VERSION=${VERSION} llama stack build --template $template --image-type container || handle_build_error $template
5551
fi
5652
docker images
5753

58-
echo "Pushing docker image"
54+
if [ "$last_build_error" = "true" ]; then
55+
echo "Skipping push for template $template because of build error"
56+
return
57+
fi
58+
59+
echo "Pushing docker image for template $template and platform $BUILD_PLATFORM"
5960
if [ "$PYPI_SOURCE" = "testpypi" ]; then
60-
docker tag distribution-$template:test-${VERSION} llamastack/distribution-$template:test-${VERSION}
61-
docker push llamastack/distribution-$template:test-${VERSION}
61+
docker tag distribution-$template:test-${VERSION} $DOCKERHUB_ORGANIZATION/distribution-$template:test-${VERSION}-${ARCH}
62+
docker push $DOCKERHUB_ORGANIZATION/distribution-$template:test-${VERSION}-${ARCH}
6263
else
63-
docker tag distribution-$template:${VERSION} llamastack/distribution-$template:${VERSION}
64-
docker tag distribution-$template:${VERSION} llamastack/distribution-$template:latest
65-
docker push llamastack/distribution-$template:${VERSION}
66-
docker push llamastack/distribution-$template:latest
64+
docker tag distribution-$template:${VERSION} $DOCKERHUB_ORGANIZATION/distribution-$template:${VERSION}-${ARCH}
65+
docker tag distribution-$template:${VERSION} $DOCKERHUB_ORGANIZATION/distribution-$template:latest-${ARCH}
66+
docker push $DOCKERHUB_ORGANIZATION/distribution-$template:${VERSION}-${ARCH}
67+
docker push $DOCKERHUB_ORGANIZATION/distribution-$template:latest-${ARCH}
6768
fi
6869
}
6970

70-
if [ -z "$TEMPLATES" ]; then
71-
TEMPLATES=(starter tgi meta-reference-gpu postgres-demo)
72-
else
73-
TEMPLATES=(${TEMPLATES//,/ })
74-
fi
75-
7671
for template in "${TEMPLATES[@]}"; do
7772
build_and_push_docker $template
7873
done

0 commit comments

Comments
 (0)