1129 lines
33 KiB
Bash
Executable File
1129 lines
33 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
# 情绪博物馆阿里云服务器优化部署脚本
|
||
# 适配要求:MySQL/Redis/Nacos直接安装,应用服务使用Docker
|
||
# 分步骤执行,避免超时,记录密码到MD文件
|
||
# 作者: EmotionMuseum Team
|
||
# 日期: 2025-07-13
|
||
|
||
set -e
|
||
|
||
# 颜色定义
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
BLUE='\033[0;34m'
|
||
PURPLE='\033[0;35m'
|
||
CYAN='\033[0;36m'
|
||
NC='\033[0m'
|
||
|
||
# 服务器配置
|
||
SERVER_IP="47.111.10.27"
|
||
SERVER_USER="root"
|
||
MYSQL_ROOT_PASSWORD="123456"
|
||
|
||
# 部署目录配置
|
||
PROGRAMS_DIR="/data/programs"
|
||
BUILDS_DIR="/data/builds"
|
||
WEB_DIR="/data/www/emotion-museum"
|
||
LOGS_DIR="/data/logs/emotion-museum"
|
||
CONFIG_FILE="/data/deployment_passwords.md"
|
||
|
||
# 生成密码函数
|
||
generate_password() {
|
||
echo $(openssl rand -base64 32 | tr -d "=+/" | cut -c1-20)
|
||
}
|
||
|
||
# 日志函数
|
||
log_info() {
|
||
echo -e "${GREEN}[INFO]${NC} $1"
|
||
}
|
||
|
||
log_warn() {
|
||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||
}
|
||
|
||
log_error() {
|
||
echo -e "${RED}[ERROR]${NC} $1"
|
||
}
|
||
|
||
log_step() {
|
||
echo -e "${BLUE}[STEP]${NC} $1"
|
||
}
|
||
|
||
log_success() {
|
||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||
}
|
||
|
||
log_debug() {
|
||
echo -e "${CYAN}[DEBUG]${NC} $1"
|
||
}
|
||
|
||
# 远程执行命令
|
||
remote_exec() {
|
||
local command="$1"
|
||
local timeout="${2:-60}"
|
||
ssh -o StrictHostKeyChecking=no -o ConnectTimeout="$timeout" -o ServerAliveInterval=30 -o ServerAliveCountMax=3 "${SERVER_USER}@${SERVER_IP}" "$command"
|
||
}
|
||
|
||
# 复制文件到服务器
|
||
remote_copy() {
|
||
local local_path="$1"
|
||
local remote_path="$2"
|
||
scp -o StrictHostKeyChecking=no -r "$local_path" "${SERVER_USER}@${SERVER_IP}:$remote_path"
|
||
}
|
||
|
||
# 检查服务器连接
|
||
check_server_connection() {
|
||
log_step "检查服务器连接..."
|
||
|
||
if ! ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 "${SERVER_USER}@${SERVER_IP}" "echo 'Connected to server successfully'" &>/dev/null; then
|
||
log_error "无法连接到服务器 ${SERVER_IP},请检查网络连接和SSH配置"
|
||
exit 1
|
||
fi
|
||
|
||
log_success "服务器连接正常"
|
||
|
||
# 显示服务器基本信息
|
||
log_info "服务器信息:"
|
||
remote_exec "echo ' 内核版本: '$(uname -r)"
|
||
remote_exec "echo ' 当前用户: '$(whoami)"
|
||
remote_exec "echo ' 当前时间: '$(date)"
|
||
}
|
||
|
||
# 创建服务器目录结构
|
||
setup_directories() {
|
||
log_step "创建服务器目录结构..."
|
||
|
||
remote_exec "mkdir -p ${PROGRAMS_DIR}/{java,maven,nodejs,nacos}"
|
||
remote_exec "mkdir -p ${BUILDS_DIR}"
|
||
remote_exec "mkdir -p ${WEB_DIR}"
|
||
remote_exec "mkdir -p ${LOGS_DIR}/{mysql,redis,nacos,docker,nginx}"
|
||
remote_exec "mkdir -p /data/backup"
|
||
remote_exec "mkdir -p /data/ssl"
|
||
|
||
log_success "目录结构创建完成"
|
||
remote_exec "tree /data -L 2 2>/dev/null || ls -la /data"
|
||
}
|
||
|
||
# 安装基础软件包
|
||
install_basic_packages() {
|
||
log_step "安装基础软件包..."
|
||
|
||
remote_exec "yum update -y"
|
||
remote_exec "yum install -y wget curl git unzip vim net-tools tree htop"
|
||
|
||
log_success "基础软件包安装完成"
|
||
}
|
||
|
||
# 安装Docker
|
||
install_docker() {
|
||
log_step "安装Docker..."
|
||
|
||
remote_exec "
|
||
if ! command -v docker &> /dev/null; then
|
||
echo '开始安装Docker...'
|
||
curl -fsSL https://get.docker.com | sh
|
||
systemctl start docker
|
||
systemctl enable docker
|
||
|
||
# 安装Docker Compose
|
||
curl -L \"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-\$(uname -s)-\$(uname -m)\" -o /usr/local/bin/docker-compose
|
||
chmod +x /usr/local/bin/docker-compose
|
||
ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose
|
||
|
||
echo 'Docker和Docker Compose安装完成'
|
||
docker --version
|
||
docker-compose --version
|
||
else
|
||
echo 'Docker已安装: '$(docker --version)
|
||
if ! command -v docker-compose &> /dev/null; then
|
||
echo '安装Docker Compose...'
|
||
curl -L \"https://github.com/docker/compose/releases/download/1.29.2/docker-compose-\$(uname -s)-\$(uname -m)\" -o /usr/local/bin/docker-compose
|
||
chmod +x /usr/local/bin/docker-compose
|
||
ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose
|
||
fi
|
||
echo 'Docker Compose: '$(docker-compose --version)
|
||
fi
|
||
"
|
||
|
||
log_success "Docker安装检查完成"
|
||
}
|
||
|
||
# 安装Java环境
|
||
install_java() {
|
||
log_step "安装Java环境..."
|
||
|
||
remote_exec "
|
||
if ! java -version 2>&1 | grep -q '17'; then
|
||
echo '安装Java 17...'
|
||
yum install -y java-17-openjdk java-17-openjdk-devel
|
||
|
||
# 配置环境变量
|
||
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk' >> /etc/profile
|
||
echo 'export PATH=\$JAVA_HOME/bin:\$PATH' >> /etc/profile
|
||
source /etc/profile
|
||
|
||
echo 'Java 17安装完成'
|
||
else
|
||
echo 'Java 17已安装'
|
||
fi
|
||
java -version
|
||
"
|
||
|
||
log_success "Java环境检查完成"
|
||
}
|
||
|
||
# 安装Maven环境
|
||
install_maven() {
|
||
log_step "安装Maven环境..."
|
||
|
||
remote_exec "
|
||
if ! command -v mvn &> /dev/null; then
|
||
echo '安装Maven...'
|
||
MAVEN_VERSION='3.9.5'
|
||
cd /tmp
|
||
wget https://archive.apache.org/dist/maven/maven-3/\${MAVEN_VERSION}/binaries/apache-maven-\${MAVEN_VERSION}-bin.tar.gz
|
||
tar -xzf apache-maven-\${MAVEN_VERSION}-bin.tar.gz
|
||
mv apache-maven-\${MAVEN_VERSION} ${PROGRAMS_DIR}/maven
|
||
|
||
# 配置环境变量
|
||
echo 'export MAVEN_HOME=${PROGRAMS_DIR}/maven' >> /etc/profile
|
||
echo 'export PATH=\$MAVEN_HOME/bin:\$PATH' >> /etc/profile
|
||
source /etc/profile
|
||
|
||
rm -f apache-maven-\${MAVEN_VERSION}-bin.tar.gz
|
||
echo 'Maven安装完成'
|
||
else
|
||
echo 'Maven已安装'
|
||
fi
|
||
mvn -version 2>/dev/null || echo 'Maven需要重新登录生效'
|
||
"
|
||
|
||
log_success "Maven环境检查完成"
|
||
}
|
||
|
||
# 安装Node.js环境
|
||
install_nodejs() {
|
||
log_step "安装Node.js环境..."
|
||
|
||
remote_exec "
|
||
if ! command -v node &> /dev/null; then
|
||
echo '安装Node.js 18...'
|
||
curl -fsSL https://rpm.nodesource.com/setup_18.x | bash -
|
||
yum install -y nodejs
|
||
|
||
# 配置npm镜像
|
||
npm config set registry https://registry.npmmirror.com
|
||
|
||
echo 'Node.js安装完成'
|
||
else
|
||
echo 'Node.js已安装'
|
||
fi
|
||
node --version
|
||
npm --version
|
||
"
|
||
|
||
log_success "Node.js环境检查完成"
|
||
}
|
||
|
||
# 验证MySQL连接
|
||
verify_mysql() {
|
||
log_step "验证MySQL连接..."
|
||
|
||
# 首先检查是否有Docker容器运行MySQL
|
||
if remote_exec "docker ps | grep mysql > /dev/null"; then
|
||
log_info "检测到Docker MySQL容器"
|
||
if remote_exec "docker exec \$(docker ps | grep mysql | awk '{print \$1}') mysql -u root -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1;' &>/dev/null"; then
|
||
log_success "Docker MySQL连接正常,密码正确"
|
||
return 0
|
||
else
|
||
log_error "Docker MySQL连接失败,请检查密码"
|
||
return 1
|
||
fi
|
||
# 检查本地MySQL服务
|
||
elif remote_exec "mysql -u root -p${MYSQL_ROOT_PASSWORD} -e 'SELECT 1;' &>/dev/null"; then
|
||
log_success "本地MySQL连接正常,密码正确"
|
||
return 0
|
||
else
|
||
log_error "MySQL连接失败,请检查密码或MySQL服务状态"
|
||
remote_exec "systemctl status mysqld || systemctl status mysql || echo 'No local MySQL service'"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
# 配置MySQL数据库
|
||
setup_mysql() {
|
||
log_step "配置MySQL数据库..."
|
||
|
||
# 首先验证连接
|
||
if ! verify_mysql; then
|
||
log_error "MySQL验证失败,请检查MySQL服务和密码"
|
||
exit 1
|
||
fi
|
||
|
||
# 创建应用数据库和用户
|
||
log_info "创建应用数据库和用户..."
|
||
|
||
# 检查是否是Docker MySQL
|
||
if remote_exec "docker ps | grep mysql > /dev/null"; then
|
||
log_info "使用Docker MySQL容器"
|
||
remote_exec "
|
||
docker exec \$(docker ps | grep mysql | awk '{print \$1}') mysql -u root -p${MYSQL_ROOT_PASSWORD} -e \"
|
||
CREATE DATABASE IF NOT EXISTS emotion_museum CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
CREATE USER IF NOT EXISTS 'emotion'@'%' IDENTIFIED BY 'EmotionDB2024!';
|
||
GRANT ALL PRIVILEGES ON emotion_museum.* TO 'emotion'@'%';
|
||
FLUSH PRIVILEGES;
|
||
SELECT 'MySQL数据库配置完成' AS status;
|
||
\"
|
||
"
|
||
else
|
||
log_info "使用本地MySQL服务"
|
||
remote_exec "
|
||
mysql -u root -p${MYSQL_ROOT_PASSWORD} -e \"
|
||
CREATE DATABASE IF NOT EXISTS emotion_museum CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
CREATE USER IF NOT EXISTS 'emotion'@'%' IDENTIFIED BY 'EmotionDB2024!';
|
||
GRANT ALL PRIVILEGES ON emotion_museum.* TO 'emotion'@'%';
|
||
FLUSH PRIVILEGES;
|
||
SELECT 'MySQL数据库配置完成' AS status;
|
||
\"
|
||
"
|
||
fi
|
||
|
||
log_success "MySQL数据库配置完成"
|
||
}
|
||
|
||
# 配置Redis服务
|
||
setup_redis() {
|
||
log_step "配置Redis服务..."
|
||
|
||
# 检查是否已有Docker Redis容器运行
|
||
if remote_exec "docker ps | grep redis > /dev/null"; then
|
||
log_info "检测到Docker Redis容器正在运行"
|
||
|
||
# 获取Redis容器信息
|
||
REDIS_CONTAINER=$(remote_exec "docker ps | grep redis | awk '{print \$1}'")
|
||
log_info "Redis容器ID: $REDIS_CONTAINER"
|
||
|
||
# 测试Redis连接
|
||
if remote_exec "docker exec \$(docker ps | grep redis | awk '{print \$1}') redis-cli ping 2>/dev/null | grep -q PONG"; then
|
||
log_success "Docker Redis服务正常运行"
|
||
else
|
||
log_warn "Docker Redis可能需要密码,尝试重启容器"
|
||
remote_exec "docker restart \$(docker ps | grep redis | awk '{print \$1}')"
|
||
sleep 5
|
||
fi
|
||
|
||
# 记录Redis信息(从Docker环境变量获取)
|
||
REDIS_PASSWORD=$(remote_exec "docker exec \$(docker ps | grep redis | awk '{print \$1}') env | grep REDIS_PASSWORD | cut -d'=' -f2 2>/dev/null || echo 'no-password'")
|
||
echo "REDIS_PASSWORD=${REDIS_PASSWORD}" >> /tmp/passwords.txt
|
||
|
||
log_success "Docker Redis配置确认完成"
|
||
return 0
|
||
fi
|
||
|
||
# 如果没有Docker Redis,安装本地Redis
|
||
log_info "安装本地Redis服务..."
|
||
|
||
# 生成Redis密码
|
||
REDIS_PASSWORD=$(generate_password)
|
||
|
||
remote_exec "
|
||
# 检查Redis是否已安装
|
||
if ! command -v redis-server &> /dev/null; then
|
||
echo '安装Redis...'
|
||
yum install -y redis
|
||
else
|
||
echo 'Redis已安装'
|
||
fi
|
||
|
||
# 配置Redis
|
||
cp /etc/redis.conf /etc/redis.conf.backup 2>/dev/null || true
|
||
sed -i 's/^# requirepass foobared/requirepass ${REDIS_PASSWORD}/' /etc/redis.conf
|
||
sed -i 's/^bind 127.0.0.1/bind 0.0.0.0/' /etc/redis.conf
|
||
|
||
# 启动Redis服务
|
||
systemctl start redis
|
||
systemctl enable redis
|
||
|
||
echo 'Redis配置完成,密码: ${REDIS_PASSWORD}'
|
||
"
|
||
|
||
# 记录Redis密码
|
||
echo "REDIS_PASSWORD=${REDIS_PASSWORD}" >> /tmp/passwords.txt
|
||
|
||
log_success "本地Redis配置完成,密码已生成"
|
||
}
|
||
|
||
# 安装配置Nacos
|
||
setup_nacos() {
|
||
log_step "使用Docker安装配置Nacos..."
|
||
|
||
# 检查是否已有Nacos容器运行
|
||
if remote_exec "docker ps | grep nacos > /dev/null"; then
|
||
log_info "检测到Nacos容器正在运行"
|
||
if remote_exec "curl -s http://localhost:8848/nacos > /dev/null"; then
|
||
log_success "Nacos服务正常运行"
|
||
return 0
|
||
else
|
||
log_warn "Nacos容器存在但服务异常,重启容器"
|
||
remote_exec "docker restart \$(docker ps | grep nacos | awk '{print \$1}')"
|
||
sleep 10
|
||
fi
|
||
fi
|
||
|
||
log_info "创建Nacos Docker配置..."
|
||
|
||
# 创建Nacos配置目录
|
||
remote_exec "mkdir -p ${PROGRAMS_DIR}/nacos/{conf,data,logs}"
|
||
|
||
# 创建Nacos配置文件
|
||
cat > /tmp/nacos-application.properties << 'EOF'
|
||
# Nacos配置文件
|
||
server.servlet.contextPath=/nacos
|
||
server.port=8848
|
||
|
||
# 数据库配置 - 使用MySQL
|
||
spring.datasource.platform=mysql
|
||
db.num=1
|
||
db.url.0=jdbc:mysql://host.docker.internal:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai
|
||
db.user.0=emotion
|
||
db.password.0=EmotionDB2024!
|
||
|
||
# JVM配置
|
||
nacos.inetutils.prefer-hostname-over-ip=false
|
||
nacos.inetutils.ip-address=0.0.0.0
|
||
|
||
# 安全配置
|
||
nacos.security.ignore.urls=/,/error,/**/*.css,/**/*.js,/**/*.html,/**/*.map,/**/*.svg,/**/*.png,/**/*.ico,/console-ui/public/**,/v1/auth/**,/v1/console/health/**,/actuator/**,/v1/console/server/**
|
||
|
||
# 集群配置(单机模式)
|
||
nacos.naming.distro.taskDispatchThreadCount=10
|
||
nacos.naming.distro.taskDispatchPeriod=200
|
||
nacos.naming.distro.batchSyncKeyCount=1000
|
||
nacos.naming.distro.initDataRatio=0.9
|
||
nacos.naming.distro.syncRetryDelay=5000
|
||
nacos.naming.data.warmup=true
|
||
nacos.naming.expireInstance=true
|
||
|
||
# 日志配置
|
||
logging.level.root=INFO
|
||
logging.level.org.springframework=INFO
|
||
logging.level.com.alibaba.nacos=INFO
|
||
EOF
|
||
|
||
# 上传配置文件
|
||
remote_copy "/tmp/nacos-application.properties" "${PROGRAMS_DIR}/nacos/conf/application.properties"
|
||
rm /tmp/nacos-application.properties
|
||
|
||
# 创建Nacos数据库
|
||
log_info "创建Nacos数据库..."
|
||
if remote_exec "docker ps | grep mysql > /dev/null"; then
|
||
remote_exec "
|
||
docker exec \$(docker ps | grep mysql | awk '{print \$1}') mysql -u root -p${MYSQL_ROOT_PASSWORD} -e \"
|
||
CREATE DATABASE IF NOT EXISTS nacos_config CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||
GRANT ALL PRIVILEGES ON nacos_config.* TO 'emotion'@'%';
|
||
FLUSH PRIVILEGES;
|
||
\"
|
||
"
|
||
fi
|
||
|
||
# 启动Nacos容器
|
||
log_info "启动Nacos Docker容器..."
|
||
remote_exec "
|
||
# 停止可能存在的Nacos容器
|
||
docker stop emotion-nacos 2>/dev/null || true
|
||
docker rm emotion-nacos 2>/dev/null || true
|
||
|
||
# 启动新的Nacos容器
|
||
docker run -d \\
|
||
--name emotion-nacos \\
|
||
--restart=always \\
|
||
-p 8848:8848 \\
|
||
-p 9848:9848 \\
|
||
-p 9849:9849 \\
|
||
-e MODE=standalone \\
|
||
-e PREFER_HOST_MODE=hostname \\
|
||
-e SPRING_DATASOURCE_PLATFORM=mysql \\
|
||
-e MYSQL_SERVICE_HOST=host.docker.internal \\
|
||
-e MYSQL_SERVICE_PORT=3306 \\
|
||
-e MYSQL_SERVICE_DB_NAME=nacos_config \\
|
||
-e MYSQL_SERVICE_USER=emotion \\
|
||
-e MYSQL_SERVICE_PASSWORD=EmotionDB2024! \\
|
||
-e NACOS_AUTH_ENABLE=false \\
|
||
-v ${PROGRAMS_DIR}/nacos/conf:/home/nacos/conf \\
|
||
-v ${PROGRAMS_DIR}/nacos/data:/home/nacos/data \\
|
||
-v ${PROGRAMS_DIR}/nacos/logs:/home/nacos/logs \\
|
||
--add-host=host.docker.internal:host-gateway \\
|
||
nacos/nacos-server:v2.2.0
|
||
|
||
echo 'Nacos容器启动完成'
|
||
"
|
||
|
||
# 等待Nacos启动
|
||
log_info "等待Nacos服务启动..."
|
||
sleep 30
|
||
|
||
# 验证Nacos服务
|
||
if remote_exec "curl -s http://localhost:8848/nacos > /dev/null"; then
|
||
log_success "Nacos服务启动成功"
|
||
else
|
||
log_warn "Nacos服务可能还在启动中,请稍后检查"
|
||
fi
|
||
|
||
log_success "Docker Nacos安装配置完成"
|
||
}
|
||
|
||
# 上传构建产物
|
||
upload_artifacts() {
|
||
log_step "上传构建产物..."
|
||
|
||
# 检查构建产物是否存在
|
||
if [ ! -d "build-output" ]; then
|
||
log_error "构建产物不存在,请先运行构建命令"
|
||
log_info "可以运行: ./package.sh 或 mvn clean package"
|
||
exit 1
|
||
fi
|
||
|
||
# 上传JAR文件
|
||
if [ -d "build-output/jars" ]; then
|
||
log_info "上传JAR文件..."
|
||
for jar in build-output/jars/*.jar; do
|
||
if [ -f "$jar" ]; then
|
||
remote_copy "$jar" "${BUILDS_DIR}/"
|
||
log_info "已上传: $(basename $jar)"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# 上传前端文件
|
||
if [ -d "build-output/web" ]; then
|
||
log_info "上传前端文件..."
|
||
remote_exec "rm -rf ${WEB_DIR}/*"
|
||
|
||
# 直接上传整个目录
|
||
remote_copy "build-output/web/" "${WEB_DIR}/"
|
||
|
||
log_info "前端文件上传完成"
|
||
fi
|
||
|
||
# 上传数据库脚本
|
||
if [ -f "backend/mysql_emotion_museum_final.sql" ]; then
|
||
remote_copy "backend/mysql_emotion_museum_final.sql" "/tmp/"
|
||
log_info "数据库脚本上传完成"
|
||
fi
|
||
|
||
log_success "构建产物上传完成"
|
||
}
|
||
|
||
# 导入数据库
|
||
import_database() {
|
||
log_step "导入数据库..."
|
||
|
||
if ! remote_exec "[ -f /tmp/mysql_emotion_museum_final.sql ]"; then
|
||
log_error "数据库脚本不存在,跳过导入"
|
||
return 1
|
||
fi
|
||
|
||
# 检查是否是Docker MySQL
|
||
if remote_exec "docker ps | grep mysql > /dev/null"; then
|
||
log_info "使用Docker MySQL导入数据库..."
|
||
remote_exec "
|
||
echo '开始导入数据库到Docker MySQL...'
|
||
docker exec -i \$(docker ps | grep mysql | awk '{print \$1}') mysql -u root -p${MYSQL_ROOT_PASSWORD} emotion_museum < /tmp/mysql_emotion_museum_final.sql
|
||
echo '数据库导入完成'
|
||
|
||
# 验证导入结果
|
||
docker exec \$(docker ps | grep mysql | awk '{print \$1}') mysql -u root -p${MYSQL_ROOT_PASSWORD} emotion_museum -e 'SHOW TABLES;'
|
||
"
|
||
else
|
||
log_info "使用本地MySQL导入数据库..."
|
||
remote_exec "
|
||
echo '开始导入数据库到本地MySQL...'
|
||
mysql -u root -p${MYSQL_ROOT_PASSWORD} emotion_museum < /tmp/mysql_emotion_museum_final.sql
|
||
echo '数据库导入完成'
|
||
|
||
# 验证导入结果
|
||
mysql -u root -p${MYSQL_ROOT_PASSWORD} emotion_museum -e 'SHOW TABLES;'
|
||
"
|
||
fi
|
||
|
||
log_success "数据库导入完成"
|
||
}
|
||
|
||
# 创建应用启动脚本(不使用Docker)
|
||
create_app_scripts() {
|
||
log_step "创建应用启动脚本..."
|
||
|
||
# 创建启动脚本
|
||
cat > /tmp/start-services.sh << 'EOF'
|
||
#!/bin/bash
|
||
|
||
# 情绪博物馆应用服务启动脚本
|
||
|
||
BUILDS_DIR="/data/builds"
|
||
LOGS_DIR="/data/logs/emotion-museum"
|
||
|
||
# 创建日志目录
|
||
mkdir -p ${LOGS_DIR}/{gateway,ai,user}
|
||
|
||
# 设置环境变量
|
||
export SPRING_PROFILES_ACTIVE=prod
|
||
export NACOS_SERVER_ADDR=localhost:8848
|
||
export MYSQL_HOST=localhost
|
||
export MYSQL_PORT=3306
|
||
export MYSQL_DATABASE=emotion_museum
|
||
export MYSQL_USERNAME=emotion
|
||
export MYSQL_PASSWORD=EmotionDB2024!
|
||
export REDIS_HOST=localhost
|
||
export REDIS_PORT=6379
|
||
export COZE_API_TOKEN=pat_GCR4qKzqpf90wMCvKsldMrB18KG3QsLDci65bZthssKsbLxu8X70BKYumleDcabO
|
||
export TZ=Asia/Shanghai
|
||
|
||
# 停止可能运行的服务
|
||
pkill -f emotion-gateway || true
|
||
pkill -f emotion-ai || true
|
||
pkill -f emotion-user || true
|
||
|
||
sleep 5
|
||
|
||
# 启动网关服务
|
||
echo "启动网关服务..."
|
||
nohup java -jar ${BUILDS_DIR}/emotion-gateway-1.0.0.jar \
|
||
--server.port=9000 \
|
||
--spring.profiles.active=prod \
|
||
--spring.cloud.nacos.discovery.server-addr=${NACOS_SERVER_ADDR} \
|
||
--spring.cloud.nacos.discovery.enabled=true \
|
||
--spring.cloud.nacos.discovery.namespace=public \
|
||
--spring.cloud.nacos.discovery.group=DEFAULT_GROUP \
|
||
--spring.redis.host=${REDIS_HOST} \
|
||
--spring.redis.port=${REDIS_PORT} \
|
||
> ${LOGS_DIR}/gateway/app.log 2>&1 &
|
||
|
||
sleep 10
|
||
|
||
# 启动AI服务
|
||
echo "启动AI服务..."
|
||
nohup java -jar ${BUILDS_DIR}/emotion-ai-1.0.0.jar \
|
||
--server.port=9002 \
|
||
--spring.profiles.active=prod \
|
||
--spring.main.allow-bean-definition-overriding=true \
|
||
--spring.cloud.nacos.discovery.server-addr=${NACOS_SERVER_ADDR} \
|
||
--spring.cloud.nacos.discovery.enabled=true \
|
||
--spring.cloud.nacos.discovery.namespace=public \
|
||
--spring.cloud.nacos.discovery.group=DEFAULT_GROUP \
|
||
--spring.datasource.url=jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai \
|
||
--spring.datasource.username=${MYSQL_USERNAME} \
|
||
--spring.datasource.password=${MYSQL_PASSWORD} \
|
||
--spring.redis.host=${REDIS_HOST} \
|
||
--spring.redis.port=${REDIS_PORT} \
|
||
--coze.api.token=${COZE_API_TOKEN} \
|
||
> ${LOGS_DIR}/ai/app.log 2>&1 &
|
||
|
||
sleep 10
|
||
|
||
# 启动用户服务
|
||
echo "启动用户服务..."
|
||
nohup java -jar ${BUILDS_DIR}/emotion-user-1.0.0.jar \
|
||
--server.port=9001 \
|
||
--spring.profiles.active=prod \
|
||
--spring.main.allow-bean-definition-overriding=true \
|
||
--spring.cloud.nacos.discovery.server-addr=${NACOS_SERVER_ADDR} \
|
||
--spring.cloud.nacos.discovery.enabled=true \
|
||
--spring.cloud.nacos.discovery.namespace=public \
|
||
--spring.cloud.nacos.discovery.group=DEFAULT_GROUP \
|
||
--spring.datasource.url=jdbc:mysql://${MYSQL_HOST}:${MYSQL_PORT}/${MYSQL_DATABASE}?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai \
|
||
--spring.datasource.username=${MYSQL_USERNAME} \
|
||
--spring.datasource.password=${MYSQL_PASSWORD} \
|
||
--spring.redis.host=${REDIS_HOST} \
|
||
--spring.redis.port=${REDIS_PORT} \
|
||
> ${LOGS_DIR}/user/app.log 2>&1 &
|
||
|
||
echo "所有服务启动完成"
|
||
echo "查看服务状态: ps aux | grep emotion"
|
||
echo "查看日志: tail -f ${LOGS_DIR}/*/app.log"
|
||
EOF
|
||
|
||
# 创建停止脚本
|
||
cat > /tmp/stop-services.sh << 'EOF'
|
||
#!/bin/bash
|
||
|
||
echo "停止情绪博物馆应用服务..."
|
||
|
||
pkill -f emotion-gateway && echo "网关服务已停止"
|
||
pkill -f emotion-ai && echo "AI服务已停止"
|
||
pkill -f emotion-user && echo "用户服务已停止"
|
||
|
||
echo "所有服务已停止"
|
||
EOF
|
||
|
||
# 上传脚本
|
||
remote_copy "/tmp/start-services.sh" "${BUILDS_DIR}/start-services.sh"
|
||
remote_copy "/tmp/stop-services.sh" "${BUILDS_DIR}/stop-services.sh"
|
||
|
||
# 设置执行权限
|
||
remote_exec "chmod +x ${BUILDS_DIR}/start-services.sh ${BUILDS_DIR}/stop-services.sh"
|
||
|
||
# 清理临时文件
|
||
rm /tmp/start-services.sh /tmp/stop-services.sh
|
||
|
||
log_success "应用启动脚本创建完成"
|
||
}
|
||
|
||
# 配置Nginx
|
||
setup_nginx() {
|
||
log_step "配置Nginx..."
|
||
|
||
remote_exec "
|
||
# 安装Nginx
|
||
if ! command -v nginx &> /dev/null; then
|
||
yum install -y nginx
|
||
fi
|
||
|
||
# 备份原配置
|
||
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
|
||
|
||
# 创建新的Nginx配置
|
||
cat > /etc/nginx/nginx.conf << 'NGINX_EOF'
|
||
user nginx;
|
||
worker_processes auto;
|
||
error_log /var/log/nginx/error.log;
|
||
pid /run/nginx.pid;
|
||
|
||
events {
|
||
worker_connections 1024;
|
||
}
|
||
|
||
http {
|
||
log_format main '\$remote_addr - \$remote_user [\$time_local] \"\$request\" '
|
||
'\$status \$body_bytes_sent \"\$http_referer\" '
|
||
'\"\$http_user_agent\" \"\$http_x_forwarded_for\"';
|
||
|
||
access_log /var/log/nginx/access.log main;
|
||
|
||
sendfile on;
|
||
tcp_nopush on;
|
||
tcp_nodelay on;
|
||
keepalive_timeout 65;
|
||
types_hash_max_size 2048;
|
||
|
||
include /etc/nginx/mime.types;
|
||
default_type application/octet-stream;
|
||
|
||
# 前端应用
|
||
server {
|
||
listen 80;
|
||
server_name _;
|
||
|
||
# 情绪博物馆前端应用
|
||
location /emotion-museum {
|
||
alias ${WEB_DIR};
|
||
index index.html;
|
||
try_files \$uri \$uri/ /emotion-museum/index.html;
|
||
}
|
||
|
||
# 根路径重定向到情绪博物馆
|
||
location = / {
|
||
return 301 /emotion-museum/;
|
||
}
|
||
|
||
# API代理到网关
|
||
location /api/ {
|
||
proxy_pass http://127.0.0.1:9000/api/;
|
||
proxy_set_header Host \$host;
|
||
proxy_set_header X-Real-IP \$remote_addr;
|
||
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto \$scheme;
|
||
proxy_connect_timeout 30s;
|
||
proxy_send_timeout 30s;
|
||
proxy_read_timeout 30s;
|
||
}
|
||
|
||
# 静态资源缓存
|
||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
||
expires 1y;
|
||
add_header Cache-Control \"public, no-transform\";
|
||
}
|
||
|
||
# 健康检查
|
||
location /health {
|
||
access_log off;
|
||
return 200 'healthy';
|
||
add_header Content-Type text/plain;
|
||
}
|
||
}
|
||
}
|
||
NGINX_EOF
|
||
|
||
# 启动Nginx
|
||
systemctl start nginx
|
||
systemctl enable nginx
|
||
|
||
echo 'Nginx配置完成'
|
||
"
|
||
|
||
log_success "Nginx配置完成"
|
||
}
|
||
|
||
# 启动应用服务
|
||
start_app_services() {
|
||
log_step "启动应用服务..."
|
||
|
||
# 使用脚本启动服务
|
||
remote_exec "
|
||
cd ${BUILDS_DIR}
|
||
|
||
# 执行启动脚本
|
||
bash start-services.sh
|
||
|
||
echo '应用服务启动完成'
|
||
"
|
||
|
||
# 等待服务启动
|
||
sleep 15
|
||
|
||
# 检查服务状态
|
||
log_info "检查服务状态..."
|
||
remote_exec "ps aux | grep -E 'emotion-(gateway|ai|user)' | grep -v grep || echo '没有找到运行的服务'"
|
||
|
||
log_success "应用服务启动完成"
|
||
}
|
||
|
||
# 创建密码记录文件
|
||
create_password_record() {
|
||
log_step "创建密码记录文件..."
|
||
|
||
# 读取临时密码文件
|
||
REDIS_PASSWORD=""
|
||
if [ -f "/tmp/passwords.txt" ]; then
|
||
REDIS_PASSWORD=$(grep "REDIS_PASSWORD" /tmp/passwords.txt | cut -d'=' -f2)
|
||
fi
|
||
|
||
cat > /tmp/deployment_passwords.md << EOF
|
||
# 情绪博物馆部署密码记录
|
||
|
||
## 服务器信息
|
||
- 服务器IP: ${SERVER_IP}
|
||
- 部署时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||
- 部署用户: ${SERVER_USER}
|
||
|
||
## 数据库配置
|
||
### MySQL
|
||
- 端口: 3306
|
||
- Root用户: root
|
||
- Root密码: ${MYSQL_ROOT_PASSWORD}
|
||
- 应用数据库: emotion_museum
|
||
- 应用用户: emotion
|
||
- 应用密码: EmotionDB2024!
|
||
|
||
### Redis
|
||
- 端口: 6379
|
||
- 密码: ${REDIS_PASSWORD:-"未设置或生成失败"}
|
||
|
||
## 服务端口配置
|
||
- Nginx: 80
|
||
- MySQL: 3306
|
||
- Redis: 6379
|
||
- Nacos: 8848
|
||
- 网关服务: 9000
|
||
- 用户服务: 9001
|
||
- AI服务: 9002
|
||
|
||
## 访问地址
|
||
- 前端应用: http://${SERVER_IP}
|
||
- API网关: http://${SERVER_IP}:9000
|
||
- Nacos控制台: http://${SERVER_IP}:8848/nacos
|
||
- 用户名: nacos
|
||
- 密码: nacos
|
||
|
||
## API配置
|
||
- Coze API Token: pat_GCR4qKzqpf90wMCvKsldMrB18KG3QsLDci65bZthssKsbLxu8X70BKYumleDcabO
|
||
|
||
## 目录结构
|
||
- 程序目录: ${PROGRAMS_DIR}
|
||
- 构建目录: ${BUILDS_DIR}
|
||
- 前端目录: ${WEB_DIR}
|
||
- 日志目录: ${LOGS_DIR}
|
||
- 备份目录: /data/backup
|
||
|
||
## 管理命令
|
||
\`\`\`bash
|
||
# 查看服务状态
|
||
systemctl status mysqld redis nacos nginx
|
||
docker ps
|
||
|
||
# 查看应用日志
|
||
docker logs -f emotion-gateway
|
||
docker logs -f emotion-ai
|
||
docker logs -f emotion-user
|
||
|
||
# 重启服务
|
||
systemctl restart mysqld redis nacos nginx
|
||
docker-compose -f ${BUILDS_DIR}/docker-compose.yml restart
|
||
|
||
# 停止所有服务
|
||
docker-compose -f ${BUILDS_DIR}/docker-compose.yml down
|
||
systemctl stop nginx redis mysqld
|
||
${PROGRAMS_DIR}/nacos/bin/shutdown.sh
|
||
\`\`\`
|
||
|
||
## 备份命令
|
||
\`\`\`bash
|
||
# 数据库备份
|
||
mysqldump -u root -p${MYSQL_ROOT_PASSWORD} emotion_museum > /data/backup/emotion_museum_\$(date +%Y%m%d_%H%M%S).sql
|
||
|
||
# 配置备份
|
||
tar -czf /data/backup/config_\$(date +%Y%m%d_%H%M%S).tar.gz /etc/nginx /etc/redis.conf ${PROGRAMS_DIR}/nacos/conf
|
||
\`\`\`
|
||
|
||
## 安全提醒
|
||
⚠️ 重要提醒:
|
||
1. 请及时修改默认密码
|
||
2. 建议配置防火墙规则
|
||
3. 定期备份数据库
|
||
4. 监控服务器资源使用情况
|
||
|
||
## 更新记录
|
||
- $(date '+%Y-%m-%d %H:%M:%S'): 初始部署完成
|
||
|
||
---
|
||
**此文件包含敏感信息,请妥善保管!**
|
||
EOF
|
||
|
||
# 上传密码记录文件
|
||
remote_copy "/tmp/deployment_passwords.md" "${CONFIG_FILE}"
|
||
rm /tmp/deployment_passwords.md
|
||
|
||
# 清理临时密码文件
|
||
rm -f /tmp/passwords.txt
|
||
|
||
log_success "密码记录文件已创建: ${CONFIG_FILE}"
|
||
}
|
||
|
||
# 健康检查
|
||
health_check() {
|
||
log_step "执行健康检查..."
|
||
|
||
sleep 30 # 等待服务启动
|
||
|
||
log_info "检查基础服务状态..."
|
||
remote_exec "
|
||
echo '=== 系统服务状态 ==='
|
||
systemctl is-active mysqld && echo '✅ MySQL: 运行中' || echo '❌ MySQL: 异常'
|
||
systemctl is-active redis && echo '✅ Redis: 运行中' || echo '❌ Redis: 异常'
|
||
systemctl is-active nginx && echo '✅ Nginx: 运行中' || echo '❌ Nginx: 异常'
|
||
pgrep -f nacos > /dev/null && echo '✅ Nacos: 运行中' || echo '❌ Nacos: 异常'
|
||
|
||
echo ''
|
||
echo '=== Docker服务状态 ==='
|
||
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
|
||
|
||
echo ''
|
||
echo '=== 端口监听状态 ==='
|
||
netstat -tlnp | grep -E ':(80|3306|6379|8848|9000|9001|9002)' | awk '{print \$1\" \"\$4}' | sort
|
||
"
|
||
|
||
log_info "HTTP接口测试..."
|
||
|
||
# 测试前端
|
||
if remote_exec "curl -s -o /dev/null -w '%{http_code}' http://localhost:80 | grep -q 200"; then
|
||
log_success "✅ 前端应用访问正常"
|
||
else
|
||
log_warn "❌ 前端应用访问异常"
|
||
fi
|
||
|
||
# 测试Nacos
|
||
if remote_exec "curl -s -o /dev/null -w '%{http_code}' http://localhost:8848/nacos | grep -q 200"; then
|
||
log_success "✅ Nacos控制台访问正常"
|
||
else
|
||
log_warn "❌ Nacos控制台访问异常"
|
||
fi
|
||
|
||
# 测试网关
|
||
sleep 10 # 额外等待网关启动
|
||
if remote_exec "curl -s -o /dev/null -w '%{http_code}' http://localhost:9000/actuator/health 2>/dev/null | grep -q 200"; then
|
||
log_success "✅ API网关访问正常"
|
||
else
|
||
log_warn "❌ API网关访问异常(可能还在启动中)"
|
||
fi
|
||
|
||
log_success "健康检查完成"
|
||
}
|
||
|
||
# 显示部署结果
|
||
show_deployment_result() {
|
||
echo ""
|
||
echo "🎉 情绪博物馆部署完成!"
|
||
echo ""
|
||
echo "📱 访问地址:"
|
||
echo " 前端应用: http://${SERVER_IP}"
|
||
echo " API网关: http://${SERVER_IP}:9000"
|
||
echo " Nacos: http://${SERVER_IP}:8848/nacos"
|
||
echo ""
|
||
echo "📁 重要文件:"
|
||
echo " 密码记录: ${CONFIG_FILE}"
|
||
echo " 应用目录: ${BUILDS_DIR}"
|
||
echo " 前端目录: ${WEB_DIR}"
|
||
echo " 日志目录: ${LOGS_DIR}"
|
||
echo ""
|
||
echo "🔧 管理命令:"
|
||
echo " ssh ${SERVER_USER}@${SERVER_IP}"
|
||
echo " docker-compose -f ${BUILDS_DIR}/docker-compose.yml logs -f"
|
||
echo " systemctl status mysqld redis nacos nginx"
|
||
echo ""
|
||
echo "⚠️ 重要提醒:"
|
||
echo " 1. 密码信息已保存到服务器 ${CONFIG_FILE} 文件中"
|
||
echo " 2. 请及时修改默认密码"
|
||
echo " 3. 建议配置防火墙规则"
|
||
echo " 4. 定期备份数据库"
|
||
echo ""
|
||
}
|
||
|
||
# 显示帮助信息
|
||
show_help() {
|
||
echo "情绪博物馆阿里云部署脚本"
|
||
echo ""
|
||
echo "用法: $0 [选项]"
|
||
echo ""
|
||
echo "选项:"
|
||
echo " check - 检查服务器连接和环境"
|
||
echo " env - 安装基础环境(Java、Maven、Node.js、Docker)"
|
||
echo " mysql - 配置MySQL数据库"
|
||
echo " redis - 配置Redis服务"
|
||
echo " nacos - 安装配置Nacos"
|
||
echo " upload - 上传构建产物"
|
||
echo " import-db - 导入数据库"
|
||
echo " deploy - 部署应用服务"
|
||
echo " nginx - 配置Nginx"
|
||
echo " health - 健康检查"
|
||
echo " passwords - 创建密码记录文件"
|
||
echo " all - 完整部署(默认)"
|
||
echo " help - 显示此帮助信息"
|
||
echo ""
|
||
echo "分步骤部署示例:"
|
||
echo " $0 check # 1. 检查服务器连接"
|
||
echo " $0 env # 2. 安装基础环境"
|
||
echo " $0 mysql # 3. 配置MySQL"
|
||
echo " $0 redis # 4. 配置Redis"
|
||
echo " $0 nacos # 5. 安装Nacos"
|
||
echo " $0 upload # 6. 上传构建产物"
|
||
echo " $0 import-db # 7. 导入数据库"
|
||
echo " $0 deploy # 8. 部署应用服务"
|
||
echo " $0 nginx # 9. 配置Nginx"
|
||
echo " $0 passwords # 10. 创建密码记录"
|
||
echo " $0 health # 11. 健康检查"
|
||
echo ""
|
||
echo "一键部署:"
|
||
echo " $0 all # 完整部署所有组件"
|
||
echo ""
|
||
}
|
||
|
||
# 主函数入口
|
||
main() {
|
||
case "${1:-all}" in
|
||
"check")
|
||
check_server_connection
|
||
;;
|
||
"env")
|
||
check_server_connection
|
||
setup_directories
|
||
install_basic_packages
|
||
install_docker
|
||
install_java
|
||
install_maven
|
||
install_nodejs
|
||
log_success "基础环境安装完成!"
|
||
echo "下一步: $0 mysql"
|
||
;;
|
||
"mysql")
|
||
check_server_connection
|
||
setup_mysql
|
||
log_success "MySQL配置完成!"
|
||
echo "下一步: $0 redis"
|
||
;;
|
||
"redis")
|
||
check_server_connection
|
||
setup_redis
|
||
log_success "Redis配置完成!"
|
||
echo "下一步: $0 nacos"
|
||
;;
|
||
"nacos")
|
||
check_server_connection
|
||
setup_nacos
|
||
log_success "Nacos安装完成!"
|
||
echo "下一步: $0 upload"
|
||
;;
|
||
"upload")
|
||
check_server_connection
|
||
upload_artifacts
|
||
log_success "构建产物上传完成!"
|
||
echo "下一步: $0 import-db"
|
||
;;
|
||
"import-db")
|
||
check_server_connection
|
||
import_database
|
||
log_success "数据库导入完成!"
|
||
echo "下一步: $0 deploy"
|
||
;;
|
||
"deploy")
|
||
check_server_connection
|
||
create_app_scripts
|
||
start_app_services
|
||
log_success "应用服务部署完成!"
|
||
echo "下一步: $0 nginx"
|
||
;;
|
||
"nginx")
|
||
check_server_connection
|
||
setup_nginx
|
||
log_success "Nginx配置完成!"
|
||
echo "下一步: $0 passwords"
|
||
;;
|
||
"passwords")
|
||
check_server_connection
|
||
create_password_record
|
||
log_success "密码记录创建完成!"
|
||
echo "下一步: $0 health"
|
||
;;
|
||
"health")
|
||
check_server_connection
|
||
health_check
|
||
show_deployment_result
|
||
;;
|
||
"help")
|
||
show_help
|
||
;;
|
||
"all")
|
||
echo "🚀 开始完整部署情绪博物馆到阿里云服务器..."
|
||
echo ""
|
||
|
||
# 完整部署流程
|
||
check_server_connection
|
||
setup_directories
|
||
install_basic_packages
|
||
install_docker
|
||
install_java
|
||
install_maven
|
||
install_nodejs
|
||
setup_mysql
|
||
setup_redis
|
||
setup_nacos
|
||
upload_artifacts
|
||
import_database
|
||
create_app_scripts
|
||
start_app_services
|
||
setup_nginx
|
||
create_password_record
|
||
health_check
|
||
show_deployment_result
|
||
;;
|
||
*)
|
||
echo "未知选项: $1"
|
||
show_help
|
||
exit 1
|
||
;;
|
||
esac
|
||
}
|
||
|
||
# 执行主函数
|
||
main "$@"
|