deploy.sh: incoming image tag wins over .image-tags.env; health via container healthcheck

Two bugs surfaced wiring dev auto-deploy:
1. Sourcing .image-tags.env clobbered the caller's incoming *_IMAGE_TAG. The
   first backend-only deploy persists FRONTEND_IMAGE_TAG=local (sibling unknown);
   the next frontend deploy then sourced that and pulled :local -> 'manifest
   unknown'. Now the incoming env is captured before sourcing and re-applied.
2. Health-checked services via a host-port curl, but the dev overlay leaves the
   frontend port unpublished (reached via the backend proxy) -> false failure.
   Now polls each container's own HEALTHCHECK status via docker inspect.
This commit is contained in:
Emi Griffith 2026-07-22 15:48:23 -07:00
parent 418f4e0631
commit 59e7517747

View file

@ -114,9 +114,19 @@ export REGISTRY_HOST BACKEND_IMAGE_PATH FRONTEND_IMAGE_PATH
# service being deployed then overrides its line below. This file is untracked # service being deployed then overrides its line below. This file is untracked
# (see .gitignore), so `git reset --hard` above leaves it in place. # (see .gitignore), so `git reset --hard` above leaves it in place.
TAGS_FILE="$APP_DIR/deploy/.image-tags.env" TAGS_FILE="$APP_DIR/deploy/.image-tags.env"
# Capture the tags the caller explicitly passed BEFORE sourcing -- they must
# WIN. The file only supplies the *sibling's* last-known tag; sourcing it
# unconditionally would clobber an incoming tag (e.g. a frontend deploy whose
# FRONTEND_IMAGE_TAG got overwritten by the stale `local` the first backend-only
# deploy persisted for the not-yet-known sibling -> pull `:local` -> "manifest
# unknown"). So source for the sibling, then re-apply the caller's own value.
_incoming_backend="${BACKEND_IMAGE_TAG:-}"
_incoming_frontend="${FRONTEND_IMAGE_TAG:-}"
if [ -f "$TAGS_FILE" ]; then if [ -f "$TAGS_FILE" ]; then
set -a; . "$TAGS_FILE"; set +a set -a; . "$TAGS_FILE"; set +a
fi fi
[ -n "$_incoming_backend" ] && BACKEND_IMAGE_TAG="$_incoming_backend"
[ -n "$_incoming_frontend" ] && FRONTEND_IMAGE_TAG="$_incoming_frontend"
# Guard: the service(s) being rolled MUST have a concrete tag supplied now (the # Guard: the service(s) being rolled MUST have a concrete tag supplied now (the
# sibling's may come from the persisted file). `all` needs both. # sibling's may come from the persisted file). `all` needs both.
@ -207,21 +217,25 @@ EOF
# Health check the service(s) we rolled: backend on 8137, frontend on 8080. # Health check the service(s) we rolled: backend on 8137, frontend on 8080.
# (For `all`, backend's `/` serving is the readiness signal the old script used # (For `all`, backend's `/` serving is the readiness signal the old script used
# and the frontend depends_on backend anyway.) # and the frontend depends_on backend anyway.)
declare -A HEALTH_PORTS=( [backend]=8137 [frontend]=8080 ) # Health via each container's own HEALTHCHECK (docker inspect), NOT a host-port
# curl: the dev overlay leaves the frontend port UNpublished (reached through the
# backend's _proxy_to_frontend), so a localhost:8080 curl spuriously fails there.
# Both images HEALTHCHECK-curl /healthz internally, so this works published or not.
health_ok=1 health_ok=1
for svc in "${TARGETS[@]}"; do for svc in "${TARGETS[@]}"; do
port="${HEALTH_PORTS[$svc]}" cid=$(docker compose ps -q "$svc" 2>/dev/null)
url="http://127.0.0.1:${port}/healthz" echo "==> Health check: $svc (container health)"
echo "==> Health check: $svc ($url)" ok=0; st=unknown
ok=0 for i in $(seq 1 40); do
for i in $(seq 1 30); do st=$(docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' "$cid" 2>/dev/null || echo gone)
if curl -fsS -o /dev/null "$url"; then ok=1; break; fi [ "$st" = healthy ] && { ok=1; break; }
sleep 1 if [ "$st" = none ] && [ "$(docker inspect --format '{{.State.Status}}' "$cid" 2>/dev/null)" = running ]; then ok=1; break; fi
sleep 2
done done
if [ "$ok" = 1 ]; then if [ "$ok" = 1 ]; then
echo "==> OK: $svc is serving" echo "==> OK: $svc is healthy"
else else
echo "!! Health check failed for $svc ($url)" >&2 echo "!! Health check failed for $svc (status=$st)" >&2
health_ok=0 health_ok=0
fi fi
done done