Files
soul-yongping/soul-api/deploy/docker-deploy-remote.sh
Alex-larget 6df1736e1e 1
2026-03-20 14:47:37 +08:00

131 lines
4.4 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# soul-api Docker 蓝绿部署脚本(在服务器上执行)
# 用法:./docker-deploy-remote.sh /tmp/soul_api_image.tar.gz [--skip-nginx]
# --skip-nginx跳过 Nginx 切换,由宝塔 API 在本地执行
set -e
PROJECT_ROOT="${DEPLOY_DOCKER_PATH:-/www/wwwroot/self/soul-dev}"
ACTIVE_FILE="$PROJECT_ROOT/.active"
NGINX_CONF="${DEPLOY_NGINX_CONF:-}"
IMAGE_TAR="${1:-}"
SKIP_NGINX=""
if [ "${2:-}" = "--skip-nginx" ]; then
SKIP_NGINX=1
fi
if [ -z "$IMAGE_TAR" ] || [ ! -f "$IMAGE_TAR" ]; then
echo "[ERROR] usage: $0 <path-to-image.tar.gz> [--skip-nginx]"
exit 1
fi
cd "$PROJECT_ROOT"
# 兼容 docker-compose / docker compose不同系统安装不一致
dc() {
if command -v docker-compose >/dev/null 2>&1; then
docker-compose "$@"
else
docker compose "$@"
fi
}
# 兼容 curl / wget健康检查工具不一定都有
health_ok() {
url="$1"
if command -v curl >/dev/null 2>&1; then
curl -sf "$url" >/dev/null 2>&1
else
wget -qO- "$url" >/dev/null 2>&1
fi
}
# 加载新镜像
echo "[1/5] 加载 Docker 镜像 ..."
gunzip -c "$IMAGE_TAR" | docker load
rm -f "$IMAGE_TAR"
# 确定当前活跃实例与待启动实例
CURRENT="blue"
if [ -f "$ACTIVE_FILE" ]; then
CURRENT=$(cat "$ACTIVE_FILE")
fi
if [ "$CURRENT" = "blue" ]; then
NEW="green"
OLD_PORT=9001
NEW_PORT=9002
else
NEW="blue"
OLD_PORT=9002
NEW_PORT=9001
fi
echo "[2/5] 当前活跃: $CURRENT ($OLD_PORT),将启动: $NEW ($NEW_PORT)"
# 启动新实例
echo "[3/5] 启动 soul-api-$NEW ..."
# --no-deps线上 Redis 已在跑,不再让 compose 拉起/重建依赖
dc -f docker-compose.bluegreen.yml up -d --no-deps "soul-api-$NEW"
# 等待健康检查(镜像已从 tar.gz 加载,无需联网拉取,最多 120 秒)
echo "[4/5] 等待健康检查 ..."
sleep 5
for i in $(seq 1 58); do
if health_ok "http://127.0.0.1:$NEW_PORT/health"; then
echo " 健康检查通过 ($((5 + i * 2))s)"
break
fi
sleep 2
if [ $i -eq 58 ]; then
echo "[ERROR] 健康检查超时120s新实例未就绪。可查看: docker-compose -f docker-compose.bluegreen.yml logs soul-api-$NEW"
dc -f docker-compose.bluegreen.yml stop "soul-api-$NEW"
exit 1
fi
done
# 切换 Nginx若配置了 NGINX_CONF将 proxy_pass 中的端口改为 NEW_PORT
if [ -z "$SKIP_NGINX" ]; then
CONF_TO_EDIT="$NGINX_CONF"
# 自动兜底:如果未传入 DEPLOY_NGINX_CONF则尝试在宝塔默认目录中定位 vhost 配置文件
if [ -z "$CONF_TO_EDIT" ] || [ ! -f "$CONF_TO_EDIT" ]; then
CONF_DIR="${DEPLOY_NGINX_CONF_DIR:-/www/server/panel/vhost/nginx}"
if [ -d "$CONF_DIR" ]; then
# 优先匹配旧/新端口对应的 proxy_pass尽量减少误命中
for p in "$OLD_PORT" "$NEW_PORT"; do
# proxy_pass 前可能带空格;用正则增强匹配容错
match="$(grep -rlE "proxy_pass[[:space:]]+http://(127\\.0\\.0\\.1|localhost|0\\.0\\.0\\.0):${p}" "$CONF_DIR" 2>/dev/null | sed -n '1p')"
if [ -n "$match" ]; then
CONF_TO_EDIT="$match"
break
fi
done
# 如果仍未匹配尝试按域名关键字可选DEPLOY_DOMAIN
if [ -z "$CONF_TO_EDIT" ] && [ -n "${DEPLOY_DOMAIN:-}" ]; then
match="$(grep -rl "${DEPLOY_DOMAIN}" "$CONF_DIR" 2>/dev/null | head -n 1)"
if [ -n "$match" ]; then
CONF_TO_EDIT="$match"
fi
fi
fi
fi
if [ -n "$CONF_TO_EDIT" ] && [ -f "$CONF_TO_EDIT" ]; then
echo "[5/5] 切换 Nginx 到 $NEW_PORT ...(编辑: $CONF_TO_EDIT"
# 只在同一个 vhost 配置里替换 proxy_pass 上游端口
sed -i.bak "s|proxy_pass http://127.0.0.1:[0-9]*|proxy_pass http://127.0.0.1:$NEW_PORT|g" "$CONF_TO_EDIT"
sed -i.bak "s|proxy_pass http://localhost:[0-9]*|proxy_pass http://127.0.0.1:$NEW_PORT|g" "$CONF_TO_EDIT"
sed -i.bak "s|proxy_pass http://0.0.0.0:[0-9]*|proxy_pass http://127.0.0.1:$NEW_PORT|g" "$CONF_TO_EDIT"
nginx -t && nginx -s reload
echo " Nginx 已重载"
else
echo "[5/5] 未找到可编辑的 nginx 配置文件,跳过 Nginx 切换。请手动将 proxy_pass 改为 127.0.0.1:$NEW_PORT"
fi
else
echo "[5/5] 已跳过 Nginx 切换(--skip-nginx"
fi
# 停止旧实例(首次部署时可能不存在,忽略错误)
dc -f docker-compose.bluegreen.yml stop "soul-api-$CURRENT" 2>/dev/null || true
echo "$NEW" > "$ACTIVE_FILE"
echo ""
echo "[SUCCESS] 部署完成,当前活跃: $NEW (端口 $NEW_PORT)"