spark-server/deploy/docker/deploy_remote.sh
DESKTOP-L8OUL9F\gfl0034 753c276496 feat: PopAdmin 拉取管理、签到能量 API 与图片 150KiB 硬上限
管理端按用户查询开启通讯录/相册/媒体拉取;服务端写入路径自动压图;新增 /v1/sign 与 /v1/energy。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-02 12:44:06 +08:00

145 lines
5.0 KiB
Bash

#!/usr/bin/env bash
# Build spark-server on ECS via multi-stage Dockerfile.remote (golang container compile).
# Never overwrites whole configs/config.yaml; only patches image/avatar max bytes if present.
# Env: SPARK_RELEASE, SPARK_SRC_DIR, SPARK_DATA_DIR
set -euo pipefail
DATA="${SPARK_DATA_DIR:-/data/spark-server}"
REMOTE="${SPARK_SRC_DIR:-/tmp/spark-image-limit-build}"
RELEASE="${SPARK_RELEASE:-img150k-$(date +%Y%m%d%H%M%S)}"
LOCK="${SPARK_DEPLOY_LOCK:-/tmp/spark-image-limit-build.lock}"
COMPOSE_LOCK="${SPARK_COMPOSE_LOCK:-/tmp/spark-compose-mutate.lock}"
cleanup() { rm -f "$LOCK" || true; }
cleanup_all() { rm -f "$LOCK" "$COMPOSE_LOCK" || true; }
trap cleanup EXIT
if [[ -f "$COMPOSE_LOCK" ]]; then
echo "compose mutate lock held: $COMPOSE_LOCK" >&2
cat "$COMPOSE_LOCK" >&2 || true
exit 99
fi
if [[ -f /tmp/sign-energy-deploy.lock ]]; then
echo "sign-energy deploy in progress; abort to avoid conflict" >&2
cat /tmp/sign-energy-deploy.lock >&2 || true
exit 99
fi
echo $$ >"$LOCK"
echo "==> release $RELEASE (src=$REMOTE)"
cd "$REMOTE"
if [[ -f spark-src.tgz ]]; then
tar xzf spark-src.tgz
fi
test -f go.mod
DF=Dockerfile.remote
if [[ ! -f "$DF" && -f deploy/docker/Dockerfile.remote ]]; then
DF=deploy/docker/Dockerfile.remote
fi
test -f "$DF"
mkdir -p "$DATA/releases" "$DATA/configs/backup" "$DATA/images"
# Stamp rollback BEFORE retagging :latest
if [[ -f "$DATA/configs/config.yaml" ]]; then
cp -a "$DATA/configs/config.yaml" "$DATA/configs/backup/config.yaml.$(date +%Y%m%d%H%M%S)"
fi
if docker image inspect spark-server:latest >/dev/null 2>&1; then
docker tag spark-server:latest spark-server:rollback
docker image inspect spark-server:latest --format '{{.Id}}' >"$DATA/releases/previous_image_id"
date -Iseconds >"$DATA/releases/previous_stamped_at"
fi
# Patch media limits in-place only when keys already exist (never rewrite whole file).
python3 - <<'PY'
from pathlib import Path
import re
p = Path("/data/spark-server/configs/config.yaml")
if not p.is_file():
print("NOTE: no config.yaml")
raise SystemExit(0)
t = p.read_text(encoding="utf-8")
if "image_max_bytes:" not in t:
print("NOTE: image_max_bytes missing; code DefaultOptions (150 KiB) will apply")
raise SystemExit(0)
def set_key(text, key, val):
pat = re.compile(r"(^\s*" + key + r":\s*)\d+", re.M)
if pat.search(text):
return pat.sub(r"\g<1>" + str(val), text), True
return text, False
nt, c1 = set_key(t, "image_max_bytes", 153600)
nt, c2 = set_key(nt, "avatar_max_bytes", 153600)
if c1 or c2:
p.write_text(nt, encoding="utf-8")
print("patched media max bytes to 153600")
else:
print("media keys present; left as-is")
PY
echo "==> docker build via Dockerfile.remote (compile inside golang:1.26-bookworm; NO host go)"
docker pull golang:1.26-bookworm
# Fallback explicit container compile if someone only has runtime Dockerfile:
# docker run --rm -v "$REMOTE":/src -w /src -e CGO_ENABLED=0 -e GOOS=linux -e GOARCH=amd64 \
# -e GOPROXY=https://proxy.golang.org,direct --entrypoint go golang:1.26-bookworm \
# build -trimpath -ldflags='-s -w -buildid=' -o bin/linux_amd64/spark-server ./cmd/server
docker build --platform linux/amd64 \
-f "$DF" \
-t "spark-server:${RELEASE}" \
-t spark-server:latest \
"$REMOTE"
echo "==> save image tar"
docker save "spark-server:${RELEASE}" | gzip -c >"$DATA/images/spark-server-${RELEASE}.tar.gz"
cp -f "$DATA/images/spark-server-${RELEASE}.tar.gz" "$DATA/images/spark-server.tar.gz"
echo "img150k $RELEASE $(date -Iseconds) pid=$$" >"$COMPOSE_LOCK"
trap cleanup_all EXIT
cd "$DATA/compose"
docker compose -f docker-compose.yaml up -d --force-recreate spark-server
ok=0
for _ in $(seq 1 36); do
if curl -fsS -m 3 http://127.0.0.1:18080/healthz >/dev/null 2>&1; then
ok=1
break
fi
sleep 2
done
if [[ "$ok" != "1" ]]; then
echo "HEALTH_FAIL rolling back" >&2
docker tag spark-server:rollback spark-server:latest || true
docker compose -f docker-compose.yaml up -d --force-recreate spark-server || true
exit 2
fi
docker exec spark-server /usr/local/bin/spark-migrate -config /app/configs/config.yaml -dir /app/migrations || true
echo "==> verify"
curl -fsS http://127.0.0.1:18080/healthz; echo
curl -fsS http://127.0.0.1:18080/readyz; echo
grep -E 'image_max_bytes|avatar_max_bytes' "$DATA/configs/config.yaml" || echo "config keys absent (DefaultOptions OK)"
docker exec spark-server sh -c 'strings /usr/local/bin/spark-server | grep -F "All server-written images are capped" | head -1' || echo "string probe miss"
docker ps --filter name=spark-server --format 'table {{.Names}}\t{{.Status}}\t{{.Image}}'
printf '%s\n' "$RELEASE" >"$DATA/releases/current_release"
IMG_ID=$(docker image inspect spark-server:latest --format '{{.Id}}')
PREV=$(cat "$DATA/releases/previous_image_id" 2>/dev/null || true)
NOW=$(date -Iseconds)
cat >"$DATA/releases/manifest.json" <<EOF
{
"status": "ok",
"release": "$RELEASE",
"image_id": "$IMG_ID",
"previous_image_id": "$PREV",
"image_tar": "$DATA/images/spark-server-$RELEASE.tar.gz",
"deployed_at": "$NOW",
"note": "image under 150k EnsureUnderLimit (Dockerfile.remote)"
}
EOF
echo "RELEASE $RELEASE"