659 lines
16 KiB
Bash
Executable File
659 lines
16 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# 情绪博物馆阿里云服务器部署脚本 - 适配现有Docker环境
|
|
# 服务器已有MySQL/Redis/Nacos容器运行
|
|
|
|
set -e
|
|
|
|
# 颜色定义
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
# 服务器配置
|
|
SERVER_IP="47.111.10.27"
|
|
SERVER_USER="root"
|
|
|
|
# 现有Docker容器配置
|
|
MYSQL_ROOT_PASSWORD="123456"
|
|
MYSQL_CONTAINER="emotion-mysql-prod"
|
|
REDIS_CONTAINER="emotion-redis-prod"
|
|
NACOS_CONTAINER="emotion-nacos-prod"
|
|
|
|
# 部署目录配置
|
|
BUILDS_DIR="/data/builds"
|
|
WEB_DIR="/data/www/emotion-museum"
|
|
CONFIG_FILE="/data/deployment_config.md"
|
|
|
|
# 日志函数
|
|
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"
|
|
}
|
|
|
|
# 远程执行命令
|
|
remote_exec() {
|
|
local command="$1"
|
|
ssh -o StrictHostKeyChecking=no "${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'" &>/dev/null; then
|
|
log_error "无法连接到服务器 ${SERVER_IP}"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "服务器连接正常"
|
|
}
|
|
|
|
# 检查现有Docker服务
|
|
check_existing_services() {
|
|
log_step "检查现有Docker服务..."
|
|
|
|
# 检查Docker容器状态
|
|
if remote_exec "docker ps | grep -q ${MYSQL_CONTAINER}"; then
|
|
log_info "✅ MySQL容器运行正常"
|
|
else
|
|
log_error "❌ MySQL容器未运行"
|
|
exit 1
|
|
fi
|
|
|
|
if remote_exec "docker ps | grep -q ${REDIS_CONTAINER}"; then
|
|
log_info "✅ Redis容器运行正常"
|
|
else
|
|
log_error "❌ Redis容器未运行"
|
|
exit 1
|
|
fi
|
|
|
|
if remote_exec "docker ps | grep -q ${NACOS_CONTAINER}"; then
|
|
log_info "✅ Nacos容器运行正常"
|
|
else
|
|
log_error "❌ Nacos容器未运行"
|
|
exit 1
|
|
fi
|
|
|
|
# 测试MySQL连接
|
|
if remote_exec "docker exec ${MYSQL_CONTAINER} mysql -u root -p'${MYSQL_ROOT_PASSWORD}' -e 'SELECT 1;' &>/dev/null"; then
|
|
log_info "✅ MySQL连接正常"
|
|
else
|
|
log_error "❌ MySQL连接失败"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "现有服务检查完成"
|
|
}
|
|
|
|
# 创建目录结构
|
|
setup_directories() {
|
|
log_step "创建部署目录..."
|
|
|
|
remote_exec "mkdir -p ${BUILDS_DIR}"
|
|
remote_exec "mkdir -p ${WEB_DIR}"
|
|
remote_exec "mkdir -p /data/logs/{app,nginx}"
|
|
|
|
log_info "目录创建完成"
|
|
}
|
|
|
|
# 上传构建产物
|
|
upload_artifacts() {
|
|
log_step "上传构建产物..."
|
|
|
|
# 检查构建产物
|
|
if [ ! -d "build-output" ]; then
|
|
log_error "构建产物不存在,请先运行: ./deploy-aliyun.sh build"
|
|
exit 1
|
|
fi
|
|
|
|
# 上传JAR文件
|
|
if [ -d "build-output/jars" ]; then
|
|
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
|
|
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_info "构建产物上传完成"
|
|
}
|
|
|
|
# 导入数据库
|
|
import_database() {
|
|
log_step "导入数据库..."
|
|
|
|
remote_exec "
|
|
if [ -f /tmp/mysql_emotion_museum_final.sql ]; then
|
|
docker exec -i ${MYSQL_CONTAINER} mysql -u root -p'${MYSQL_ROOT_PASSWORD}' emotion_museum < /tmp/mysql_emotion_museum_final.sql
|
|
echo '数据库导入完成'
|
|
else
|
|
echo '数据库脚本不存在,跳过导入'
|
|
fi
|
|
"
|
|
|
|
log_info "数据库处理完成"
|
|
}
|
|
|
|
# 创建应用配置文件
|
|
create_app_configs() {
|
|
log_step "创建应用配置..."
|
|
|
|
# 创建应用properties文件
|
|
cat > /tmp/application-prod.yml << 'EOF'
|
|
server:
|
|
port: 9000
|
|
|
|
spring:
|
|
application:
|
|
name: emotion-gateway
|
|
cloud:
|
|
nacos:
|
|
discovery:
|
|
server-addr: host.docker.internal:8848
|
|
config:
|
|
server-addr: host.docker.internal:8848
|
|
file-extension: yml
|
|
datasource:
|
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
|
url: jdbc:mysql://host.docker.internal:3306/emotion_museum?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
|
|
username: emotion
|
|
password: emotion123
|
|
redis:
|
|
host: host.docker.internal
|
|
port: 6379
|
|
timeout: 2000
|
|
jedis:
|
|
pool:
|
|
max-active: 8
|
|
max-wait: -1
|
|
max-idle: 8
|
|
min-idle: 0
|
|
|
|
logging:
|
|
level:
|
|
com.emotionmuseum: DEBUG
|
|
file:
|
|
name: /app/logs/emotion-gateway.log
|
|
EOF
|
|
|
|
# 上传配置文件
|
|
remote_copy "/tmp/application-prod.yml" "${BUILDS_DIR}/"
|
|
rm /tmp/application-prod.yml
|
|
|
|
log_info "应用配置创建完成"
|
|
}
|
|
|
|
# 创建Docker Compose配置
|
|
create_docker_compose() {
|
|
log_step "创建应用Docker Compose配置..."
|
|
|
|
cat > /tmp/docker-compose.yml << 'EOF'
|
|
version: '3.8'
|
|
|
|
services:
|
|
# 网关服务
|
|
emotion-gateway:
|
|
image: openjdk:17-jre-slim
|
|
container_name: emotion-gateway
|
|
restart: always
|
|
ports:
|
|
- "9000:9000"
|
|
environment:
|
|
SPRING_PROFILES_ACTIVE: prod
|
|
TZ: Asia/Shanghai
|
|
JAVA_OPTS: '-Xmx512m -Xms256m'
|
|
volumes:
|
|
- /data/builds/emotion-gateway-1.0.0.jar:/app/app.jar:ro
|
|
- /data/builds/application-prod.yml:/app/application-prod.yml:ro
|
|
- /data/logs/app:/app/logs
|
|
working_dir: /app
|
|
command: ["java", "-jar", "app.jar"]
|
|
extra_hosts:
|
|
- "host.docker.internal:172.17.0.1"
|
|
networks:
|
|
- emotion-network
|
|
|
|
# AI服务
|
|
emotion-ai:
|
|
image: openjdk:17-jre-slim
|
|
container_name: emotion-ai
|
|
restart: always
|
|
ports:
|
|
- "9002:9002"
|
|
environment:
|
|
SPRING_PROFILES_ACTIVE: prod
|
|
TZ: Asia/Shanghai
|
|
JAVA_OPTS: '-Xmx512m -Xms256m'
|
|
volumes:
|
|
- /data/builds/emotion-ai-1.0.0.jar:/app/app.jar:ro
|
|
- /data/logs/app:/app/logs
|
|
working_dir: /app
|
|
command: ["java", "-jar", "app.jar"]
|
|
extra_hosts:
|
|
- "host.docker.internal:172.17.0.1"
|
|
networks:
|
|
- emotion-network
|
|
|
|
# 用户服务
|
|
emotion-user:
|
|
image: openjdk:17-jre-slim
|
|
container_name: emotion-user
|
|
restart: always
|
|
ports:
|
|
- "9001:9001"
|
|
environment:
|
|
SPRING_PROFILES_ACTIVE: prod
|
|
TZ: Asia/Shanghai
|
|
JAVA_OPTS: '-Xmx512m -Xms256m'
|
|
volumes:
|
|
- /data/builds/emotion-user-1.0.0.jar:/app/app.jar:ro
|
|
- /data/logs/app:/app/logs
|
|
working_dir: /app
|
|
command: ["java", "-jar", "app.jar"]
|
|
extra_hosts:
|
|
- "host.docker.internal:172.17.0.1"
|
|
networks:
|
|
- emotion-network
|
|
|
|
networks:
|
|
emotion-network:
|
|
driver: bridge
|
|
EOF
|
|
|
|
# 上传Docker Compose文件
|
|
remote_copy "/tmp/docker-compose.yml" "${BUILDS_DIR}/docker-compose.yml"
|
|
rm /tmp/docker-compose.yml
|
|
|
|
log_info "Docker Compose配置创建完成"
|
|
}
|
|
|
|
# 配置Nginx
|
|
setup_nginx() {
|
|
log_step "配置Nginx..."
|
|
|
|
# 检查Nginx是否已安装
|
|
if ! remote_exec "command -v nginx &> /dev/null"; then
|
|
remote_exec "yum install -y nginx"
|
|
fi
|
|
|
|
# 创建Nginx配置
|
|
cat > /tmp/nginx.conf << 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 ${SERVER_IP} _;
|
|
root ${WEB_DIR};
|
|
index index.html;
|
|
|
|
# 前端路由
|
|
location / {
|
|
try_files \$uri \$uri/ /index.html;
|
|
}
|
|
|
|
# API代理到网关
|
|
location /api/ {
|
|
proxy_pass http://127.0.0.1:9000/;
|
|
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 60s;
|
|
proxy_read_timeout 60s;
|
|
proxy_send_timeout 60s;
|
|
}
|
|
|
|
# 直接访问网关
|
|
location /gateway/ {
|
|
proxy_pass http://127.0.0.1:9000/;
|
|
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;
|
|
}
|
|
|
|
# 静态资源缓存
|
|
location ~* \\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
|
expires 1y;
|
|
add_header Cache-Control "public, no-transform";
|
|
}
|
|
|
|
# 健康检查
|
|
location /health {
|
|
access_log off;
|
|
return 200 "healthy\\n";
|
|
add_header Content-Type text/plain;
|
|
}
|
|
}
|
|
}
|
|
EOF
|
|
|
|
# 上传并应用Nginx配置
|
|
remote_copy "/tmp/nginx.conf" "/etc/nginx/nginx.conf"
|
|
rm /tmp/nginx.conf
|
|
|
|
# 启动Nginx
|
|
remote_exec "
|
|
nginx -t && systemctl start nginx && systemctl enable nginx
|
|
echo 'Nginx配置完成'
|
|
"
|
|
|
|
log_info "Nginx配置完成"
|
|
}
|
|
|
|
# 启动应用服务
|
|
start_application_services() {
|
|
log_step "启动应用服务..."
|
|
|
|
remote_exec "
|
|
cd ${BUILDS_DIR}
|
|
|
|
# 停止可能存在的同名容器
|
|
docker stop emotion-gateway emotion-ai emotion-user 2>/dev/null || true
|
|
docker rm emotion-gateway emotion-ai emotion-user 2>/dev/null || true
|
|
|
|
# 启动应用服务
|
|
docker-compose up -d
|
|
|
|
echo '应用服务启动完成'
|
|
"
|
|
|
|
log_info "应用服务启动完成"
|
|
}
|
|
|
|
# 等待服务启动
|
|
wait_for_services() {
|
|
log_step "等待服务启动..."
|
|
|
|
sleep 20
|
|
|
|
# 检查服务状态
|
|
log_info "检查应用容器状态..."
|
|
remote_exec "docker ps | grep -E 'emotion-(gateway|ai|user)'"
|
|
|
|
log_info "等待服务完全启动..."
|
|
sleep 30
|
|
}
|
|
|
|
# 健康检查
|
|
health_check() {
|
|
log_step "执行健康检查..."
|
|
|
|
log_info "检查基础服务..."
|
|
remote_exec "docker ps | grep -E '(mysql|redis|nacos)'"
|
|
|
|
log_info "检查应用服务..."
|
|
remote_exec "docker ps | grep -E 'emotion-(gateway|ai|user)'"
|
|
|
|
log_info "检查端口监听..."
|
|
remote_exec "netstat -tlnp | grep -E ':(80|3306|6379|8848|9000|9001|9002)'"
|
|
|
|
# HTTP健康检查
|
|
log_info "HTTP接口测试..."
|
|
|
|
# 测试前端
|
|
if remote_exec "curl -s -o /dev/null -w '%{http_code}' http://localhost/ | grep -q 200"; then
|
|
log_info "✅ 前端应用正常"
|
|
else
|
|
log_warn "❌ 前端应用异常"
|
|
fi
|
|
|
|
# 测试网关健康检查
|
|
sleep 10
|
|
if remote_exec "curl -s http://localhost:9000/actuator/health 2>/dev/null | grep -q UP"; then
|
|
log_info "✅ 网关服务正常"
|
|
else
|
|
log_warn "❌ 网关服务异常,检查日志:"
|
|
remote_exec "docker logs emotion-gateway | tail -20"
|
|
fi
|
|
|
|
# 测试Nacos
|
|
if remote_exec "curl -s -o /dev/null -w '%{http_code}' http://localhost:8848/nacos | grep -q 200"; then
|
|
log_info "✅ Nacos控制台正常"
|
|
else
|
|
log_warn "❌ Nacos控制台异常"
|
|
fi
|
|
|
|
log_info "健康检查完成"
|
|
}
|
|
|
|
# 显示服务日志
|
|
show_logs() {
|
|
log_step "显示服务日志..."
|
|
|
|
log_info "网关服务日志:"
|
|
remote_exec "docker logs emotion-gateway | tail -10"
|
|
|
|
log_info "AI服务日志:"
|
|
remote_exec "docker logs emotion-ai | tail -10"
|
|
|
|
log_info "用户服务日志:"
|
|
remote_exec "docker logs emotion-user | tail -10"
|
|
}
|
|
|
|
# 创建部署记录
|
|
create_deployment_record() {
|
|
log_step "创建部署记录..."
|
|
|
|
cat > /tmp/deployment_config.md << EOF
|
|
# 情绪博物馆部署配置记录
|
|
|
|
## 服务器信息
|
|
- 服务器IP: ${SERVER_IP}
|
|
- 部署时间: $(date '+%Y-%m-%d %H:%M:%S')
|
|
|
|
## Docker服务配置
|
|
### 基础服务 (现有容器)
|
|
- MySQL: ${MYSQL_CONTAINER} (端口: 3306, 密码: ${MYSQL_ROOT_PASSWORD})
|
|
- Redis: ${REDIS_CONTAINER} (端口: 6379)
|
|
- Nacos: ${NACOS_CONTAINER} (端口: 8848)
|
|
|
|
### 应用服务 (新部署)
|
|
- 网关服务: emotion-gateway (端口: 9000)
|
|
- AI服务: emotion-ai (端口: 9002)
|
|
- 用户服务: emotion-user (端口: 9001)
|
|
- Nginx: 系统服务 (端口: 80)
|
|
|
|
## 访问地址
|
|
- 前端应用: http://${SERVER_IP}/
|
|
- API网关: http://${SERVER_IP}:9000/
|
|
- Nacos控制台: http://${SERVER_IP}:8848/nacos (nacos/nacos)
|
|
|
|
## 目录结构
|
|
- 应用JAR包: ${BUILDS_DIR}/*.jar
|
|
- 前端文件: ${WEB_DIR}/
|
|
- Docker配置: ${BUILDS_DIR}/docker-compose.yml
|
|
- 应用日志: /data/logs/app/
|
|
- Nginx日志: /var/log/nginx/
|
|
|
|
## 管理命令
|
|
\`\`\`bash
|
|
# 查看所有容器状态
|
|
docker ps
|
|
|
|
# 查看应用日志
|
|
docker logs -f emotion-gateway
|
|
docker logs -f emotion-ai
|
|
docker logs -f emotion-user
|
|
|
|
# 重启应用服务
|
|
cd ${BUILDS_DIR}
|
|
docker-compose restart
|
|
|
|
# 更新应用
|
|
docker-compose down
|
|
# 替换JAR文件
|
|
docker-compose up -d
|
|
|
|
# 重启Nginx
|
|
systemctl restart nginx
|
|
|
|
# 重启基础服务
|
|
docker restart ${MYSQL_CONTAINER} ${REDIS_CONTAINER} ${NACOS_CONTAINER}
|
|
\`\`\`
|
|
|
|
## 故障排除
|
|
\`\`\`bash
|
|
# 检查服务状态
|
|
docker ps
|
|
systemctl status nginx
|
|
|
|
# 检查端口占用
|
|
netstat -tlnp | grep -E ':(80|3306|6379|8848|9000|9001|9002)'
|
|
|
|
# 查看详细日志
|
|
docker logs emotion-gateway
|
|
docker logs emotion-ai
|
|
docker logs emotion-user
|
|
|
|
# 重新部署应用
|
|
cd ${BUILDS_DIR}
|
|
docker-compose down
|
|
docker-compose up -d
|
|
\`\`\`
|
|
EOF
|
|
|
|
# 上传部署记录
|
|
remote_copy "/tmp/deployment_config.md" "${CONFIG_FILE}"
|
|
rm /tmp/deployment_config.md
|
|
|
|
log_info "部署记录已保存到: ${CONFIG_FILE}"
|
|
}
|
|
|
|
# 显示部署结果
|
|
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 ""
|
|
echo "🔧 管理命令:"
|
|
echo " ssh ${SERVER_USER}@${SERVER_IP}"
|
|
echo " docker ps"
|
|
echo " docker logs -f emotion-gateway"
|
|
echo ""
|
|
echo "⚠️ 注意事项:"
|
|
echo " 1. 基础服务(MySQL/Redis/Nacos)使用现有Docker容器"
|
|
echo " 2. 应用服务已部署为新的Docker容器"
|
|
echo " 3. 请检查防火墙设置,确保端口80可访问"
|
|
echo ""
|
|
}
|
|
|
|
# 主部署流程
|
|
main() {
|
|
echo "🚀 开始部署情绪博物馆应用服务..."
|
|
echo "🔍 检测到服务器已有MySQL/Redis/Nacos容器,将使用现有基础设施"
|
|
echo ""
|
|
|
|
check_server_connection
|
|
check_existing_services
|
|
setup_directories
|
|
upload_artifacts
|
|
import_database
|
|
create_app_configs
|
|
create_docker_compose
|
|
setup_nginx
|
|
start_application_services
|
|
wait_for_services
|
|
health_check
|
|
show_logs
|
|
create_deployment_record
|
|
show_deployment_result
|
|
}
|
|
|
|
# 命令行参数处理
|
|
case "${1:-}" in
|
|
"check")
|
|
check_server_connection
|
|
check_existing_services
|
|
;;
|
|
"deploy-app")
|
|
log_info "仅部署应用服务..."
|
|
check_server_connection
|
|
check_existing_services
|
|
upload_artifacts
|
|
create_app_configs
|
|
create_docker_compose
|
|
start_application_services
|
|
wait_for_services
|
|
health_check
|
|
;;
|
|
"health")
|
|
check_server_connection
|
|
health_check
|
|
;;
|
|
"logs")
|
|
check_server_connection
|
|
show_logs
|
|
;;
|
|
*)
|
|
main
|
|
;;
|
|
esac |