diff --git a/docker/remote-agent/deploy/README.md b/docker/remote-agent/deploy/README.md index 8b9bcbb..a13651d 100644 --- a/docker/remote-agent/deploy/README.md +++ b/docker/remote-agent/deploy/README.md @@ -106,12 +106,18 @@ it — handy if you need to roll back quickly. does not match this host"** — the ZIP was built for the wrong CPU architecture (typically an Apple Silicon Mac produced an `arm64` image for an `x86_64` Linux host). `install.sh` catches this and prints the - exact rebuild command; ask your build operator to run: + exact rebuild command; ask your build operator to `git pull` first + (to pick up the fixed cross-arch build) and then run: ``` ./docker/remote-agent/package.sh --platform linux/amd64 ``` (or `linux/arm64` if this host is ARM — run `uname -m` to check: `x86_64` → `linux/amd64`, `aarch64` → `linux/arm64`.) + + Note that `install.sh` **always** re-runs `docker load` on the bundled + tarball, so a stale image left from an earlier wrong-arch attempt at the + same version tag will be transparently replaced when you install a + corrected bundle — no need to `docker rmi` by hand. - **Agent connects, then disconnects immediately** — `WS_TOKEN` doesn't match the server. Fix in `.env`, then `docker compose restart`. - **Agent never connects** — check `WS_URL` (correct hostname, correct diff --git a/docker/remote-agent/deploy/install.sh b/docker/remote-agent/deploy/install.sh index 42f0ca3..afddf9c 100755 --- a/docker/remote-agent/deploy/install.sh +++ b/docker/remote-agent/deploy/install.sh @@ -65,21 +65,29 @@ else fi # --- 3. Load the image ----------------------------------------------------- +# ALWAYS docker load, unconditionally. `docker load` reassigns the tag to +# whatever's in the tarball and is a fast no-op when the layers are already +# present, so this is safe to re-run. We intentionally do NOT "skip if the +# tag already exists" — a stale image left over from a previous wrong-arch +# attempt has this exact tag, and skipping the load would hide the correct +# image in the tarball we're actually holding. IMAGE_TAG="sha-remote-agent:${VERSION}" -if docker image inspect "$IMAGE_TAG" >/dev/null 2>&1; then - log "Image $IMAGE_TAG already present — skipping load." -else - log "Loading Docker image from $IMAGE_TARBALL..." - docker load -i "$IMAGE_TARBALL" -fi + +log "Loading Docker image from ${IMAGE_TARBALL}..." +docker load -i "$IMAGE_TARBALL" # --- 3a. Platform sanity check -------------------------------------------- -# If the image was built for a different CPU architecture than this host, -# Docker will let it "run" but tini (and node) fail with cryptic errors -# like "exec format error". Catch that up front with a clear message. +# Inspect the image we just (re)loaded — this is the ground truth for what +# was actually shipped in this ZIP, independent of anything that was on the +# host before. If the tarball was built for a different CPU architecture +# than this host, Docker will let it "run" but tini (and node) fail with +# cryptic errors like "exec format error". Catch that up front with a +# clear message. IMAGE_ARCH="$(docker image inspect --format '{{.Architecture}}' "$IMAGE_TAG" 2>/dev/null || true)" +IMAGE_ID_SHORT="$(docker image inspect --format '{{.Id}}' "$IMAGE_TAG" 2>/dev/null | sed 's|^sha256:||' | cut -c1-12)" + HOST_ARCH_RAW="$(uname -m)" case "$HOST_ARCH_RAW" in x86_64|amd64) HOST_ARCH="amd64" ;; @@ -88,10 +96,22 @@ case "$HOST_ARCH_RAW" in *) HOST_ARCH="$HOST_ARCH_RAW" ;; esac -if [[ -n "$IMAGE_ARCH" && "$IMAGE_ARCH" != "$HOST_ARCH" ]]; then - warn "Image architecture ($IMAGE_ARCH) does not match this host ($HOST_ARCH)." - warn "The container will fail to start with 'exec format error'." - die "Rebuild on the dev host with: ./docker/remote-agent/package.sh --platform linux/${HOST_ARCH}" +log "Loaded ${IMAGE_TAG} (id: ${IMAGE_ID_SHORT:-unknown}, arch: ${IMAGE_ARCH:-unknown}); host arch: ${HOST_ARCH}." + +if [[ -z "$IMAGE_ARCH" ]]; then + die "Could not read image architecture from Docker — is the image really loaded?" +fi + +if [[ "$IMAGE_ARCH" != "$HOST_ARCH" ]]; then + warn "Image architecture (${IMAGE_ARCH}) does not match this host (${HOST_ARCH})." + warn "The container would fail to start with 'exec /sbin/tini: exec format error'." + warn "" + warn "This means the ZIP was built for the wrong CPU. On the build host:" + warn " 1. git pull # make sure you have the fixed package.sh" + warn " 2. ./docker/remote-agent/package.sh --platform linux/${HOST_ARCH}" + warn "The updated package.sh verifies the architecture during build and" + warn "refuses to produce a ZIP that would fail this check." + die "Aborting install. Ship a linux/${HOST_ARCH} bundle and re-run this script." fi # --- 4. Bootstrap .env -----------------------------------------------------