From 3beb039ddac474b02a20f63cbcf0b9bb3df1e660 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 3 Nov 2026 11:24:06 +0800 Subject: [PATCH] =?UTF-8?q?fix(=E9=83=A8=E7=BD=B2):=20=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=E6=B2=A1=E9=80=9A=E8=BF=87=E6=97=B6=E6=8A=8A=E9=95=9C=E5=83=8F?= =?UTF-8?q?=E5=90=8D=E6=8C=87=E5=9B=9E=E5=8E=9F=E6=9D=A5=E7=9A=84=EF=BC=8C?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E5=86=8D=E8=B5=B7=E5=AE=B9=E5=99=A8=E4=B8=8D?= =?UTF-8?q?=E4=BC=9A=E6=8D=A2=E4=B8=8A=E6=B2=A1=E8=BF=81=E7=A7=BB=E7=9A=84?= =?UTF-8?q?=E6=96=B0=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- docker/deploy.sh | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/docker/deploy.sh b/docker/deploy.sh index c7a5f16..0e43522 100755 --- a/docker/deploy.sh +++ b/docker/deploy.sh @@ -130,6 +130,30 @@ ok "对外端口 $port" # ---------------------------------------------------------------- 起栈 +# 构建会把 oj2-api:latest / oj2-web:latest 这两个名字挪到新镜像上,而迁移排在构建之后。 +# 迁移失败时容器没动、还跑着旧镜像,但名字已经指向新镜像 —— 之后谁跑一次 +# `compose up -d`(比如 --no-build 改个 env),就会把还没迁移的新代码、甚至编坏了的 +# 二进制换上去。2026-11-03 真撞过一次(新镜像缺 libicu,当时手动 docker tag 回去的)。 +# 所以构建前记下它们原来指向哪个镜像,迁移失败时指回去。 +built_images=$(grep -E '^[[:space:]]*image: oj2-(api|web):' <<<"$cfg" | awk '{print $2}' | sort -u || true) +declare -A prev_image=() +for img in $built_images; do + prev_image[$img]=$(docker image inspect -f '{{.Id}}' "$img" 2>/dev/null || true) +done +restore_images() { + local img + for img in $built_images; do + if [ -n "${prev_image[$img]}" ]; then + if docker tag "${prev_image[$img]}" "$img"; then + warn "$img 已指回构建前的镜像 ${prev_image[$img]:7:12}" + else + warn "$img 没能指回 ${prev_image[$img]},手动:docker tag ${prev_image[$img]} $img" + fi + fi + done + return 0 # 下面紧跟着 die,别让这里的失败把 die 的说明吞掉 +} + if [ "$BUILD" -eq 1 ]; then say "构建镜像(首次约 5 分钟,之后走缓存很快)" # --pull:每次都去查 FROM 的基础镜像有没有新版。不带的话 caddy:2-alpine、 @@ -152,11 +176,11 @@ say "数据库迁移" "${COMPOSE[@]}" run --rm \ -e OJ2_ALLOW_DESTRUCTIVE="${OJ2_ALLOW_DESTRUCTIVE:-}" \ oj-api oj2-api migrate \ - || die "迁移没通过,已中止部署(容器没动过)。**原因看上面 migrate 自己的输出**, + || { restore_images; die "迁移没通过,已中止部署(容器没动过,镜像名也指回了构建前的)。**原因看上面 migrate 自己的输出**, 它对每种情况都打印了具体该做什么,别照搬下面这几条猜。常见的三种: · 破坏性语句被拦 → 确认备份后 OJ2_ALLOW_DESTRUCTIVE=1 docker/deploy.sh · 缺迁移基线记录 → 按它打印的 SQL 插一行 - · 连不上库 → oj-postgres 是否起来了(docker logs oj-postgres)、DATA_DIR 对不对" + · 连不上库 → oj-postgres 是否起来了(docker logs oj-postgres)、DATA_DIR 对不对"; } say "起栈" "${COMPOSE[@]}" up -d