You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

97 lines
5.7 KiB

#!/usr/bin/env bash
# console 生产环境:部署指定镜像版本到生产机,支持回滚。console 为单机管理后台,无区域之分。
#
# 镜像由 ./prod-build.sh 预先构建推送;本脚本只做「远端拉取 + 重启」。
# 仅做镜像部署:服务器上的 docker-compose.yml / .env / confs/ 由你自行维护
# (照着仓库里的 env/env.example、confs/console.yaml.example 在服务器上放好真实文件),本脚本不上传任何配置。
#
# 用法(在 deploy/console/ 下):
# ./prod-deploy.sh <tag> # 部署指定版本,如 ./prod-deploy.sh 0.1.1
# ./prod-deploy.sh rollback # 回滚到上一次部署版本(与当前版本来回切换)
set -euo pipefail
SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
blue() { printf "\033[34m%s\033[0m\n" "$*"; }
green() { printf "\033[32m%s\033[0m\n" "$*"; }
red() { printf "\033[31m%s\033[0m\n" "$*"; }
# ╔══════════════════════════════════════════════════════════════════════╗
# ║ 生产部署目标 / 私有仓库凭据 —— 写死在此(本文件纳入 git)。公开仓库前清空 HOST/PASS。 ║
# ╚══════════════════════════════════════════════════════════════════════╝
IMAGE_NAME="console-a11"
REGISTRY="docker-registry.ideapsound.com"
REGISTRY_USER="admin"
REGISTRY_PASS="li13451234"
DOCKER_NETWORK="1panel-network" # compose 外部网络名(与服务器一致)
DEPLOY_HOST="47.253.88.66" # ← 生产服务器 IP(必填)
DEPLOY_PORT=22
DEPLOY_USER=root
DEPLOY_KEY=/Users/liwei/Documents/key/yunyan-us.pem
DEPLOY_DIR="/home/work/console-a11" # 远端部署目录(其中 docker-compose.yml/.env/confs 由你自己维护)
# ── 参数 ──
ARG1="${1:-}"
[ -n "$ARG1" ] || { red "用法: ./prod-deploy.sh <tag|rollback>(如 0.1.1)"; exit 1; }
if [ "$ARG1" = "rollback" ]; then MODE="rollback"; NEW_TAG=""; else MODE="deploy"; NEW_TAG="$ARG1"; fi
: "${DEPLOY_HOST:?请在 prod-deploy.sh 顶部填 DEPLOY_HOST(生产服务器 IP)}"
_ssh() { ssh -p "$DEPLOY_PORT" -i "${DEPLOY_KEY/#\~/$HOME}" -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST" "$@"; }
_scp() { scp -P "$DEPLOY_PORT" -i "${DEPLOY_KEY/#\~/$HOME}" -o StrictHostKeyChecking=accept-new "$@"; }
_dest() { echo "$DEPLOY_USER@$DEPLOY_HOST:$1"; }
# 同步「模板 + compose」(只传模板,绝不覆盖你维护的真实 .env / confs/console.yaml)
blue ">>> 同步模板与 compose → $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_DIR"
_ssh "mkdir -p '$DEPLOY_DIR/confs' '$DEPLOY_DIR/log'"
_scp "$SVC_DIR/docker-compose.yml" "$(_dest "$DEPLOY_DIR/docker-compose.yml")"
_scp "$SVC_DIR/confs/console.yaml.example" "$(_dest "$DEPLOY_DIR/confs/console.yaml.example")"
_scp "$SVC_DIR/env/env.example" "$(_dest "$DEPLOY_DIR/env.example")"
# 远端拉取并重启(不上传真实配置):tag 历史存服务器上独立的 .deploy_tag,不动你维护的 .env。
blue ">>> 远端部署($MODE${NEW_TAG:+ $NEW_TAG}) → $DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_DIR"
_ssh bash -s -- "$DEPLOY_DIR" "$MODE" "$NEW_TAG" "$REGISTRY/$IMAGE_NAME" "$REGISTRY" "$REGISTRY_USER" "$REGISTRY_PASS" "$DOCKER_NETWORK" <<'REMOTE'
set -e
DIR="$1"; MODE="$2"; NEW_TAG="$3"; IMG_PREFIX="$4"; REG="$5"; REG_USER="$6"; REG_PASS="$7"; NET="$8"
[ -f "$DIR/.env" ] || { echo "✗ 缺少 $DIR/.env(请照 env.example 在服务器填好真实 .env)"; exit 1; }
[ -f "$DIR/confs/console.yaml" ] || { echo "✗ 缺少 $DIR/confs/console.yaml(请照 confs/console.yaml.example 在服务器填好)"; exit 1; }
[ -f "$DIR/docker-compose.yml" ] || { echo "✗ 缺少 $DIR/docker-compose.yml"; exit 1; }
STATE="$DIR/.deploy_tag" # 当前部署 tag(独立文件,不动用户的 .env)
PREVF="$DIR/.deploy_tag.prev" # 上一次部署 tag
CUR_TAG="$([ -f "$STATE" ] && cat "$STATE" || true)"
CUR_PREV="$([ -f "$PREVF" ] && cat "$PREVF" || true)"
if [ "$MODE" = "rollback" ]; then
[ -n "$CUR_PREV" ] || { echo "没有上一次版本记录(.deploy_tag.prev),无法回滚"; exit 1; }
FINAL_TAG="$CUR_PREV"; FINAL_PREV="$CUR_TAG" # 与当前版本来回切换
else
FINAL_TAG="$NEW_TAG"
if [ -n "$CUR_TAG" ] && [ "$CUR_TAG" != "$NEW_TAG" ]; then FINAL_PREV="$CUR_TAG"; else FINAL_PREV="$CUR_PREV"; fi
fi
echo "$REG_PASS" | docker login "$REG" -u "$REG_USER" --password-stdin >/dev/null
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET"
docker pull "$IMG_PREFIX:$FINAL_TAG"
# 自动适配 compose 版本:优先 v2 插件(docker compose),回退 v1(docker-compose)
if docker compose version >/dev/null 2>&1; then DC="docker compose"; else DC="docker-compose"; fi
# .env 与 compose 同目录会被自动加载,无需 --env-file(老版本/ v1 不认该 flag);
# REGISTRY/TAG 用 inline 环境变量覆盖(优先级高于 .env),不改写用户的 .env
cd "$DIR"
# 先正常 up;若因历史遗留的同名容器(非本 compose 项目创建,compose 不会自动替换)冲突,
# 强制删掉该容器后重试一次。容器名与 docker-compose.yml 的 container_name 一致。
REGISTRY="$REG" TAG="$FINAL_TAG" $DC up -d || {
echo ">>> up 失败,尝试清理同名遗留容器(console-a11)后重试"
docker rm -f console-a11 2>/dev/null || true
REGISTRY="$REG" TAG="$FINAL_TAG" $DC up -d
}
docker image prune -f
echo "$FINAL_TAG" > "$STATE"
[ -n "$FINAL_PREV" ] && echo "$FINAL_PREV" > "$PREVF" || true
echo "已部署版本 TAG=$FINAL_TAG (上一次=${FINAL_PREV:-无})"
REMOTE
green "✓ console $MODE 完成"