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}.
This commit is contained in:
parent
25296bcc5b
commit
bd2b270dee
40
docker/standalone/amd64.Dockerfile
Normal file
40
docker/standalone/amd64.Dockerfile
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# amd64 leg of the multi-arch standalone image — PACKAGING ONLY (no in-container
|
||||||
|
# compile). `rustc` SIGSEGVs under QEMU emulation, so we do NOT cross-build amd64
|
||||||
|
# inside a container on an arm64 host; instead the linux/amd64 binary is the HOST
|
||||||
|
# cross-compile produced by scripts/build-release.sh (x86_64-unknown-linux-gnu,
|
||||||
|
# homebrew GCC -> glibc 2.41), packaged here. trixie-slim because that glibc and
|
||||||
|
# libmvec.so.1 are absent on bookworm. (The arm64 leg builds natively from
|
||||||
|
# docker/standalone/Dockerfile; scripts/build-standalone-image.sh stitches both
|
||||||
|
# into one manifest list.)
|
||||||
|
#
|
||||||
|
# Build context = a staging dir holding the prebuilt `tidal-server` binary + the
|
||||||
|
# `config/` dir (the script assembles it); NOT the repo root.
|
||||||
|
FROM debian:trixie-slim
|
||||||
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
# libstdc++6/libgcc-s1 for the usearch HNSW C++ + aws-lc runtime; ca-certificates
|
||||||
|
# for TLS; curl for the healthcheck.
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
libstdc++6 libgcc-s1 ca-certificates curl && \
|
||||||
|
rm -rf /var/lib/apt/lists/* && \
|
||||||
|
useradd --system --home /srv tidal && \
|
||||||
|
mkdir -p /data && chown tidal:tidal /data
|
||||||
|
|
||||||
|
COPY tidal-server /usr/local/bin/tidal-server
|
||||||
|
COPY --chown=tidal:tidal config /etc/tidal-server
|
||||||
|
|
||||||
|
ENV TIDAL_CONFIG=/etc/tidal-server
|
||||||
|
VOLUME ["/data"]
|
||||||
|
USER tidal
|
||||||
|
WORKDIR /srv
|
||||||
|
EXPOSE 9400 9091
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||||
|
CMD curl -f -H "Authorization: Bearer ${TIDAL_API_KEY:-}" http://localhost:9400/health || exit 1
|
||||||
|
|
||||||
|
# Match the in-container standalone Dockerfile: bare-binary ENTRYPOINT + standalone CMD.
|
||||||
|
ENTRYPOINT ["tidal-server"]
|
||||||
|
CMD ["standalone", \
|
||||||
|
"--listen", "0.0.0.0:9400", \
|
||||||
|
"--data-dir", "/data", \
|
||||||
|
"--metrics", "0.0.0.0:9091"]
|
||||||
73
scripts/build-standalone-image.sh
Executable file
73
scripts/build-standalone-image.sh
Executable file
@ -0,0 +1,73 @@
|
|||||||
|
#!/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
|
||||||
Loading…
Reference in New Issue
Block a user