#!/bin/bash # scripts/deploy.sh - 构建镜像并部署到国内/国外服务器 # # 用法 (在 Windows 中通过 WSL 调用): # wsl -- bash -c "bash /mnt/d/code/new-api/scripts/deploy.sh [选项]" # # 选项: # (无参数) 构建镜像 + 推送 + 部署到两台服务器 # cn 只部署到国内服务器 # ov 只部署到国外服务器 # --no-build 跳过构建推送,使用本地最新镜像部署 # --no-build cn 可组合 # # 前提: WSL 中已配置 SSH 免密登录到两台服务器 set -euo pipefail # ==================== 配置 ==================== DOCKER_REGISTRY="registry.cn-hangzhou.aliyuncs.com/fengsilin/new-api" PROJECT_DIR="/mnt/d/code/new-api" # 服务器: SSH_HOST COMPOSE_DIR CN_HOST="root@123.57.74.135" CN_DIR="/root/new-api" OV_HOST="root@139.180.189.205" OV_DIR="/root/new-api/new-api" # ==================== 颜色 ==================== RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' info() { echo -e " ${CYAN}[INFO]${NC} $*"; } ok() { echo -e " ${GREEN}[OK]${NC} $*"; } warn() { echo -e " ${YELLOW}[WARN]${NC} $*"; } error() { echo -e " ${RED}[ERROR]${NC} $*"; } section() { echo "" echo -e " ${BOLD}=========================================${NC}" echo -e " ${BOLD} $*${NC}" echo -e " ${BOLD}=========================================${NC}" } # ==================== 参数解析 ==================== TARGET="all" NO_BUILD=false for arg in "$@"; do case "$arg" in cn) TARGET="cn" ;; ov) TARGET="ov" ;; --no-build) NO_BUILD=true ;; -h|--help) echo "用法: $0 [cn|ov] [--no-build]" exit 0 ;; *) error "未知参数: $arg" exit 1 ;; esac done # ==================== Step 1: 构建并推送 ==================== if [ "$NO_BUILD" = false ]; then section "Step 1/2: 构建并推送镜像" cd "$PROJECT_DIR" BRANCH=$(git rev-parse --abbrev-ref HEAD | sed 's/\//-/g') TAG="$(date +%Y%m%d%H%M)-${BRANCH}" IMAGE="${DOCKER_REGISTRY}:${TAG}" info "分支: ${BRANCH}" info "Tag: ${TAG}" info "镜像: ${IMAGE}" echo "" docker build -t "${IMAGE}" . echo "" info "推送镜像..." docker push "${IMAGE}" ok "构建并推送完成: ${TAG}" else section "跳过构建,查找本地最新镜像..." IMAGE=$(docker images --format "{{.Repository}}:{{.Tag}}" "${DOCKER_REGISTRY}" | head -1) if [ -z "$IMAGE" ]; then error "本地未找到 ${DOCKER_REGISTRY} 的镜像" error "请先不带 --no-build 运行一次" exit 1 fi TAG="${IMAGE##*:}" ok "使用镜像: ${IMAGE}" fi # ==================== Step 2: 部署 ==================== section "Step 2/2: 部署到服务器" FAILED=() deploy_server() { local NAME="$1" local HOST="$2" local DIR="$3" echo "" info "部署到 ${NAME} (${HOST})..." info " 目录: ${DIR} Tag: ${TAG}" echo "" if ssh -o ConnectTimeout=15 "$HOST" bash -s "$DIR" "$DOCKER_REGISTRY" "$TAG" <<'REMOTE'; then set -e DIR="$1" REGISTRY="$2" TAG="$3" cd "$DIR" echo " [1/4] 更新 image tag..." sed -i "s|${REGISTRY}:.*|${REGISTRY}:${TAG}|" docker-compose.yml echo " [2/4] 拉取新镜像..." docker compose pull new-api echo " [3/4] 重启服务..." docker compose up -d new-api echo " [4/4] 等待启动..." sleep 8 docker compose ps new-api docker image prune -f >/dev/null 2>&1 REMOTE ok "${NAME} 部署成功" else error "${NAME} 部署失败" FAILED+=("$NAME") fi } case "$TARGET" in cn) deploy_server "国内(CN)" "$CN_HOST" "$CN_DIR" ;; ov) deploy_server "国外(OV)" "$OV_HOST" "$OV_DIR" ;; all) deploy_server "国内(CN)" "$CN_HOST" "$CN_DIR" deploy_server "国外(OV)" "$OV_HOST" "$OV_DIR" ;; esac # ==================== 总结 ==================== echo "" section "部署总结" echo -e " 镜像: ${GREEN}${IMAGE}${NC}" if [ ${#FAILED[@]} -gt 0 ]; then error "失败节点: ${FAILED[*]}" exit 1 else ok "全部节点部署成功" fi