feat: 项目初始化及当前全部内容提交

This commit is contained in:
2025-07-15 17:37:50 +08:00
parent ec817067f1
commit e78f192d34
622 changed files with 75174 additions and 383 deletions
+659
View File
@@ -0,0 +1,659 @@
#!/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