- #!/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
|