tidaldb/scripts/build-standalone-image.sh
jx12n bd2b270dee build(standalone): committed multi-arch pullable standalone dev image path
Consumers (e.g. thepeach) need a PULLABLE tidaldb image — not every dev has the
source for a compose `build:` context. Publishes registry.threesix.ai/tidal/standalone
as a manifest list: linux/amd64 (Linux/CI) + linux/arm64 (Apple-silicon Macs),
defaulting to STANDALONE mode (:9400, --data-dir /data) so it drops into a consumer's
docker-compose like postgres.

Hybrid build because `rustc` SIGSEGVs under QEMU (an in-container amd64 cross-build on
an arm64 host fails):
- amd64: docker/standalone/amd64.Dockerfile packages the HOST cross-compiled x86_64
  binary (the proven build-release path; trixie-slim for glibc 2.41/libmvec) — apt+COPY only.
- arm64: native in-container build from docker/standalone/Dockerfile.
- scripts/build-standalone-image.sh stitches both into one manifest list (:m12 + :latest).

Verified: pulled :m12 (arm64), booted standalone, GET /health -> {ok:true,mode:standalone}.
2026-06-19 21:34:06 -06:00

74 lines
4.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# build-standalone-image.sh — the committed, repeatable build path for the
# PULLABLE, MULTI-ARCH standalone dev image.
#
# ./scripts/build-standalone-image.sh [tag] # default tag: m12 (+ also tags :latest)
#
# WHY THIS IS SEPARATE FROM build-release.sh:
# build-release.sh produces the PRODUCTION images (server/dr/stress), amd64-ONLY,
# defaulting to CLUSTER mode — they will not run natively on an arm64 dev Mac.
# This publishes a manifest list with BOTH linux/amd64 (Linux devs / CI) and
# linux/arm64 (Apple-silicon Macs), defaulting to STANDALONE mode, so a consumer
# app (e.g. thepeach) can pull it as a docker-compose dependency like postgres —
# no source checkout required.
#
# WHY THE HYBRID (not a single `buildx --platform amd64,arm64`):
# `rustc` SIGSEGVs under QEMU emulation, so an in-container amd64 cross-build on
# an arm64 host fails. We therefore:
# - amd64: package the HOST cross-compiled x86_64 binary (the proven build-release
# path) via docker/standalone/amd64.Dockerfile — apt + COPY only, no compile.
# - arm64: build natively in-container from docker/standalone/Dockerfile.
# - stitch both into a manifest list with `imagetools create`.
#
# Registry creds come from the Docker daemon's existing login (zot accepts anonymous
# push for this registry); no secret is embedded.
set -euo pipefail
TAG="${1:-m12}"
REGISTRY="${TIDAL_REGISTRY:-registry.threesix.ai/tidal}"
IMAGE="${REGISTRY}/standalone"
BUILDER="${TIDAL_BUILDX_BUILDER:-amd64builder}"
TARGET="x86_64-unknown-linux-gnu"
die() { echo "build-standalone-image: $*" >&2; exit 1; }
command -v docker >/dev/null || die "docker not on PATH"
docker buildx inspect "$BUILDER" >/dev/null 2>&1 \
|| die "buildx builder '$BUILDER' not found (docker buildx create --name $BUILDER --driver docker-container --use)"
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"; cd "$REPO_ROOT"
echo "==> multi-arch standalone image ${IMAGE}:${TAG} (+ :latest), source $(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
# 1. amd64 binary: HOST cross-compile if absent (QEMU rustc segfaults, so never in-container).
BIN="target/${TARGET}/release/tidal-server"
if [ ! -x "$BIN" ]; then
command -v "${TARGET}-gcc" >/dev/null || die "missing ${TARGET}-gcc (brew install ${TARGET}); needed to cross-compile the amd64 binary"
rustup target list --installed 2>/dev/null | grep -qx "$TARGET" || die "rust target $TARGET not installed (rustup target add $TARGET)"
echo "==> amd64 binary absent — host cross-compiling -p tidal-server for $TARGET"
export CC_x86_64_unknown_linux_gnu="${TARGET}-gcc" \
CXX_x86_64_unknown_linux_gnu="${TARGET}-g++" \
AR_x86_64_unknown_linux_gnu="${TARGET}-ar" \
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="${TARGET}-gcc" \
PROTOC="${PROTOC:-$(command -v protoc || true)}"
[ -n "$PROTOC" ] || die "protoc not found (brew install protobuf), or set PROTOC"
cargo build -p tidal-server --release --target "$TARGET" --locked
fi
# 2. amd64 image: package the prebuilt binary (no compile -> reliable under QEMU).
STAGE="tmp/standalone-amd64"; rm -rf "$STAGE"; mkdir -p "$STAGE"
cp "$BIN" "$STAGE/tidal-server"
cp -R tidal-server/config "$STAGE/config"
cp docker/standalone/amd64.Dockerfile "$STAGE/Dockerfile"
echo "==> building+pushing ${IMAGE}:${TAG}-amd64 (packaging)"
docker buildx build --builder "$BUILDER" --platform linux/amd64 -t "${IMAGE}:${TAG}-amd64" --push "$STAGE"
# 3. arm64 image: native in-container build.
echo "==> building+pushing ${IMAGE}:${TAG}-arm64 (native in-container)"
docker buildx build --builder "$BUILDER" --platform linux/arm64 -f docker/standalone/Dockerfile -t "${IMAGE}:${TAG}-arm64" --push .
# 4. stitch the two single-arch tags into one manifest list.
echo "==> assembling manifest list ${IMAGE}:${TAG} + :latest"
docker buildx imagetools create -t "${IMAGE}:${TAG}" -t "${IMAGE}:latest" "${IMAGE}:${TAG}-amd64" "${IMAGE}:${TAG}-arm64"
echo "==> published. Manifest list arches:"
docker buildx imagetools inspect "${IMAGE}:${TAG}" 2>/dev/null | grep -E 'Name:|Platform:' || true