#!/usr/bin/env bash # ------------------------------------------------------------------ # fnOS 一键更新部署 # # 用法(在 NAS 宿主机): # bash /vol1/1000/Docker/idcard-api/deploy.sh # # 逻辑:增量构建(只重跑失效层,通常 10-30s)→ 等就绪 → 校验镜像内代码 # 是否真的更新了 → 打印 health。校验失败自动降级为 --no-cache 全量重建。 # ------------------------------------------------------------------ set -uo pipefail # 切到脚本所在目录,避免路径写死 cd "$(dirname "$0")" || exit 1 PROJECT_NAME="icd" # compose 项目名(镜像名 icd-idcard-api 的前缀) SERVICE="idcard-api" # container_name PORT=8000 MARKER="auth_enabled" # 用它能判断镜像里是新代码 echo "==> 目录: $(pwd)" # ---------- 1. 增量构建 + 启动 ---------- echo "==> 1/4 构建并启动(增量,通常 10-30 秒)" if ! sudo docker compose -p "$PROJECT_NAME" up -d --build; then echo "!! 构建失败。常见原因:基础镜像源 401,检查 Dockerfile 的 BASE_IMAGE" exit 1 fi # ---------- 2. 等服务就绪 ---------- echo "==> 2/4 等待服务就绪" ready=0 for _ in $(seq 1 30); do if curl -sf "http://127.0.0.1:$PORT/api/v1/idcard/health" >/dev/null 2>&1; then ready=1 break fi sleep 2 done if [ "$ready" -ne 1 ]; then echo "!! 服务 60 秒内未就绪,看日志:sudo docker logs --tail 50 $SERVICE" exit 1 fi # ---------- 3. 校验镜像内代码是否真的更新 ---------- echo "==> 3/4 校验容器内代码版本" count=$(sudo docker exec "$SERVICE" grep -c "$MARKER" /app/app/main.py 2>/dev/null || echo 0) if [ "${count:-0}" -lt 1 ]; then echo "!! 容器内仍是旧代码,降级为 --no-cache 全量重建(需要几分钟)" sudo docker compose -p "$PROJECT_NAME" build --no-cache || exit 1 sudo docker compose -p "$PROJECT_NAME" up -d --force-recreate || exit 1 count=$(sudo docker exec "$SERVICE" grep -c "$MARKER" /app/app/main.py 2>/dev/null || echo 0) if [ "${count:-0}" -lt 1 ]; then echo "!! 全量重建后代码仍是旧的。检查 compose 项目目录是否就是本目录:" sudo docker inspect "$SERVICE" --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}' exit 1 fi fi echo " 容器内代码已更新(匹配 $count 处)" # ---------- 4. 健康检查 ---------- echo "==> 4/4 健康检查" curl -s "http://127.0.0.1:$PORT/api/v1/idcard/health" echo echo echo "部署完成。" echo " 看日志:sudo docker logs -f $SERVICE" echo " 看内存:sudo docker stats --no-stream $SERVICE"