Commit bd442595 by luoqi

fix(deploy): 逻辑包进 main() — 脚本 git pull 自更新时 bash 边读边执行会错位

bash 按字节偏移惰性读脚本;本脚本运行中会 pull 更新自己 → 后半段按新文件偏移执行旧/错位代码
(实测:验证逻辑跑的是旧版)。包进 main() 并在文件末尾调用,bash 先整体解析完再执行,免疫自更新。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent 55444ced
......@@ -7,60 +7,73 @@
# 根治:生产部署不依赖 compose 的"要不要重建"判定 —— 显式 build → 显式 force-recreate
# → 部署后硬验证(容器镜像 ID == 新镜像 ID / 迁移无 pending / health 200),任一不过即失败退出。
#
# ⚠️ 整个逻辑包在 main() 里,文件末尾才调用 —— bash 是边读边执行脚本文件的,
# 而本脚本会 git pull 更新自己;不包 main 的话,pull 后 bash 继续按"新文件的字节偏移"
# 读后半段 → 执行旧/错位代码(2026-06-10 实测:验证逻辑跑的是旧版)。
#
# 用法(服务器上,~/pac):
# bash deploy/deploy-prod.sh # git pull + build + 切换 + 验证
# bash deploy/deploy-prod.sh --no-pull # 跳过 git pull(代码已就位时)
set -euo pipefail
cd "$(dirname "$0")/.."
COMPOSE=(docker compose -f docker-compose.prod.yml
--env-file apps/pac-service/.env --env-file apps/pac-web/.env)
SERVICES=(pac-migrate pac-service pac-web)
log() { printf '\n\033[1;36m== %s ==\033[0m\n' "$*"; }
die() { printf '\033[1;31mFAIL: %s\033[0m\n' "$*" >&2; exit 1; }
if [[ "${1:-}" != "--no-pull" ]]; then
main() {
cd "$(dirname "$0")/.."
local COMPOSE=(docker compose -f docker-compose.prod.yml
--env-file apps/pac-service/.env --env-file apps/pac-web/.env)
local SERVICES=(pac-migrate pac-service pac-web)
if [[ "${1:-}" != "--no-pull" ]]; then
log "git pull --ff-only"
git pull --ff-only origin main
fi
log "HEAD: $(git log --oneline -1)"
fi
log "HEAD: $(git log --oneline -1)"
log "build 镜像(显式,不和 up 混)"
"${COMPOSE[@]}" build "${SERVICES[@]}"
log "build 镜像(显式,不和 up 混)"
"${COMPOSE[@]}" build "${SERVICES[@]}"
log "force-recreate(不信 compose 的重建判定)"
"${COMPOSE[@]}" up -d --force-recreate "${SERVICES[@]}"
log "force-recreate(不信 compose 的重建判定)"
"${COMPOSE[@]}" up -d --force-recreate "${SERVICES[@]}"
# ── 部署后硬验证:任一不过 = 部署失败 ─────────────────────────────
log "验证 1/3:容器跑的镜像 == 刚构建的镜像"
proj=$(basename "$PWD")
for svc in pac-service pac-web; do
# ── 部署后硬验证:任一不过 = 部署失败 ─────────────────────────────
log "验证 1/3:容器跑的镜像 == 刚构建的镜像"
local proj svc want got
proj=$(basename "$PWD")
for svc in pac-service pac-web; do
want=$(docker image inspect "${proj}-${svc}" --format '{{.Id}}')
got=$(docker inspect "${proj}-${svc}-1" --format '{{.Image}}')
[[ "$want" == "$got" ]] || die "$svc 容器仍在旧镜像(want ${want:7:12} got ${got:7:12})— compose 又没重建"
echo " $svc OK (${want:7:12})"
done
done
log "验证 2/3:数据库迁移无 pending(migrate 容器 exit 0 且 deploy 干净)"
mexit=$(docker inspect "${proj}-pac-migrate-1" --format '{{.State.ExitCode}}')
[[ "$mexit" == "0" ]] || die "migrate 容器 exit=$mexit(看 docker logs ${proj}-pac-migrate-1)"
# 注 1:prisma 的"新版本提示框"位置不固定(异步)→ 不能 tail 截断,全量输出里找;
# 注 2:pipefail 下 `cmd | grep -q` 会因 grep 提前退出给 cmd 发 SIGPIPE → 管道 141 误判失败
# → 先落变量再 grep。
status_out=$(docker exec "${proj}-pac-service-1" sh -c 'npx prisma migrate status 2>&1' || true)
grep -qiE 'database schema is up to date' <<<"$status_out" \
log "验证 2/3:数据库迁移无 pending(migrate 容器 exit 0 且 deploy 干净)"
local mexit status_out
mexit=$(docker inspect "${proj}-pac-migrate-1" --format '{{.State.ExitCode}}')
[[ "$mexit" == "0" ]] || die "migrate 容器 exit=$mexit(看 docker logs ${proj}-pac-migrate-1)"
# 注 1:prisma 的"新版本提示框"位置不固定(异步)→ 不能 tail 截断,全量输出里找;
# 注 2:pipefail 下 `cmd | grep -q` 会因 grep 提前退出给 cmd 发 SIGPIPE → 管道 141 误判失败
# → 先落变量再 grep。
status_out=$(docker exec "${proj}-pac-service-1" sh -c 'npx prisma migrate status 2>&1' || true)
grep -qiE 'database schema is up to date' <<<"$status_out" \
|| die "迁移有 pending / 状态异常: $(tail -2 <<<"$status_out")"
echo " migrate OK"
echo " migrate OK"
log "验证 3/3:health + web"
for i in $(seq 1 30); do
log "验证 3/3:health + web"
local i code webcode
for i in $(seq 1 30); do
code=$(curl -s -m 5 -o /dev/null -w '%{http_code}' http://127.0.0.1:3101/pac/v1/health || true)
[[ "$code" == "200" ]] && break; sleep 2
done
[[ "${code:-}" == "200" ]] || die "service health=$code"
webcode=$(curl -s -m 30 -o /dev/null -w '%{http_code}' http://127.0.0.1:3100/ || true)
[[ "$webcode" == "200" ]] || die "web http=$webcode"
echo " health 200 / web 200"
[[ "$code" == "200" ]] && break
sleep 2
done
[[ "${code:-}" == "200" ]] || die "service health=$code"
webcode=$(curl -s -m 30 -o /dev/null -w '%{http_code}' http://127.0.0.1:3100/ || true)
[[ "$webcode" == "200" ]] || die "web http=$webcode"
echo " health 200 / web 200"
log "部署成功 ✅ $(git log --oneline -1)"
}
log "部署成功 ✅ $(git log --oneline -1)"
main "$@"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment