Duke Admin 部署运维手册
目录
部署概述
Duke Admin 是一个前后端分离的后台管理系统,包含前端 Vue 应用和后端 Spring Boot 服务。本文档详细介绍如何在不同环境中部署和运维该系统。
系统架构
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ 前端应用 │ │ 后端服务 │ │ 数据库 │
│ (Vue + Nginx) │◄──►│ (Spring Boot) │◄──►│ (MySQL) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ 缓存服务 │
│ (Redis) │
└─────────────────┘
环境要求
系统要求
- 操作系统: Linux (CentOS 7+, Ubuntu 18+), Windows 10+, macOS 10.14+
- 内存: 最低 4GB,推荐 8GB+
- 磁盘: 最低 20GB 可用空间
- 网络: 支持 HTTP/HTTPS 访问
软件要求
前端环境
- Node.js: 16.0.0+
- npm: 8.0.0+
- Nginx: 1.18.0+ (生产环境)
后端环境
- JDK: 1.8+
- Maven: 3.6.0+
- MySQL: 5.7+
- Redis: 6.0+
端口要求
| 服务 | 端口 | 说明 |
|---|---|---|
| 前端开发服务器 | 3000 | 开发环境 |
| 后端服务 | 8080 | Spring Boot 应用 |
| MySQL | 3306 | 数据库服务 |
| Redis | 6379 | 缓存服务 |
| Nginx | 80/443 | Web 服务器 |
开发环境部署
1. 环境准备
安装 Node.js
# 使用 nvm 安装 Node.js
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install 16
nvm use 16
# 验证安装
node --version
npm --version
安装 JDK
# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-8-jdk
# CentOS/RHEL
sudo yum install java-1.8.0-openjdk-devel
# 验证安装
java -version
安装 Maven
# 下载 Maven
wget https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
tar -xzf apache-maven-3.6.3-bin.tar.gz
sudo mv apache-maven-3.6.3 /opt/maven
# 配置环境变量
echo 'export MAVEN_HOME=/opt/maven' >> ~/.bashrc
echo 'export PATH=$PATH:$MAVEN_HOME/bin' >> ~/.bashrc
source ~/.bashrc
# 验证安装
mvn -version
安装 MySQL
# Ubuntu/Debian
sudo apt install mysql-server
# CentOS/RHEL
sudo yum install mysql-server
# 启动 MySQL
sudo systemctl start mysqld
sudo systemctl enable mysqld
# 安全配置
sudo mysql_secure_installation
安装 Redis
# Ubuntu/Debian
sudo apt install redis-server
# CentOS/RHEL
sudo yum install redis
# 启动 Redis
sudo systemctl start redis
sudo systemctl enable redis
# 验证安装
redis-cli ping
2. 前端部署
克隆项目
git clone <repository-url>
cd duke-vue
安装依赖
npm install
配置环境变量
# 编辑开发环境配置
vim .env.development
# 配置内容
VITE_APP_BASE_API=/api
VITE_APP_TITLE=Duke Admin
启动开发服务器
npm run dev
构建生产版本
npm run build
3. 后端部署
克隆项目
git clone <repository-url>
cd duke-boot
数据库初始化
# 创建数据库
mysql -u root -p
CREATE DATABASE duke CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
exit
# 执行 SQL 脚本
mysql -u root -p duke < duke-boot.sql
配置数据库连接
# 编辑配置文件
vim duke-admin/src/main/resources/application.yml
# 修改数据库配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/duke?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: your_username
password: your_password
编译项目
mvn clean install -DskipTests
启动应用
# 开发环境启动
mvn spring-boot:run
# 或者直接运行 jar
java -jar duke-admin/target/duke-admin.jar
生产环境部署
1. 服务器准备
系统优化
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装必要软件
sudo apt install -y nginx mysql-server redis-server openjdk-8-jdk
# 配置防火墙
sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 8080
sudo ufw enable
创建应用用户
# 创建应用用户
sudo useradd -m -s /bin/bash duke
sudo passwd duke
# 添加到 sudo 组
sudo usermod -aG sudo duke
2. 数据库部署
MySQL 配置优化
# 编辑 MySQL 配置
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
# 添加以下配置
[mysqld]
# 字符集
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
# 连接数
max_connections = 1000
max_connect_errors = 1000
# 缓冲池
innodb_buffer_pool_size = 1G
innodb_log_file_size = 256M
# 查询缓存
query_cache_size = 64M
query_cache_type = 1
# 重启 MySQL
sudo systemctl restart mysql
创建数据库和用户
-- 创建数据库
CREATE DATABASE duke CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 创建用户
CREATE USER 'duke'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON duke.* TO 'duke'@'localhost';
FLUSH PRIVILEGES;
-- 执行初始化脚本
source /path/to/duke-boot.sql;
3. Redis 配置
Redis 配置优化
# 编辑 Redis 配置
sudo vim /etc/redis/redis.conf
# 修改以下配置
bind 127.0.0.1
port 6379
requirepass your_redis_password
maxmemory 256mb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
# 重启 Redis
sudo systemctl restart redis
4. 后端服务部署
构建应用
# 切换到应用用户
sudo su - duke
# 克隆项目
git clone <repository-url>
cd duke-boot
# 构建项目
mvn clean package -DskipTests
配置应用
# 创建配置目录
mkdir -p /home/duke/config
# 创建生产环境配置文件
vim /home/duke/config/application-prod.yml
# 配置内容
server:
port: 8080
spring:
profiles:
active: prod
datasource:
url: jdbc:mysql://localhost:3306/duke?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: duke
password: your_password
druid:
initial-size: 10
min-idle: 10
max-active: 50
max-wait: 60000
redis:
host: localhost
port: 6379
password: your_redis_password
database: 0
timeout: 10s
lettuce:
pool:
min-idle: 5
max-idle: 20
max-active: 50
max-wait: -1ms
logging:
level:
com.duke: info
file:
name: /home/duke/logs/duke-admin.log
max-size: 100MB
max-history: 30
创建启动脚本
# 创建启动脚本
vim /home/duke/start.sh
#!/bin/bash
APP_NAME="duke-admin"
APP_JAR="duke-admin.jar"
APP_PATH="/home/duke/app"
CONFIG_PATH="/home/duke/config"
LOG_PATH="/home/duke/logs"
# 创建目录
mkdir -p $LOG_PATH
# JVM 参数
JVM_OPTS="-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m"
# 启动应用
nohup java $JVM_OPTS \
-jar $APP_PATH/$APP_JAR \
--spring.config.location=$CONFIG_PATH/application-prod.yml \
> $LOG_PATH/app.log 2>&1 &
echo $! > $APP_PATH/app.pid
echo "应用启动成功,PID: $(cat $APP_PATH/app.pid)"
# 设置执行权限
chmod +x /home/duke/start.sh
创建停止脚本
# 创建停止脚本
vim /home/duke/stop.sh
#!/bin/bash
APP_NAME="duke-admin"
APP_PATH="/home/duke/app"
PID_FILE="$APP_PATH/app.pid"
if [ -f $PID_FILE ]; then
PID=$(cat $PID_FILE)
if ps -p $PID > /dev/null; then
echo "停止应用 $APP_NAME (PID: $PID)..."
kill $PID
sleep 5
if ps -p $PID > /dev/null; then
echo "强制停止应用..."
kill -9 $PID
fi
rm -f $PID_FILE
echo "应用已停止"
else
echo "应用未运行"
rm -f $PID_FILE
fi
else
echo "PID 文件不存在"
fi
chmod +x /home/duke/stop.sh
创建 Systemd 服务
# 创建服务文件
sudo vim /etc/systemd/system/duke-admin.service
[Unit]
Description=Duke Admin Application
After=network.target mysql.service redis.service
[Service]
Type=forking
User=duke
Group=duke
WorkingDirectory=/home/duke
ExecStart=/home/duke/start.sh
ExecStop=/home/duke/stop.sh
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
# 重新加载 systemd
sudo systemctl daemon-reload
# 启用服务
sudo systemctl enable duke-admin
# 启动服务
sudo systemctl start duke-admin
# 查看状态
sudo systemctl status duke-admin
5. 前端部署
构建前端应用
# 切换到应用用户
sudo su - duke
# 克隆前端项目
git clone <repository-url> duke-vue
cd duke-vue
# 安装依赖
npm install
# 构建生产版本
npm run build
Nginx 配置
# 安装 Nginx
sudo apt install nginx
# 创建 Nginx 配置
sudo vim /etc/nginx/sites-available/duke-admin
server {
listen 80;
server_name your-domain.com;
# 前端静态文件
location / {
root /home/duke/duke-vue/dist;
index index.html;
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://localhost:8080/;
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)$ {
root /home/duke/duke-vue/dist;
expires 1y;
add_header Cache-Control "public, immutable";
}
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
}
# 启用站点
sudo ln -s /etc/nginx/sites-available/duke-admin /etc/nginx/sites-enabled/
# 测试配置
sudo nginx -t
# 重启 Nginx
sudo systemctl restart nginx
Docker 部署
1. 后端 Docker 部署
创建 Dockerfile
# 后端 Dockerfile
FROM openjdk:8-jre-alpine
# 设置工作目录
WORKDIR /app
# 复制 jar 包
COPY duke-admin/target/duke-admin.jar app.jar
# 复制配置文件
COPY duke-admin/src/main/resources/application.yml application.yml
# 创建日志目录
RUN mkdir -p /app/logs
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-Xms512m", "-Xmx1024m", "-jar", "app.jar"]
创建 docker-compose.yml
version: "3.8"
services:
# MySQL 服务
mysql:
image: mysql:5.7
container_name: duke-mysql
environment:
MYSQL_ROOT_PASSWORD: root_password
MYSQL_DATABASE: duke
MYSQL_USER: duke
MYSQL_PASSWORD: duke_password
volumes:
- mysql_data:/var/lib/mysql
- ./duke-boot.sql:/docker-entrypoint-initdb.d/duke-boot.sql
ports:
- "3306:3306"
networks:
- duke-network
# Redis 服务
redis:
image: redis:6-alpine
container_name: duke-redis
command: redis-server --requirepass redis_password
volumes:
- redis_data:/data
ports:
- "6379:6379"
networks:
- duke-network
# 后端应用
duke-admin:
build: ./duke-boot
container_name: duke-admin
environment:
SPRING_PROFILES_ACTIVE: docker
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/duke?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
SPRING_DATASOURCE_USERNAME: duke
SPRING_DATASOURCE_PASSWORD: duke_password
SPRING_REDIS_HOST: redis
SPRING_REDIS_PASSWORD: redis_password
ports:
- "8080:8080"
depends_on:
- mysql
- redis
networks:
- duke-network
# Nginx 服务
nginx:
image: nginx:alpine
container_name: duke-nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./duke-vue/dist:/usr/share/nginx/html
ports:
- "80:80"
depends_on:
- duke-admin
networks:
- duke-network
volumes:
mysql_data:
redis_data:
networks:
duke-network:
driver: bridge
部署命令
# 构建并启动服务
docker-compose up -d
# 查看服务状态
docker-compose ps
# 查看日志
docker-compose logs -f duke-admin
# 停止服务
docker-compose down
2. 前端 Docker 部署
创建前端 Dockerfile
# 构建阶段
FROM node:16-alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 生产阶段
FROM nginx:alpine as production-stage
# 复制构建结果
COPY /app/dist /usr/share/nginx/html
# 复制 Nginx 配置
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Nginx 配置
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# 日志格式
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;
error_log /var/log/nginx/error.log;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# 前端路由
location / {
try_files $uri $uri/ /index.html;
}
# API 代理
location /api/ {
proxy_pass http://duke-admin:8080/;
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)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
}
配置管理
1. 环境配置
开发环境配置
# application-dev.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/duke?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: root
password: password
redis:
host: localhost
port: 6379
password:
database: 0
logging:
level:
com.duke: debug
生产环境配置
# application-prod.yml
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/duke?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
username: ${DB_USERNAME:duke}
password: ${DB_PASSWORD:duke_password}
druid:
initial-size: 10
min-idle: 10
max-active: 50
max-wait: 60000
redis:
host: localhost
port: 6379
password: ${REDIS_PASSWORD:redis_password}
database: 0
timeout: 10s
lettuce:
pool:
min-idle: 5
max-idle: 20
max-active: 50
max-wait: -1ms
logging:
level:
com.duke: info
file:
name: logs/duke-admin.log
max-size: 100MB
max-history: 30
2. 安全配置
JWT 配置
# JWT 配置
jwt:
secret: ${JWT_SECRET:duke-secret-key-2024}
expiration: ${JWT_EXPIRATION:86400}
header: Authorization
跨域配置
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOriginPattern("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
监控运维
1. 应用监控
健康检查
# 健康检查接口
curl http://localhost:8080/actuator/health
# 应用信息
curl http://localhost:8080/actuator/info
# 环境信息
curl http://localhost:8080/actuator/env
日志监控
# 查看应用日志
tail -f /home/duke/logs/duke-admin.log
# 查看错误日志
grep "ERROR" /home/duke/logs/duke-admin.log
# 查看访问日志
tail -f /var/log/nginx/access.log
2. 系统监控
系统资源监控
# CPU 使用率
top -p $(pgrep -f duke-admin)
# 内存使用
free -h
# 磁盘使用
df -h
# 网络连接
netstat -tulpn | grep 8080
数据库监控
-- 查看连接数
SHOW STATUS LIKE 'Threads_connected';
-- 查看慢查询
SHOW VARIABLES LIKE 'slow_query_log';
-- 查看锁等待
SHOW ENGINE INNODB STATUS;
3. 告警配置
邮件告警脚本
#!/bin/bash
# 告警脚本
# 配置
SMTP_SERVER="smtp.example.com"
SMTP_PORT="587"
SMTP_USER="alert@example.com"
SMTP_PASS="password"
ALERT_EMAIL="admin@example.com"
# 检查应用状态
check_app() {
if ! curl -f http://localhost:8080/actuator/health > /dev/null 2>&1; then
send_alert "应用服务异常"
fi
}
# 检查数据库连接
check_db() {
if ! mysql -u duke -p'duke_password' -e "SELECT 1" > /dev/null 2>&1; then
send_alert "数据库连接异常"
fi
}
# 检查磁盘空间
check_disk() {
DISK_USAGE=$(df / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $DISK_USAGE -gt 80 ]; then
send_alert "磁盘空间不足: ${DISK_USAGE}%"
fi
}
# 发送告警邮件
send_alert() {
local message="$1"
echo "$(date): $message" | mail -s "Duke Admin 告警" -S smtp="$SMTP_SERVER:$SMTP_PORT" -S smtp-use-starttls -S smtp-auth=login -S smtp-auth-user="$SMTP_USER" -S smtp-auth-password="$SMTP_PASS" "$ALERT_EMAIL"
}
# 执行检查
check_app
check_db
check_disk
故障排查
1. 常见问题
应用启动失败
# 检查端口占用
netstat -tulpn | grep 8080
# 检查日志
tail -f /home/duke/logs/duke-admin.log
# 检查配置文件
java -jar duke-admin.jar --debug
数据库连接失败
# 检查 MySQL 服务状态
sudo systemctl status mysql
# 检查连接
mysql -u duke -p -h localhost
# 检查防火墙
sudo ufw status
Redis 连接失败
# 检查 Redis 服务状态
sudo systemctl status redis
# 测试连接
redis-cli ping
# 检查密码
redis-cli -a your_password ping
2. 性能问题
内存泄漏
# 查看 JVM 内存使用
jstat -gc $(pgrep -f duke-admin)
# 生成堆转储
jmap -dump:format=b,file=heap.hprof $(pgrep -f duke-admin)
慢查询
-- 开启慢查询日志
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 2;
-- 查看慢查询
SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10;
3. 日志分析
错误日志分析
# 统计错误数量
grep "ERROR" /home/duke/logs/duke-admin.log | wc -l
# 查看错误详情
grep "ERROR" /home/duke/logs/duke-admin.log | tail -20
# 分析异常类型
grep "ERROR" /home/duke/logs/duke-admin.log | awk '{print $NF}' | sort | uniq -c
访问日志分析
# 统计访问量
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr
# 统计响应时间
awk '{print $10}' /var/log/nginx/access.log | sort -n | tail -10
# 统计状态码
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c
性能优化
1. JVM 优化
JVM 参数调优
# 生产环境 JVM 参数
JVM_OPTS="-server \
-Xms2g \
-Xmx2g \
-XX:MetaspaceSize=256m \
-XX:MaxMetaspaceSize=512m \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/home/duke/logs/ \
-XX:+PrintGCDetails \
-XX:+PrintGCTimeStamps \
-Xloggc:/home/duke/logs/gc.log"
2. 数据库优化
MySQL 配置优化
[mysqld]
# 缓冲池大小
innodb_buffer_pool_size = 2G
# 日志文件大小
innodb_log_file_size = 512M
# 连接数
max_connections = 1000
# 查询缓存
query_cache_size = 128M
query_cache_type = 1
# 慢查询日志
slow_query_log = 1
long_query_time = 2
索引优化
-- 分析表
ANALYZE TABLE sys_user;
-- 查看索引使用情况
SHOW INDEX FROM sys_user;
-- 创建复合索引
CREATE INDEX idx_user_dept_status ON sys_user(dept_id, status);
3. 缓存优化
Redis 配置优化
# Redis 配置优化
maxmemory 1gb
maxmemory-policy allkeys-lru
save 900 1
save 300 10
save 60 10000
应用缓存策略
// 缓存配置
@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
}
}
4. 前端优化
Nginx 配置优化
# 启用 Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# 启用 HTTP/2
listen 443 ssl http2;
前端构建优化
// vite.config.js
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {
vendor: ["vue", "vue-router", "pinia"],
element: ["element-plus"],
},
},
},
chunkSizeWarningLimit: 1000,
},
});
