1279 lines
43 KiB
Bash
Executable File
1279 lines
43 KiB
Bash
Executable File
#!/bin/bash
|
||
# ============================================
|
||
# 多模式部署脚本
|
||
# 用法:
|
||
# bash deploy.sh init 交互式初始化 .env
|
||
# bash deploy.sh start 启动
|
||
# bash deploy.sh build [分支] 编译镜像
|
||
# bash deploy.sh rebuild [分支] 拉取代码 + 编译 + 启动
|
||
# bash deploy.sh stop 停止
|
||
# bash deploy.sh logs 查看日志
|
||
# bash deploy.sh status 容器状态
|
||
# bash deploy.sh config 检查配置
|
||
# bash deploy.sh init-nacos 初始化 Nacos 配置(仅 Cloud 模式)
|
||
# ============================================
|
||
set -e
|
||
|
||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
cd "$DIR"
|
||
|
||
PROJECT_DIR="$(dirname "$DIR")"
|
||
CMD="${1:-help}"
|
||
BRANCH="${2:-master}"
|
||
|
||
# ============================================
|
||
# 工具函数
|
||
# ============================================
|
||
|
||
# 生成随机 JWT 密钥
|
||
gen_jwt_secret() {
|
||
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 48
|
||
}
|
||
|
||
# TCP 端口连通性检查
|
||
check_port() {
|
||
local host="$1" port="$2" label="$3"
|
||
echo -n " ${label} (${host}:${port}) ... "
|
||
if command -v nc &>/dev/null; then
|
||
if nc -z -w 5 "$host" "$port" 2>/dev/null; then
|
||
echo "✅ 可达"
|
||
return 0
|
||
fi
|
||
elif command -v timeout &>/dev/null; then
|
||
if timeout 5 bash -c "echo >/dev/tcp/${host}/${port}" 2>/dev/null; then
|
||
echo "✅ 可达"
|
||
return 0
|
||
fi
|
||
else
|
||
# macOS 没有 timeout,用 perl 做超时
|
||
if perl -e "use IO::Socket::INET; \$s=IO::Socket::INET->new(PeerAddr=>'$host',PeerPort=>$port,Timeout=>5); exit(1) unless \$s;" 2>/dev/null; then
|
||
echo "✅ 可达"
|
||
return 0
|
||
fi
|
||
fi
|
||
echo "❌ 不可达"
|
||
return 1
|
||
}
|
||
|
||
# MySQL 连接 + 库存在测试
|
||
check_mysql_connect_and_db() {
|
||
local host="$1" port="$2" user="$3" pass="$4" db_name="$5"
|
||
echo -n " MySQL 连接测试 (${user}@${host}:${port}/${db_name}) ... "
|
||
|
||
# 确定用哪个 mysql 客户端
|
||
local mysql_cmd=""
|
||
local connect_host="${host}"
|
||
if command -v mysql &>/dev/null; then
|
||
mysql_cmd="mysql -h${host} -P${port} -u${user} -p${pass}"
|
||
else
|
||
local docker_opts="--network host"
|
||
if [ "${host}" = "127.0.0.1" ] || [ "${host}" = "localhost" ]; then
|
||
if ! docker info 2>/dev/null | grep -q "OSType: linux"; then
|
||
connect_host="host.docker.internal"
|
||
docker_opts=""
|
||
fi
|
||
fi
|
||
mysql_cmd="docker run --rm ${docker_opts} mysql:8.0 mysql -h${connect_host} -P${port} -u${user} -p${pass}"
|
||
fi
|
||
|
||
# 第一步:基础连接测试
|
||
if ! $mysql_cmd -e "SELECT 1" 2>/dev/null >/dev/null; then
|
||
echo "❌ 连接失败(用户名/密码/网络)"
|
||
return 1
|
||
fi
|
||
|
||
# 第二步:库存在测试
|
||
if $mysql_cmd -e "USE ${db_name}" 2>/dev/null >/dev/null; then
|
||
echo "✅ 连接成功,库 '${db_name}' 存在"
|
||
return 0
|
||
fi
|
||
echo "⚠️ 连接成功,但库 '${db_name}' 不存在"
|
||
return 2
|
||
}
|
||
|
||
# Redis 连接测试
|
||
check_redis_connect() {
|
||
local host="$1" port="$2" pass="$3"
|
||
echo -n " Redis 连接测试 (${host}:${port}) ... "
|
||
|
||
local redis_cmd=""
|
||
local connect_host="${host}"
|
||
if command -v redis-cli &>/dev/null; then
|
||
redis_cmd="redis-cli -h ${host} -p ${port}"
|
||
else
|
||
local docker_opts="--network host"
|
||
if [ "${host}" = "127.0.0.1" ] || [ "${host}" = "localhost" ]; then
|
||
if ! docker info 2>/dev/null | grep -q "OSType: linux"; then
|
||
connect_host="host.docker.internal"
|
||
docker_opts=""
|
||
fi
|
||
fi
|
||
redis_cmd="docker run --rm ${docker_opts} redis:7-alpine redis-cli -h ${connect_host} -p ${port}"
|
||
fi
|
||
|
||
if [ -n "$pass" ]; then
|
||
${redis_cmd} -a "${pass}" --no-auth-warning PING 2>/dev/null | grep -q "PONG" && {
|
||
echo "✅ 连接成功"; return 0
|
||
}
|
||
else
|
||
${redis_cmd} PING 2>/dev/null | grep -q "PONG" && {
|
||
echo "✅ 连接成功"; return 0
|
||
}
|
||
fi
|
||
echo "❌ 连接失败"
|
||
return 1
|
||
}
|
||
|
||
# MinIO 连接测试
|
||
check_minio_connect() {
|
||
local host="$1" port="$2" access_key="$3" secret_key="$4"
|
||
echo -n " MinIO 连接测试 (${host}:${port}) ... "
|
||
if curl -s -o /dev/null -w "%{http_code}" "http://${host}:${port}/minio/health/live" 2>/dev/null | grep -q "200"; then
|
||
echo "✅ 可达"
|
||
return 0
|
||
fi
|
||
echo "❌ 不可达"
|
||
return 1
|
||
}
|
||
|
||
# 根据 MODE 变量检查 external 服务连通性
|
||
check_connectivity() {
|
||
local errors=0
|
||
echo ""
|
||
echo ">>> 检查外接服务连通性..."
|
||
if [ "${MYSQL_MODE}" = "external" ]; then
|
||
check_port "${MYSQL_HOST}" "${MYSQL_PORT}" "MySQL" || errors=$((errors + 1))
|
||
fi
|
||
if [ "${REDIS_MODE}" = "external" ]; then
|
||
check_port "${REDIS_HOST}" "${REDIS_PORT}" "Redis" || errors=$((errors + 1))
|
||
fi
|
||
if [ "${MINIO_MODE}" = "external" ]; then
|
||
check_port "${MINIO_HOST}" "${MINIO_PORT}" "MinIO" || errors=$((errors + 1))
|
||
fi
|
||
return $errors
|
||
}
|
||
|
||
# 数据库初始化(通过 mysql 客户端执行 SQL)
|
||
do_init_db() {
|
||
load_env
|
||
|
||
if [ "${MYSQL_MODE}" != "external" ]; then
|
||
echo "ℹ️ MYSQL_MODE=${MYSQL_MODE},使用 Docker MySQL,容器首次启动时自动初始化,无需手动执行。"
|
||
return 0
|
||
fi
|
||
|
||
if [ "${DB_INIT}" != "true" ]; then
|
||
echo "ℹ️ DB_INIT=false,跳过数据库初始化。"
|
||
echo " 如需手动初始化:"
|
||
echo " 1. 在 .env 中设置 DB_INIT=true"
|
||
echo " 2. 将 ../db/ghb_base_init.sql 导入 ${MYSQL_HOST}:${MYSQL_PORT}/${DB_NAME}"
|
||
return 0
|
||
fi
|
||
|
||
local sql_file="${DIR}/../db/ghb_base_init.sql"
|
||
if [ ! -f "$sql_file" ]; then
|
||
echo "❌ SQL 文件不存在: $sql_file"
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
echo "========================================="
|
||
echo " 数据库初始化"
|
||
echo "========================================="
|
||
echo " 目标: ${MYSQL_HOST}:${MYSQL_PORT}/${DB_NAME}"
|
||
echo " SQL: ${sql_file}"
|
||
echo "========================================="
|
||
echo ""
|
||
|
||
echo ">>> 检查 MySQL 连通性..."
|
||
if ! check_port "${MYSQL_HOST}" "${MYSQL_PORT}" "MySQL"; then
|
||
echo "❌ MySQL 不可达,无法初始化数据库"
|
||
exit 1
|
||
fi
|
||
|
||
echo ">>> 正在执行建表脚本..."
|
||
|
||
# 优先使用宿主机 mysql 客户端
|
||
if command -v mysql &>/dev/null; then
|
||
mysql -h"${MYSQL_HOST}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASS}" "${DB_NAME}" < "$sql_file" 2>&1
|
||
local rc=$?
|
||
else
|
||
# 通过 Docker 运行 mysql 客户端,兼容 Mac(host.docker.internal)和 Linux(--network host)
|
||
local connect_host="${MYSQL_HOST}"
|
||
local network_mode="--network host"
|
||
if [ "${MYSQL_HOST}" = "127.0.0.1" ] || [ "${MYSQL_HOST}" = "localhost" ]; then
|
||
# Docker Desktop Mac/Windows 用 host.docker.internal
|
||
if docker info 2>/dev/null | grep -q "OSType: linux"; then
|
||
network_mode="--network host"
|
||
else
|
||
connect_host="host.docker.internal"
|
||
network_mode=""
|
||
fi
|
||
fi
|
||
cat "$sql_file" | docker run --rm -i $network_mode \
|
||
-v "$(dirname "$sql_file"):/sql:ro" \
|
||
mysql:8.0 \
|
||
mysql -h"${connect_host}" -P"${MYSQL_PORT}" -u"${MYSQL_USER}" -p"${MYSQL_PASS}" "${DB_NAME}" 2>&1
|
||
local rc=$?
|
||
fi
|
||
|
||
if [ $rc -eq 0 ]; then
|
||
echo ""
|
||
echo "✅ 数据库初始化完成"
|
||
echo ""
|
||
echo ">>> 为防止重复初始化,请在 .env 中设置 DB_INIT=false"
|
||
# 自动关闭初始化开关,防止重复执行
|
||
if [ -f "${DIR}/.env" ]; then
|
||
sed -i.bak 's/^DB_INIT=true$/DB_INIT=false/' "${DIR}/.env" && rm -f "${DIR}/.env.bak"
|
||
echo " 已自动设置 DB_INIT=false"
|
||
fi
|
||
else
|
||
echo ""
|
||
echo "❌ 数据库初始化失败"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 检查 .env 是否存在
|
||
check_env() {
|
||
if [ ! -f "${DIR}/.env" ]; then
|
||
echo "❌ 未找到 .env,请先执行:bash deploy.sh init"
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
# 加载 .env
|
||
load_env() {
|
||
check_env
|
||
set -a
|
||
source "${DIR}/.env"
|
||
set +a
|
||
}
|
||
|
||
# 获取 compose 命令(根据 MODE 变量自动附加 --profile)
|
||
get_compose_cmd() {
|
||
local compose_file="${COMPOSE_FILE:-docker-compose.yml}"
|
||
local cmd="docker compose -f ${DIR}/${compose_file}"
|
||
local profiles=""
|
||
|
||
[ "${MYSQL_MODE:-docker}" = "docker" ] && profiles="${profiles},mysql"
|
||
[ "${REDIS_MODE:-docker}" = "docker" ] && profiles="${profiles},redis"
|
||
[ "${MINIO_MODE:-none}" = "docker" ] && profiles="${profiles},minio"
|
||
[ "${FRONTEND_ENABLED:-false}" = "true" ] && profiles="${profiles},frontend"
|
||
|
||
profiles="${profiles#,}" # 去掉开头的逗号
|
||
if [ -n "$profiles" ]; then
|
||
for p in ${profiles//,/ }; do
|
||
cmd="${cmd} --profile $p"
|
||
done
|
||
fi
|
||
echo "$cmd"
|
||
}
|
||
|
||
# 等待服务健康
|
||
wait_for_healthy() {
|
||
local container="$1" label="$2" max_wait="${3:-60}"
|
||
echo -n ">>> 等待 ${label} 就绪..."
|
||
for i in $(seq 1 "$max_wait"); do
|
||
local status
|
||
status=$(docker inspect --format='{{.State.Health.Status}}' "$container" 2>/dev/null || echo "unknown")
|
||
if [ "$status" = "healthy" ]; then
|
||
echo " ✅"
|
||
return 0
|
||
fi
|
||
sleep 2
|
||
done
|
||
echo " ❌ 超时"
|
||
return 1
|
||
}
|
||
|
||
# Docker MySQL 启动后验证库是否存在
|
||
verify_mysql_db() {
|
||
local container="${APP_NAME:-test}-mysql"
|
||
local db_name="${DB_NAME:-ghb_base}"
|
||
local pass="${MYSQL_ROOT_PASSWORD:-ChangeMe123}"
|
||
echo -n ">>> 验证数据库 '${db_name}' ... "
|
||
if docker exec "$container" mysql -uroot -p"${pass}" -e "USE ${db_name}" 2>/dev/null >/dev/null; then
|
||
echo "✅ 已就绪"
|
||
return 0
|
||
else
|
||
echo "⚠️ 库 '${db_name}' 不存在,请检查 MySQL 初始化"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# Docker Redis 启动后验证连通性
|
||
verify_redis() {
|
||
local container="${APP_NAME:-test}-redis"
|
||
local pass="${REDIS_PASS:-}"
|
||
echo -n ">>> 验证 Redis 连接 ... "
|
||
if [ -n "$pass" ]; then
|
||
docker exec "$container" redis-cli -a "${pass}" --no-auth-warning PING 2>/dev/null | grep -q "PONG"
|
||
else
|
||
docker exec "$container" redis-cli PING 2>/dev/null | grep -q "PONG"
|
||
fi
|
||
if [ $? -eq 0 ]; then
|
||
echo "✅ 已就绪"
|
||
return 0
|
||
else
|
||
echo "⚠️ Redis 未就绪"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# ============================================
|
||
# init — 交互式初始化 .env
|
||
# ============================================
|
||
do_init() {
|
||
echo ""
|
||
echo "========================================="
|
||
echo " ghb-base 部署配置向导"
|
||
echo "========================================="
|
||
echo ""
|
||
|
||
# === 一级选择:部署架构 ===
|
||
echo "请选择部署架构:"
|
||
echo " 1. 单体"
|
||
echo " 2. Spring Cloud"
|
||
echo ""
|
||
read -r -p "请输入 1/2 [1]: " DEPLOY_MODE
|
||
DEPLOY_MODE="${DEPLOY_MODE:-1}"
|
||
|
||
case "$DEPLOY_MODE" in
|
||
1)
|
||
COMPOSE_FILE="docker-compose.yml"
|
||
MODE_NAME="单体"
|
||
;;
|
||
2)
|
||
COMPOSE_FILE="docker-compose.cloud.yml"
|
||
MODE_NAME="Spring Cloud"
|
||
DEPLOY_MODE=3
|
||
;;
|
||
*)
|
||
echo "❌ 无效选择,请输入 1/2"
|
||
exit 1
|
||
;;
|
||
esac
|
||
echo ""
|
||
echo ">>> 已选择: ${MODE_NAME}"
|
||
echo ""
|
||
|
||
# === 应用配置(DB_NAME 需在 MySQL 测试前获取) ===
|
||
echo "--- 应用配置 ---"
|
||
read -r -p "应用名称 [ghb]: " APP_NAME
|
||
APP_NAME="${APP_NAME:-test}"
|
||
read -r -p "应用端口 [8008]: " APP_PORT
|
||
APP_PORT="${APP_PORT:-8008}"
|
||
read -r -p "数据库名 [ghb_base]: " DB_NAME
|
||
DB_NAME="${DB_NAME:-ghb_base}"
|
||
JWT_SECRET=$(gen_jwt_secret)
|
||
echo ""
|
||
|
||
# === 二级选择:MySQL ===
|
||
echo "--- MySQL ---"
|
||
echo " 1. Docker 一起安装"
|
||
echo " 2. 连接外部服务"
|
||
echo ""
|
||
read -r -p "请选择 1/2 [1]: " MYSQL_MODE_CHOICE
|
||
MYSQL_MODE_CHOICE="${MYSQL_MODE_CHOICE:-1}"
|
||
|
||
case "$MYSQL_MODE_CHOICE" in
|
||
1)
|
||
MYSQL_MODE="docker"
|
||
read -r -p "MySQL 端口 [3306]: " MYSQL_PORT
|
||
MYSQL_PORT="${MYSQL_PORT:-3306}"
|
||
read -r -s -p "MySQL root 密码 [ChangeMe123]: " MYSQL_ROOT_PASSWORD
|
||
echo ""
|
||
MYSQL_ROOT_PASSWORD="${MYSQL_ROOT_PASSWORD:-ChangeMe123}"
|
||
MYSQL_HOST="mysql"
|
||
MYSQL_USER="root"
|
||
MYSQL_PASS="${MYSQL_ROOT_PASSWORD}"
|
||
;;
|
||
2)
|
||
MYSQL_MODE="external"
|
||
echo "请输入外部 MySQL 连接信息:"
|
||
read -r -p " 主机地址 [127.0.0.1]: " MYSQL_HOST
|
||
MYSQL_HOST="${MYSQL_HOST:-127.0.0.1}"
|
||
read -r -p " 端口 [3306]: " MYSQL_PORT
|
||
MYSQL_PORT="${MYSQL_PORT:-3306}"
|
||
read -r -p " 用户名 [root]: " MYSQL_USER
|
||
MYSQL_USER="${MYSQL_USER:-root}"
|
||
read -r -s -p " 密码: " MYSQL_PASS
|
||
echo ""
|
||
echo ""
|
||
echo ">>> 测试 MySQL 连接..."
|
||
check_mysql_connect_and_db "${MYSQL_HOST}" "${MYSQL_PORT}" "${MYSQL_USER}" "${MYSQL_PASS}" "${DB_NAME}"
|
||
local mysql_test_rc=$?
|
||
if [ $mysql_test_rc -eq 2 ]; then
|
||
# 连接成功但库不存在
|
||
echo ""
|
||
echo "⚠️ MySQL 连接成功,但数据库 '${DB_NAME}' 不存在!"
|
||
echo " 请先创建数据库:"
|
||
echo " CREATE DATABASE ${DB_NAME} DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"
|
||
echo ""
|
||
read -r -p "是否仍然继续?[y/N]: " continue_anyway
|
||
if [ "${continue_anyway}" != "y" ] && [ "${continue_anyway}" != "Y" ]; then
|
||
echo "❌ 已取消"
|
||
exit 1
|
||
fi
|
||
elif [ $mysql_test_rc -ne 0 ]; then
|
||
echo ""
|
||
echo "⚠️ MySQL 连接失败!请检查:"
|
||
echo " 1. MySQL 服务是否已启动"
|
||
echo " 2. 主机/端口/用户名/密码是否正确"
|
||
echo " 3. 防火墙是否放行 ${MYSQL_PORT} 端口"
|
||
echo ""
|
||
read -r -p "是否仍然继续?[y/N]: " continue_anyway
|
||
if [ "${continue_anyway}" != "y" ] && [ "${continue_anyway}" != "Y" ]; then
|
||
echo "❌ 已取消"
|
||
exit 1
|
||
fi
|
||
fi
|
||
;;
|
||
*)
|
||
echo "❌ 无效选择"
|
||
exit 1
|
||
;;
|
||
esac
|
||
echo ""
|
||
|
||
# === 二级选择:Redis ===
|
||
echo "--- Redis ---"
|
||
echo " 1. Docker 一起安装"
|
||
echo " 2. 连接外部服务"
|
||
echo ""
|
||
read -r -p "请选择 1/2 [1]: " REDIS_MODE_CHOICE
|
||
REDIS_MODE_CHOICE="${REDIS_MODE_CHOICE:-1}"
|
||
|
||
case "$REDIS_MODE_CHOICE" in
|
||
1)
|
||
REDIS_MODE="docker"
|
||
read -r -p "Redis 端口 [6379]: " REDIS_HOST_PORT
|
||
REDIS_HOST_PORT="${REDIS_HOST_PORT:-6379}"
|
||
read -r -s -p "Redis 密码(无密码直接回车): " REDIS_PASS
|
||
echo ""
|
||
REDIS_HOST="redis"
|
||
REDIS_PORT="6379" # 容器内部固定 6379,App 用此变量连接
|
||
REDIS_DB="0"
|
||
;;
|
||
2)
|
||
REDIS_MODE="external"
|
||
echo "请输入外部 Redis 连接信息:"
|
||
read -r -p " 主机地址 [127.0.0.1]: " REDIS_HOST
|
||
REDIS_HOST="${REDIS_HOST:-127.0.0.1}"
|
||
read -r -p " 端口 [6379]: " REDIS_PORT
|
||
REDIS_PORT="${REDIS_PORT:-6379}"
|
||
read -r -s -p " 密码(无密码直接回车): " REDIS_PASS
|
||
echo ""
|
||
read -r -p " DB 编号 [0]: " REDIS_DB
|
||
REDIS_DB="${REDIS_DB:-0}"
|
||
echo ""
|
||
echo ">>> 测试 Redis 连接..."
|
||
check_redis_connect "${REDIS_HOST}" "${REDIS_PORT}" "${REDIS_PASS}" || {
|
||
echo ""
|
||
echo "⚠️ Redis 连接失败!请检查:"
|
||
echo " 1. Redis 服务是否已启动"
|
||
echo " 2. 主机/端口/密码是否正确"
|
||
echo ""
|
||
read -r -p "是否仍然继续?[y/N]: " continue_anyway
|
||
if [ "${continue_anyway}" != "y" ] && [ "${continue_anyway}" != "Y" ]; then
|
||
echo "❌ 已取消"
|
||
exit 1
|
||
fi
|
||
}
|
||
;;
|
||
*)
|
||
echo "❌ 无效选择"
|
||
exit 1
|
||
;;
|
||
esac
|
||
echo ""
|
||
|
||
# === 二级选择:MinIO ===
|
||
echo "--- MinIO ---"
|
||
echo " 1. Docker 一起安装"
|
||
echo " 2. 连接外部服务"
|
||
echo " 3. 不使用"
|
||
echo ""
|
||
read -r -p "请选择 1/2/3 [3]: " MINIO_MODE_CHOICE
|
||
MINIO_MODE_CHOICE="${MINIO_MODE_CHOICE:-3}"
|
||
|
||
case "$MINIO_MODE_CHOICE" in
|
||
1)
|
||
MINIO_MODE="docker"
|
||
MINIO_HOST="minio"
|
||
read -r -p "MinIO API 端口 [9000]: " MINIO_PORT
|
||
MINIO_PORT="${MINIO_PORT:-9000}"
|
||
read -r -p "MinIO Console 端口 [9001]: " MINIO_CONSOLE_PORT
|
||
MINIO_CONSOLE_PORT="${MINIO_CONSOLE_PORT:-9001}"
|
||
read -r -p "MinIO Access Key [minioadmin]: " MINIO_ACCESS_KEY
|
||
MINIO_ACCESS_KEY="${MINIO_ACCESS_KEY:-minioadmin}"
|
||
while [ "${#MINIO_ACCESS_KEY}" -lt 3 ]; do
|
||
echo "❌ MinIO Access Key 长度至少为 3 位"
|
||
read -r -p "MinIO Access Key [minioadmin]: " MINIO_ACCESS_KEY
|
||
MINIO_ACCESS_KEY="${MINIO_ACCESS_KEY:-minioadmin}"
|
||
done
|
||
read -r -s -p "MinIO Secret Key [minioadmin]: " MINIO_SECRET_KEY
|
||
echo ""
|
||
MINIO_SECRET_KEY="${MINIO_SECRET_KEY:-minioadmin}"
|
||
while [ "${#MINIO_SECRET_KEY}" -lt 8 ]; do
|
||
echo "❌ MinIO Secret Key 长度至少为 8 位"
|
||
read -r -s -p "MinIO Secret Key: " MINIO_SECRET_KEY
|
||
echo ""
|
||
MINIO_SECRET_KEY="${MINIO_SECRET_KEY:-minioadmin}"
|
||
done
|
||
read -r -p "MinIO Bucket 名称 [ghb-base]: " MINIO_BUCKET
|
||
MINIO_BUCKET="${MINIO_BUCKET:-ghb-base}"
|
||
MINIO_ENDPOINT="http://minio:9000"
|
||
;;
|
||
2)
|
||
MINIO_MODE="external"
|
||
echo "请输入外部 MinIO 连接信息:"
|
||
read -r -p " 主机地址 [127.0.0.1]: " MINIO_HOST
|
||
MINIO_HOST="${MINIO_HOST:-127.0.0.1}"
|
||
read -r -p " API 端口 [9000]: " MINIO_PORT
|
||
MINIO_PORT="${MINIO_PORT:-9000}"
|
||
read -r -p " Access Key [minioadmin]: " MINIO_ACCESS_KEY
|
||
MINIO_ACCESS_KEY="${MINIO_ACCESS_KEY:-minioadmin}"
|
||
read -r -s -p " Secret Key [minioadmin]: " MINIO_SECRET_KEY
|
||
echo ""
|
||
MINIO_SECRET_KEY="${MINIO_SECRET_KEY:-minioadmin}"
|
||
read -r -p " Bucket 名称 [ghb-base]: " MINIO_BUCKET
|
||
MINIO_BUCKET="${MINIO_BUCKET:-ghb-base}"
|
||
MINIO_ENDPOINT="http://${MINIO_HOST}:${MINIO_PORT}"
|
||
echo ""
|
||
echo ">>> 测试 MinIO 连接..."
|
||
check_minio_connect "${MINIO_HOST}" "${MINIO_PORT}" "${MINIO_ACCESS_KEY}" "${MINIO_SECRET_KEY}" || {
|
||
echo ""
|
||
echo "⚠️ MinIO 不可达!请检查:"
|
||
echo " 1. MinIO 服务是否已启动"
|
||
echo " 2. 主机/端口是否正确"
|
||
echo ""
|
||
read -r -p "是否仍然继续?[y/N]: " continue_anyway
|
||
if [ "${continue_anyway}" != "y" ] && [ "${continue_anyway}" != "Y" ]; then
|
||
echo "❌ 已取消"
|
||
exit 1
|
||
fi
|
||
}
|
||
;;
|
||
3)
|
||
MINIO_MODE="none"
|
||
MINIO_HOST="127.0.0.1"
|
||
MINIO_PORT="9000"
|
||
MINIO_ACCESS_KEY="minioadmin"
|
||
MINIO_SECRET_KEY="minioadmin"
|
||
MINIO_BUCKET="ghb-base"
|
||
MINIO_ENDPOINT="http://127.0.0.1:9000"
|
||
;;
|
||
*)
|
||
echo "❌ 无效选择"
|
||
exit 1
|
||
;;
|
||
esac
|
||
echo ""
|
||
|
||
# 自动拼接 JDBC URL
|
||
if [ "$MYSQL_MODE" = "docker" ]; then
|
||
MYSQL_URL="jdbc:mysql://mysql:3306/${DB_NAME}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"
|
||
else
|
||
MYSQL_URL="jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${DB_NAME}?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"
|
||
fi
|
||
|
||
# 网络配置
|
||
echo ""
|
||
echo "--- 网络配置 ---"
|
||
read -r -p "Docker 内部网络名 [ghb-net]: " NETWORK_NAME
|
||
NETWORK_NAME="${NETWORK_NAME:-ghb-net}"
|
||
|
||
# SpringCloud 额外配置
|
||
if [ "$DEPLOY_MODE" = "3" ]; then
|
||
echo ""
|
||
echo "--- Spring Cloud 额外配置 ---"
|
||
read -r -p "Nacos 端口 [8848]: " NACOS_PORT
|
||
NACOS_PORT="${NACOS_PORT:-8848}"
|
||
read -r -p "Gateway 端口 [9999]: " GATEWAY_PORT
|
||
GATEWAY_PORT="${GATEWAY_PORT:-9999}"
|
||
read -r -p "System 服务端口 [7001]: " SYSTEM_PORT
|
||
SYSTEM_PORT="${SYSTEM_PORT:-7001}"
|
||
fi
|
||
|
||
# 数据库初始化(external MySQL 时)
|
||
DB_INIT="false"
|
||
if [ "$MYSQL_MODE" = "external" ]; then
|
||
echo ""
|
||
read -r -p "外接数据库是否已建表?[Y/n]: " DB_READY
|
||
if [ "${DB_READY}" != "Y" ] && [ "${DB_READY}" != "y" ] && [ -n "${DB_READY}" ]; then
|
||
echo " 如果数据库是空的,可以自动执行建表脚本(${PROJECT_DIR}/db/ghb_base_init.sql)"
|
||
read -r -p " 是否自动初始化数据库表?[y/N]: " DO_INIT_DB
|
||
if [ "${DO_INIT_DB}" = "y" ] || [ "${DO_INIT_DB}" = "Y" ]; then
|
||
DB_INIT="true"
|
||
fi
|
||
fi
|
||
fi
|
||
|
||
# 前端集成
|
||
FRONTEND_ENABLED="false"
|
||
echo ""
|
||
read -r -p "是否集成前端(需要先 cd ghb-frontend && pnpm build 生成 dist)?[y/N]: " ENABLE_FRONTEND
|
||
if [ "${ENABLE_FRONTEND}" = "y" ] || [ "${ENABLE_FRONTEND}" = "Y" ]; then
|
||
FRONTEND_ENABLED="true"
|
||
read -r -p "前端端口 [80]: " FRONTEND_PORT
|
||
FRONTEND_PORT="${FRONTEND_PORT:-80}"
|
||
fi
|
||
|
||
# === 生成 .env 文件 ===
|
||
echo ""
|
||
echo ">>> 正在生成 .env 文件..."
|
||
|
||
cat > "${DIR}/.env" << EOF
|
||
# ============================================
|
||
# ghb-base 部署配置
|
||
# 生成时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||
# 部署架构: ${MODE_NAME}
|
||
# ============================================
|
||
|
||
DEPLOY_MODE=${DEPLOY_MODE}
|
||
COMPOSE_FILE=${COMPOSE_FILE}
|
||
|
||
# 应用
|
||
APP_NAME=${APP_NAME}
|
||
APP_PORT=${APP_PORT}
|
||
JAVA_OPTS="-Xms512m -Xmx512m"
|
||
|
||
# 数据库
|
||
DB_NAME=${DB_NAME}
|
||
|
||
# 网络
|
||
NETWORK_NAME=${NETWORK_NAME}
|
||
|
||
# ---- 中间件策略 ----
|
||
# docker = Docker 一起安装 | external = 连接外部服务 | none = 不使用(仅 MinIO)
|
||
MYSQL_MODE=${MYSQL_MODE}
|
||
REDIS_MODE=${REDIS_MODE}
|
||
MINIO_MODE=${MINIO_MODE}
|
||
EOF
|
||
|
||
# MySQL 配置
|
||
if [ "$MYSQL_MODE" = "docker" ]; then
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- MySQL(Docker) ----
|
||
MYSQL_PORT=${MYSQL_PORT}
|
||
MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
|
||
MYSQL_HOST=${MYSQL_HOST}
|
||
MYSQL_USER=${MYSQL_USER}
|
||
MYSQL_PASS='${MYSQL_PASS}'
|
||
MYSQL_URL='${MYSQL_URL}'
|
||
EOF
|
||
else
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- MySQL(外部) ----
|
||
MYSQL_HOST=${MYSQL_HOST}
|
||
MYSQL_PORT=${MYSQL_PORT}
|
||
MYSQL_USER=${MYSQL_USER}
|
||
MYSQL_PASS='${MYSQL_PASS}'
|
||
MYSQL_URL='${MYSQL_URL}'
|
||
EOF
|
||
fi
|
||
|
||
# Redis 配置
|
||
if [ "$REDIS_MODE" = "docker" ]; then
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- Redis(Docker) ----
|
||
REDIS_PORT=${REDIS_PORT}
|
||
REDIS_HOST_PORT=${REDIS_HOST_PORT}
|
||
REDIS_PASS='${REDIS_PASS}'
|
||
REDIS_HOST=${REDIS_HOST}
|
||
REDIS_DB=${REDIS_DB}
|
||
EOF
|
||
else
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- Redis(外部) ----
|
||
REDIS_HOST=${REDIS_HOST}
|
||
REDIS_PORT=${REDIS_PORT}
|
||
REDIS_PASS='${REDIS_PASS}'
|
||
REDIS_DB=${REDIS_DB}
|
||
EOF
|
||
fi
|
||
|
||
# MinIO 配置
|
||
if [ "$MINIO_MODE" = "docker" ]; then
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- MinIO(Docker) ----
|
||
MINIO_HOST=${MINIO_HOST}
|
||
MINIO_PORT=${MINIO_PORT}
|
||
MINIO_CONSOLE_PORT=${MINIO_CONSOLE_PORT}
|
||
MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
|
||
MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
|
||
MINIO_BUCKET=${MINIO_BUCKET}
|
||
MINIO_ENDPOINT=${MINIO_ENDPOINT}
|
||
EOF
|
||
elif [ "$MINIO_MODE" = "external" ]; then
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- MinIO(外部) ----
|
||
MINIO_HOST=${MINIO_HOST}
|
||
MINIO_PORT=${MINIO_PORT}
|
||
MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
|
||
MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
|
||
MINIO_BUCKET=${MINIO_BUCKET}
|
||
MINIO_ENDPOINT=${MINIO_ENDPOINT}
|
||
EOF
|
||
else
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- MinIO(不使用) ----
|
||
MINIO_HOST=127.0.0.1
|
||
MINIO_PORT=9000
|
||
MINIO_ACCESS_KEY=minioadmin
|
||
MINIO_SECRET_KEY=minioadmin
|
||
MINIO_BUCKET=ghb-base
|
||
MINIO_ENDPOINT=http://127.0.0.1:9000
|
||
EOF
|
||
fi
|
||
|
||
# SpringCloud 额外配置
|
||
if [ "$DEPLOY_MODE" = "3" ]; then
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# ---- Spring Cloud ----
|
||
NACOS_PORT=${NACOS_PORT}
|
||
GATEWAY_PORT=${GATEWAY_PORT}
|
||
SYSTEM_PORT=${SYSTEM_PORT}
|
||
EOF
|
||
fi
|
||
|
||
# 数据库初始化
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# 数据库初始化(true 时 start/rebuild 会自动建表)
|
||
DB_INIT=${DB_INIT}
|
||
EOF
|
||
|
||
# JWT
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# JWT
|
||
JWT_SECRET='${JWT_SECRET}'
|
||
EOF
|
||
|
||
# 前端
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# 前端集成
|
||
FRONTEND_ENABLED=${FRONTEND_ENABLED}
|
||
EOF
|
||
if [ "${FRONTEND_ENABLED}" = "true" ]; then
|
||
echo "FRONTEND_PORT=${FRONTEND_PORT}" >> "${DIR}/.env"
|
||
fi
|
||
|
||
# 上传方式
|
||
cat >> "${DIR}/.env" << EOF
|
||
|
||
# 上传方式: local(本地) / minio(MinIO)
|
||
JEECG_UPLOAD_TYPE=local
|
||
|
||
# 跳过连通性检查(true 时不检查外接服务是否可达)
|
||
SKIP_CONNECTIVITY_CHECK=false
|
||
EOF
|
||
|
||
# === 输出摘要 ===
|
||
echo ""
|
||
echo "========================================="
|
||
echo " ✅ .env 文件已生成"
|
||
echo "========================================="
|
||
echo ""
|
||
echo "部署架构: ${MODE_NAME}"
|
||
echo "MySQL: ${MYSQL_MODE}"
|
||
echo "Redis: ${REDIS_MODE}"
|
||
echo "MinIO: ${MINIO_MODE}"
|
||
if [ "${FRONTEND_ENABLED}" = "true" ]; then
|
||
echo "前端: 已集成(端口 ${FRONTEND_PORT:-80})"
|
||
echo " 注意:需要先 cd ghb-frontend && pnpm build 生成 dist/"
|
||
fi
|
||
echo ""
|
||
echo "下一步:"
|
||
echo " bash deploy.sh build # 编译镜像"
|
||
echo " bash deploy.sh start # 启动服务"
|
||
if [ "$DEPLOY_MODE" = "3" ]; then
|
||
echo " bash deploy.sh init-nacos # 初始化 Nacos 配置"
|
||
fi
|
||
echo ""
|
||
}
|
||
|
||
# ============================================
|
||
# start — 启动
|
||
# ============================================
|
||
do_start() {
|
||
load_env
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
local COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}"
|
||
|
||
echo ">>> 部署架构: ${DEPLOY_MODE:-1}"
|
||
echo ">>> MySQL: ${MYSQL_MODE:-docker} Redis: ${REDIS_MODE:-docker} MinIO: ${MINIO_MODE:-none}"
|
||
|
||
# 检查 external 服务连通性
|
||
if [ "${SKIP_CONNECTIVITY_CHECK:-false}" != "true" ]; then
|
||
check_connectivity || {
|
||
echo ""
|
||
echo "⚠️ 部分外接服务不可达,部署可能失败。"
|
||
echo ""
|
||
echo " 请选择:"
|
||
echo " 1. 退出,先修复连接问题"
|
||
echo " 2. 强制部署(跳过检查)"
|
||
echo ""
|
||
read -r -p " 请输入 1/2 [1]: " choice
|
||
case "${choice:-1}" in
|
||
2) echo ">>> 跳过检查,强制部署..." ;;
|
||
*) echo "❌ 已取消"; exit 1 ;;
|
||
esac
|
||
}
|
||
fi
|
||
|
||
echo ">>> 停掉旧容器..."
|
||
$COMPOSE_CMD down 2>/dev/null || true
|
||
echo ""
|
||
|
||
if [ "${DEPLOY_MODE}" = "3" ]; then
|
||
# ============================================
|
||
# Cloud 模式:分阶段启动
|
||
# Phase 1: docker 中间件 → Nacos
|
||
# Phase 2: 推送配置 → 业务服务
|
||
# ============================================
|
||
|
||
echo ">>> [Phase 1] 启动中间件和 Nacos..."
|
||
|
||
# 按需启动 docker 中间件
|
||
if [ "${MYSQL_MODE:-docker}" = "docker" ]; then
|
||
echo " 启动 MySQL..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile mysql up -d --force-recreate mysql
|
||
wait_for_healthy "${APP_NAME:-test}-mysql" "MySQL" 60 || {
|
||
echo "❌ MySQL 启动失败"
|
||
exit 1
|
||
}
|
||
verify_mysql_db
|
||
fi
|
||
if [ "${REDIS_MODE:-docker}" = "docker" ]; then
|
||
echo " 启动 Redis..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile redis up -d --force-recreate redis
|
||
wait_for_healthy "${APP_NAME:-test}-redis" "Redis" 30 || {
|
||
echo "❌ Redis 启动失败"
|
||
exit 1
|
||
}
|
||
verify_redis
|
||
fi
|
||
|
||
# 启动 Nacos
|
||
echo " 启动 Nacos..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" up -d --force-recreate nacos
|
||
|
||
# 等待 Nacos 健康
|
||
echo ">>> 等待 Nacos 就绪..."
|
||
local NACOS_HEALTH_URL="http://localhost:${NACOS_PORT:-8848}/nacos/v1/console/health/liveness"
|
||
for i in $(seq 1 60); do
|
||
if curl -s "$NACOS_HEALTH_URL" 2>/dev/null | grep -q "OK"; then
|
||
echo " ✅ Nacos 已就绪"
|
||
break
|
||
fi
|
||
if [ "$i" -eq 60 ]; then
|
||
echo " ❌ Nacos 启动超时,请检查日志: docker logs ${APP_NAME:-test}-nacos"
|
||
exit 1
|
||
fi
|
||
sleep 3
|
||
done
|
||
|
||
# 首次部署:Nacos 无配置则自动导入
|
||
echo ">>> 检查 Nacos 配置..."
|
||
local CHECK_RESP
|
||
CHECK_RESP=$(curl -s "http://localhost:${NACOS_PORT:-8848}/nacos/v1/cs/configs?dataId=jeecg.yaml&group=DEFAULT_GROUP")
|
||
if [ -z "$CHECK_RESP" ] || [ "$CHECK_RESP" = "config data not exist" ]; then
|
||
echo " 首次部署,自动导入配置..."
|
||
NACOS_URL="http://localhost:${NACOS_PORT:-8848}" bash "${DIR}/init-nacos.sh"
|
||
else
|
||
echo " ✅ Nacos 配置已存在,跳过导入"
|
||
fi
|
||
|
||
# Phase 2: 启动业务服务
|
||
echo ""
|
||
echo ">>> [Phase 2] 启动业务服务..."
|
||
$COMPOSE_CMD up -d --force-recreate
|
||
|
||
echo ""
|
||
echo "✅ 已启动"
|
||
echo " Nacos: http://localhost:${NACOS_PORT:-8848}/nacos"
|
||
echo " Gateway: http://localhost:${GATEWAY_PORT:-9999}"
|
||
echo " System: http://localhost:${SYSTEM_PORT:-7001}"
|
||
if [ "${MINIO_MODE:-none}" = "docker" ]; then
|
||
echo " MinIO: http://localhost:${MINIO_PORT:-9000} (Console: ${MINIO_CONSOLE_PORT:-9001})"
|
||
fi
|
||
if [ "${FRONTEND_ENABLED:-false}" = "true" ]; then
|
||
echo " 前端: http://localhost:${FRONTEND_PORT:-80}"
|
||
fi
|
||
else
|
||
# ============================================
|
||
# 单体模式:按需分步启动
|
||
# ============================================
|
||
|
||
# 先启动 docker 中间件
|
||
if [ "${MYSQL_MODE:-docker}" = "docker" ]; then
|
||
echo ">>> 启动 MySQL..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile mysql up -d --force-recreate mysql
|
||
wait_for_healthy "${APP_NAME:-test}-mysql" "MySQL" 60 || {
|
||
echo "❌ MySQL 启动失败"
|
||
exit 1
|
||
}
|
||
verify_mysql_db
|
||
fi
|
||
if [ "${REDIS_MODE:-docker}" = "docker" ]; then
|
||
echo ">>> 启动 Redis..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile redis up -d --force-recreate redis
|
||
wait_for_healthy "${APP_NAME:-test}-redis" "Redis" 30 || {
|
||
echo "❌ Redis 启动失败"
|
||
exit 1
|
||
}
|
||
verify_redis
|
||
fi
|
||
if [ "${MINIO_MODE:-none}" = "docker" ]; then
|
||
echo ">>> 启动 MinIO..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile minio up -d --force-recreate minio
|
||
fi
|
||
|
||
# 启动 app(及其它 profiled 服务如 frontend)
|
||
echo ">>> 启动应用..."
|
||
$COMPOSE_CMD up -d --force-recreate
|
||
|
||
echo ""
|
||
echo "✅ 已启动"
|
||
echo " 地址: http://localhost:${APP_PORT}/ghb"
|
||
if [ "${MINIO_MODE:-none}" = "docker" ]; then
|
||
echo " MinIO: http://localhost:${MINIO_PORT:-9000} (Console: ${MINIO_CONSOLE_PORT:-9001})"
|
||
fi
|
||
if [ "${FRONTEND_ENABLED:-false}" = "true" ]; then
|
||
echo " 前端: http://localhost:${FRONTEND_PORT:-80}"
|
||
fi
|
||
fi
|
||
echo " 日志: bash deploy.sh logs"
|
||
}
|
||
|
||
# ============================================
|
||
# build — 编译镜像
|
||
# ============================================
|
||
do_build() {
|
||
load_env
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
|
||
echo ">>> 部署架构: ${DEPLOY_MODE:-1}"
|
||
echo ">>> 编译镜像..."
|
||
|
||
if [ "${DEPLOY_MODE}" = "3" ]; then
|
||
echo " 编译所有 Cloud 服务(首次较慢,约 10-20 分钟)..."
|
||
$COMPOSE_CMD build
|
||
else
|
||
$COMPOSE_CMD build app
|
||
fi
|
||
|
||
echo ""
|
||
echo "✅ 编译完成,执行 bash deploy.sh start 启动"
|
||
}
|
||
|
||
# ============================================
|
||
# rebuild — 拉取代码 + 编译 + 启动
|
||
# ============================================
|
||
do_rebuild() {
|
||
load_env
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
local COMPOSE_FILE="${COMPOSE_FILE:-docker-compose.yml}"
|
||
|
||
echo ">>> 部署架构: ${DEPLOY_MODE:-1}"
|
||
echo ">>> 切到分支 ${BRANCH} 并拉取最新代码..."
|
||
|
||
# 拉代码前检查 external 服务连通性
|
||
if [ "${SKIP_CONNECTIVITY_CHECK:-false}" != "true" ]; then
|
||
check_connectivity || {
|
||
echo ""
|
||
echo "⚠️ 部分外接服务不可达,部署可能失败。"
|
||
read -r -p " 是否强制继续?[y/N]: " force
|
||
if [ "${force}" != "y" ] && [ "${force}" != "Y" ]; then
|
||
echo "❌ 已取消"
|
||
exit 1
|
||
fi
|
||
echo ">>> 跳过检查,强制继续..."
|
||
}
|
||
fi
|
||
|
||
if [ "${DEPLOY_MODE}" = "3" ]; then
|
||
# Cloud 模式:需要拉取完整仓库(ghb-base 根目录)
|
||
local REPO_DIR="$(dirname "$PROJECT_DIR")"
|
||
cd "$REPO_DIR"
|
||
else
|
||
cd "$PROJECT_DIR"
|
||
fi
|
||
|
||
git fetch origin
|
||
git checkout "${BRANCH}"
|
||
git pull origin "${BRANCH}"
|
||
|
||
cd "$DIR"
|
||
|
||
echo ""
|
||
echo ">>> 重新编译..."
|
||
|
||
if [ "${DEPLOY_MODE}" = "3" ]; then
|
||
echo " 编译所有 Cloud 服务(首次较慢,约 10-20 分钟)..."
|
||
$COMPOSE_CMD build --no-cache
|
||
else
|
||
$COMPOSE_CMD build --no-cache app
|
||
fi
|
||
|
||
echo ""
|
||
if [ "${DEPLOY_MODE}" = "3" ]; then
|
||
# Cloud 模式:分阶段启动
|
||
echo ">>> [Phase 1] 启动中间件和 Nacos..."
|
||
$COMPOSE_CMD down 2>/dev/null || true
|
||
|
||
if [ "${MYSQL_MODE:-docker}" = "docker" ]; then
|
||
echo " 启动 MySQL..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile mysql up -d --force-recreate mysql
|
||
wait_for_healthy "${APP_NAME:-test}-mysql" "MySQL" 60 || {
|
||
echo "❌ MySQL 启动失败"
|
||
exit 1
|
||
}
|
||
verify_mysql_db
|
||
fi
|
||
if [ "${REDIS_MODE:-docker}" = "docker" ]; then
|
||
echo " 启动 Redis..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile redis up -d --force-recreate redis
|
||
wait_for_healthy "${APP_NAME:-test}-redis" "Redis" 30 || {
|
||
echo "❌ Redis 启动失败"
|
||
exit 1
|
||
}
|
||
verify_redis
|
||
fi
|
||
|
||
echo " 启动 Nacos..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" up -d --force-recreate nacos
|
||
|
||
echo ">>> 等待 Nacos 就绪..."
|
||
local NACOS_HEALTH_URL="http://localhost:${NACOS_PORT:-8848}/nacos/v1/console/health/liveness"
|
||
for i in $(seq 1 60); do
|
||
if curl -s "$NACOS_HEALTH_URL" 2>/dev/null | grep -q "OK"; then
|
||
echo " ✅ Nacos 已就绪"
|
||
break
|
||
fi
|
||
if [ "$i" -eq 60 ]; then
|
||
echo " ❌ Nacos 启动超时"
|
||
exit 1
|
||
fi
|
||
sleep 3
|
||
done
|
||
|
||
# 首次部署:Nacos 无配置则自动导入
|
||
echo ">>> 检查 Nacos 配置..."
|
||
local CHECK_RESP
|
||
CHECK_RESP=$(curl -s "http://localhost:${NACOS_PORT:-8848}/nacos/v1/cs/configs?dataId=jeecg.yaml&group=DEFAULT_GROUP")
|
||
if [ -z "$CHECK_RESP" ] || [ "$CHECK_RESP" = "config data not exist" ]; then
|
||
echo " 首次部署,自动导入配置..."
|
||
NACOS_URL="http://localhost:${NACOS_PORT:-8848}" bash "${DIR}/init-nacos.sh"
|
||
else
|
||
echo " ✅ Nacos 配置已存在,跳过导入"
|
||
fi
|
||
|
||
echo ""
|
||
echo ">>> [Phase 2] 启动业务服务..."
|
||
$COMPOSE_CMD up -d --force-recreate
|
||
|
||
echo ""
|
||
echo "✅ 重新部署完成(分支: ${BRANCH})"
|
||
else
|
||
# 单体模式:按需分步启动
|
||
$COMPOSE_CMD down 2>/dev/null || true
|
||
|
||
if [ "${MYSQL_MODE:-docker}" = "docker" ]; then
|
||
echo ">>> 启动 MySQL..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile mysql up -d --force-recreate mysql
|
||
wait_for_healthy "${APP_NAME:-test}-mysql" "MySQL" 60 || {
|
||
echo "❌ MySQL 启动失败"
|
||
exit 1
|
||
}
|
||
verify_mysql_db
|
||
fi
|
||
if [ "${REDIS_MODE:-docker}" = "docker" ]; then
|
||
echo ">>> 启动 Redis..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile redis up -d --force-recreate redis
|
||
wait_for_healthy "${APP_NAME:-test}-redis" "Redis" 30 || {
|
||
echo "❌ Redis 启动失败"
|
||
exit 1
|
||
}
|
||
verify_redis
|
||
fi
|
||
if [ "${MINIO_MODE:-none}" = "docker" ]; then
|
||
echo ">>> 启动 MinIO..."
|
||
docker compose -f "${DIR}/${COMPOSE_FILE}" --profile minio up -d --force-recreate minio
|
||
fi
|
||
|
||
echo ">>> 启动应用..."
|
||
$COMPOSE_CMD up -d --force-recreate
|
||
echo ""
|
||
echo "✅ 重新部署完成(分支: ${BRANCH})"
|
||
fi
|
||
}
|
||
|
||
# ============================================
|
||
# stop — 停止
|
||
# ============================================
|
||
do_stop() {
|
||
load_env
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
|
||
$COMPOSE_CMD stop 2>/dev/null || true
|
||
echo "✅ 已停止"
|
||
}
|
||
|
||
# ============================================
|
||
# logs — 查看日志
|
||
# ============================================
|
||
do_logs() {
|
||
load_env
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
|
||
$COMPOSE_CMD logs -f --tail=200
|
||
}
|
||
|
||
# ============================================
|
||
# status — 容器状态
|
||
# ============================================
|
||
do_status() {
|
||
load_env
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
|
||
$COMPOSE_CMD ps -a
|
||
}
|
||
|
||
# ============================================
|
||
# config — 检查配置
|
||
# ============================================
|
||
do_config() {
|
||
load_env
|
||
echo "========================================="
|
||
echo " 部署架构: ${DEPLOY_MODE:-1}($( [ "${DEPLOY_MODE:-1}" = "3" ] && echo "Spring Cloud" || echo "单体" ))"
|
||
echo " Compose 文件: ${COMPOSE_FILE:-docker-compose.yml}"
|
||
echo " MySQL: ${MYSQL_MODE:-docker}"
|
||
echo " Redis: ${REDIS_MODE:-docker}"
|
||
echo " MinIO: ${MINIO_MODE:-none}"
|
||
echo " 网络: ${NETWORK_NAME:-ghb-net}"
|
||
echo "========================================="
|
||
echo ""
|
||
echo "========================================="
|
||
echo " .env 文件内容(敏感信息已脱敏)"
|
||
echo "========================================="
|
||
grep -v '^#' "${DIR}/.env" | grep -v '^$' | sed 's/\(PASS=\).*/\1***/' | sed 's/\(PWD=\).*/\1***/' | sed 's/\(PASSWORD=\).*/\1***/' | sed 's/\(SECRET=\).*/\1***/' | sed 's/\(_KEY=\).*/\1***/'
|
||
echo ""
|
||
echo "========================================="
|
||
echo " Docker 解析后的环境变量"
|
||
echo "========================================="
|
||
local COMPOSE_CMD
|
||
COMPOSE_CMD=$(get_compose_cmd)
|
||
$COMPOSE_CMD config 2>&1 | grep -E 'MYSQL_|REDIS_|JWT_|SPRING_|APP_|JAVA|MYSQL-|NACOS|GATEWAY|DB_|MINIO_|NETWORK_' | sed 's/\(PASS: \).*/\1***/' | sed 's/\(PWD: \).*/\1***/' | sed 's/\(SECRET: \).*/\1***/' | sed 's/\(_KEY: \).*/\1***/'
|
||
echo ""
|
||
|
||
if [ "${DEPLOY_MODE}" != "3" ]; then
|
||
echo "========================================="
|
||
echo " application-prod.yml 内容"
|
||
echo "========================================="
|
||
cat "${DIR}/config/application-prod.yml"
|
||
echo ""
|
||
fi
|
||
|
||
if [ "${DEPLOY_MODE}" = "3" ]; then
|
||
echo "========================================="
|
||
echo " Nacos 配置文件列表(部署后执行 init-nacos 导入)"
|
||
echo "========================================="
|
||
ls -la "${DIR}/nacos/config/" 2>/dev/null || echo " (无)"
|
||
echo ""
|
||
fi
|
||
}
|
||
|
||
# ============================================
|
||
# init-nacos — 导入 Nacos 配置(仅 Cloud 模式)
|
||
# ============================================
|
||
do_init_nacos() {
|
||
load_env
|
||
|
||
if [ "${DEPLOY_MODE}" != "3" ]; then
|
||
echo "❌ 当前部署架构为 ${DEPLOY_MODE:-1},Nacos 配置仅适用于 Spring Cloud 模式"
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -f "${DIR}/init-nacos.sh" ]; then
|
||
echo "❌ 未找到 init-nacos.sh"
|
||
exit 1
|
||
fi
|
||
|
||
NACOS_URL="http://localhost:${NACOS_PORT:-8848}" bash "${DIR}/init-nacos.sh" "$@"
|
||
}
|
||
|
||
# ============================================
|
||
# help
|
||
# ============================================
|
||
do_help() {
|
||
echo "用法: bash deploy.sh <命令> [分支]"
|
||
echo ""
|
||
echo "命令:"
|
||
echo " init 交互式初始化 .env 配置文件"
|
||
echo " start 停旧容器 → 启动(日常使用,不重新编译)"
|
||
echo " build [分支] 编译镜像(代码变更后用一次)"
|
||
echo " rebuild [分支] 拉取分支代码 + 编译 + 启动(一步到位)"
|
||
echo " stop 停止所有容器"
|
||
echo " logs 查看日志"
|
||
echo " status 查看容器状态"
|
||
echo " config 检查配置(不启动)"
|
||
echo " init-db 初始化外接数据库表(仅 external MySQL)"
|
||
echo " init-nacos 初始化 Nacos 配置(仅 Spring Cloud 模式)"
|
||
echo ""
|
||
echo "部署架构:"
|
||
echo " 1. 单体 → docker-compose.yml"
|
||
echo " 3. Spring Cloud → docker-compose.cloud.yml"
|
||
echo ""
|
||
echo "中间件策略(init 时独立选择):"
|
||
echo " MySQL: docker(Docker 安装)/ external(连接外部)"
|
||
echo " Redis: docker(Docker 安装)/ external(连接外部)"
|
||
echo " MinIO: docker(Docker 安装)/ external(连接外部)/ none(不使用)"
|
||
echo ""
|
||
echo "示例:"
|
||
echo " bash deploy.sh init # 首次:交互式配置"
|
||
echo " bash deploy.sh build # 编译镜像"
|
||
echo " bash deploy.sh start # 启动"
|
||
echo " bash deploy.sh rebuild test # 拉取 test 分支 + 编译 + 启动"
|
||
echo " bash deploy.sh logs # 查看日志"
|
||
}
|
||
|
||
# ============================================
|
||
# 路由
|
||
# ============================================
|
||
case "$CMD" in
|
||
init) do_init ;;
|
||
start) do_start ;;
|
||
build) do_build ;;
|
||
rebuild) do_rebuild ;;
|
||
stop) do_stop ;;
|
||
logs) do_logs ;;
|
||
status) do_status ;;
|
||
config) do_config ;;
|
||
init-nacos) do_init_nacos ;;
|
||
init-db) do_init_db ;;
|
||
help|--help|-h) do_help ;;
|
||
*)
|
||
do_help
|
||
;;
|
||
esac
|