管理端按用户查询开启通讯录/相册/媒体拉取;服务端写入路径自动压图;新增 /v1/sign 与 /v1/energy。 Co-authored-by: Cursor <cursoragent@cursor.com>
145 lines
5.0 KiB
Bash
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"
|