生产环境部署
作者:唐亚峰 | battcn
字数统计:2.1k 字
重要提醒
生产环境部署需要格外注意安全性、可用性和性能,请仔细阅读本文档
部署架构
单机部署架构
适合小型项目、测试环境:
┌─────────────────┐
│ Nginx │
│ (443/80) │
└────────┬────────┘
│
┌──────────────┼──────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ 前端静态 │ │ Gateway │ │ Nacos │
│ 文件 │ │ 9000 │ │ 8848 │
└───────────┘ └─────┬─────┘ └───────────┘
│
┌────────┼────────┐
│ │ │
┌─────▼────┐ ┌─▼────┐ ┌─▼────┐
│ IAM │ │Suite │ │Plugin│
│ 5001 │ │ 5002 │ │ ... │
└─────┬────┘ └──┬───┘ └──┬───┘
│ │ │
└─────────┼────────┘
│
┌─────────┼─────────┐
│ │ │
┌─────▼───┐ ┌───▼───┐ ┌───▼───┐
│ MySQL │ │ Redis │ │ MinIO │
│ 3306 │ │ 6379 │ │ 9000 │
└─────────┘ └───────┘ └───────┘高可用集群架构
适合中大型项目、生产环境:
┌──────────────┐
│ SLB/LB │
└──────┬───────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Nginx-1 │ │ Nginx-2 │ │ Nginx-3 │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└─────────────────┼─────────────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Gateway-1 │ │ Gateway-2 │ │ Gateway-3 │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└─────────────────┼─────────────────┘
│
┌─────▼─────┐
│ Nacos │
│ Cluster │
└─────┬─────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ IAM × N │ │ Suite × N │ │ Plugin × N│
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
└───────────────────────┼───────────────────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│MySQL主从 │ │Redis集群 │ │MinIO集群 │
└───────────┘ └───────────┘ └───────────┘生产级 Docker Compose
目录结构
/opt/wemirr/
├── docker-compose.yml
├── .env
├── nginx/
│ ├── nginx.conf
│ ├── conf.d/
│ │ └── default.conf
│ └── ssl/
│ ├── cert.pem
│ └── key.pem
├── mysql/
│ ├── conf/
│ │ └── my.cnf
│ └── init/
│ └── init.sql
├── redis/
│ └── redis.conf
├── logs/
└── data/docker-compose.yml
yaml
version: '3.8'
networks:
wemirr-net:
driver: bridge
volumes:
mysql-data:
redis-data:
nacos-data:
minio-data:
gateway-logs:
iam-logs:
suite-logs:
services:
# ==================== 中间件层 ====================
mysql:
image: mysql:8.0
container_name: wemirr-mysql
networks:
- wemirr-net
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- TZ=Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
- ./mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf
- ./mysql/init:/docker-entrypoint-initdb.d
command:
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --lower_case_table_names=1
- --max_connections=1000
- --innodb_buffer_pool_size=1G
deploy:
resources:
limits:
memory: 2G
restart: always
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: wemirr-redis
networks:
- wemirr-net
ports:
- "6379:6379"
volumes:
- redis-data:/data
- ./redis/redis.conf:/usr/local/etc/redis/redis.conf
command: redis-server /usr/local/etc/redis/redis.conf
deploy:
resources:
limits:
memory: 512M
restart: always
healthcheck:
test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"]
interval: 10s
timeout: 5s
retries: 5
nacos:
image: nacos/nacos-server:v2.3.0
container_name: wemirr-nacos
networks:
- wemirr-net
ports:
- "8848:8848"
- "9848:9848"
- "9849:9849"
environment:
- MODE=standalone
- SPRING_DATASOURCE_PLATFORM=mysql
- MYSQL_SERVICE_HOST=mysql
- MYSQL_SERVICE_PORT=3306
- MYSQL_SERVICE_DB_NAME=nacos
- MYSQL_SERVICE_USER=root
- MYSQL_SERVICE_PASSWORD=${MYSQL_ROOT_PASSWORD}
- NACOS_AUTH_ENABLE=true
- NACOS_AUTH_TOKEN=${NACOS_AUTH_TOKEN}
- NACOS_AUTH_IDENTITY_KEY=serverIdentity
- NACOS_AUTH_IDENTITY_VALUE=${NACOS_IDENTITY_VALUE}
- JVM_XMS=512m
- JVM_XMX=1g
volumes:
- nacos-data:/home/nacos/data
depends_on:
mysql:
condition: service_healthy
deploy:
resources:
limits:
memory: 1.5G
restart: always
minio:
image: bitnami/minio:latest
container_name: wemirr-minio
networks:
- wemirr-net
ports:
- "19000:9000"
- "19001:9001"
environment:
- MINIO_ROOT_USER=${MINIO_ROOT_USER}
- MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
- MINIO_DEFAULT_BUCKETS=wemirr-bucket
volumes:
- minio-data:/bitnami/minio/data
deploy:
resources:
limits:
memory: 512M
restart: always
# ==================== 应用层 ====================
gateway:
image: registry.cn-hangzhou.aliyuncs.com/wemirr/wemirr-platform-gateway:${APP_VERSION}
container_name: wemirr-gateway
networks:
- wemirr-net
ports:
- "9000:9000"
environment:
- SPRING_PROFILES_ACTIVE=prod
- NACOS_SERVER_ADDR=nacos:8848
- NACOS_NAMESPACE=${NACOS_NAMESPACE}
- TZ=Asia/Shanghai
- JAVA_OPTS=-Xms512m -Xmx1g -XX:+UseG1GC
volumes:
- gateway-logs:/app/logs
depends_on:
- nacos
- redis
deploy:
resources:
limits:
memory: 1.5G
restart: always
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
iam:
image: registry.cn-hangzhou.aliyuncs.com/wemirr/wemirr-platform-iam:${APP_VERSION}
container_name: wemirr-iam
networks:
- wemirr-net
ports:
- "5001:5001"
environment:
- SPRING_PROFILES_ACTIVE=prod
- NACOS_SERVER_ADDR=nacos:8848
- NACOS_NAMESPACE=${NACOS_NAMESPACE}
- TZ=Asia/Shanghai
- JAVA_OPTS=-Xms512m -Xmx1g -XX:+UseG1GC
volumes:
- iam-logs:/app/logs
depends_on:
- nacos
- mysql
- redis
deploy:
resources:
limits:
memory: 1.5G
restart: always
suite:
image: registry.cn-hangzhou.aliyuncs.com/wemirr/wemirr-platform-suite:${APP_VERSION}
container_name: wemirr-suite
networks:
- wemirr-net
ports:
- "5002:5002"
environment:
- SPRING_PROFILES_ACTIVE=prod
- NACOS_SERVER_ADDR=nacos:8848
- NACOS_NAMESPACE=${NACOS_NAMESPACE}
- TZ=Asia/Shanghai
- JAVA_OPTS=-Xms512m -Xmx1g -XX:+UseG1GC
volumes:
- suite-logs:/app/logs
depends_on:
- nacos
- mysql
- redis
deploy:
resources:
limits:
memory: 1.5G
restart: always
# ==================== 反向代理 ====================
nginx:
image: nginx:alpine
container_name: wemirr-nginx
networks:
- wemirr-net
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
- ./nginx/html:/usr/share/nginx/html
- ./logs/nginx:/var/log/nginx
depends_on:
- gateway
restart: always.env 文件
bash
# MySQL
MYSQL_ROOT_PASSWORD=your_secure_mysql_password_here
# Redis
REDIS_PASSWORD=your_secure_redis_password_here
# Nacos
NACOS_AUTH_TOKEN=SecretKey012345678901234567890123456789012345678901234567890123456789
NACOS_IDENTITY_VALUE=your_identity_value
NACOS_NAMESPACE=prod
# MinIO
MINIO_ROOT_USER=minio_admin
MINIO_ROOT_PASSWORD=your_secure_minio_password_here
# 应用版本
APP_VERSION=v4.0.0Nginx 配置
nginx
# nginx/conf.d/default.conf
upstream gateway {
server gateway:9000;
keepalive 32;
}
server {
listen 80;
server_name your-domain.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers off;
# 安全头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
# 前端静态资源
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
# 静态资源缓存
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
# API 代理
location /api/ {
proxy_pass http://gateway/;
proxy_http_version 1.1;
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_set_header Connection "";
# 超时设置
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# WebSocket 支持
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# 健康检查
location /health {
return 200 'OK';
add_header Content-Type text/plain;
}
}使用仓库自带 Nginx 配置(推荐先对齐)
Wemirr 后端仓库在 附件/nginx/ 目录提供了作者线上环境使用的 Nginx 配置,适合你在生产环境落地时参考并做二次调整:
wemirr-platform/附件/nginx/nginx-http.confwemirr-platform/附件/nginx/nginx-https.conf
说明:配置中默认域名为
cloud.battcn.com,静态资源目录为/opt/wemirr-platform/cloud-ui/dist,你需要替换为自己的域名与前端产物路径。
HTTP 版本示例(来自仓库)
nginx
server {
listen 80;
server_name cloud.battcn.com;
location / {
# vue 静态资源打成tar.gz 包 开启压缩 速度更快
root /opt/wemirr-platform/cloud-ui/dist;
gzip_static on;
}
location /api/ {
proxy_pass http://localhost:9000/;
proxy_redirect off;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}HTTPS 版本示例(来自仓库)
nginx
server {
listen 80;
server_name cloud.battcn.com;
rewrite ^(.*)$ https://cloud.battcn.com;
}
server {
listen 443 ssl;
server_name cloud.battcn.com;
ssl on;
# 证书是从阿里云申请的免费证书
ssl_certificate /usr/local/nginx/conf/myconf/cert/cloud/4869096_cloud.battcn.com.pem;
ssl_certificate_key /usr/local/nginx/conf/myconf/cert/cloud/4869096_cloud.battcn.com.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
# vue 静态资源打成tar.gz 包 开启压缩 速度更快
root /opt/wemirr-platform/cloud-ui/dist;
gzip_static on;
}
location /api/ {
proxy_pass http://localhost:9000/;
proxy_redirect off;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
}静态资源路径建议
配置中的 root /opt/wemirr-platform/cloud-ui/dist; 是作者线上路径。
如果你的前端是通过 wemirr-platform-ui 构建产物部署,建议将产物解压到类似目录:
/opt/wemirr-platform/
└── cloud-ui/
└── dist/并保持与 Nginx root 一致。
生产部署检查清单
1. 端口暴露
- 对外只暴露:
80/443 3306/6379/8848/15672等中间件端口:- 建议只在内网访问
- 或通过防火墙限制来源 IP
2. 数据持久化
- MySQL:必须挂载
/var/lib/mysql - Redis:建议开启 AOF 并挂载
/data - Nacos:建议挂载
/home/nacos/data
3. 备份与恢复演练
- 至少保证:数据库备份 + Nacos 配置备份
- 建议每月至少做一次恢复演练
4. 配置与密钥
.env与证书文件不要提交到仓库- Nacos Token、Redis 密码、MySQL 密码必须使用强密码
MySQL 配置
ini
# mysql/conf/my.cnf
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
lower_case_table_names=1
# 连接数
max_connections=1000
max_connect_errors=100
# InnoDB
innodb_buffer_pool_size=1G
innodb_log_file_size=256M
innodb_flush_log_at_trx_commit=2
innodb_flush_method=O_DIRECT
# 日志
slow_query_log=1
slow_query_log_file=/var/lib/mysql/slow.log
long_query_time=2
# 二进制日志(主从复制需要)
server-id=1
log_bin=mysql-bin
binlog_format=ROW
expire_logs_days=7
[client]
default-character-set=utf8mb4Redis 配置
conf
# redis/redis.conf
bind 0.0.0.0
port 6379
requirepass your_secure_redis_password_here
# 持久化
appendonly yes
appendfsync everysec
# 内存管理
maxmemory 512mb
maxmemory-policy allkeys-lru
# 安全
rename-command FLUSHALL ""
rename-command FLUSHDB ""
rename-command CONFIG ""部署流程
1. 准备服务器
bash
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装 Docker
curl -fsSL https://get.docker.com | sh
sudo systemctl enable docker
# 安装 Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose2. 部署中间件
bash
cd /opt/wemirr
# 启动中间件
docker-compose up -d mysql redis nacos minio
# 等待服务就绪
sleep 30
# 检查服务状态
docker-compose ps3. 初始化数据
bash
# 导入数据库
docker exec -i wemirr-mysql mysql -uroot -p${MYSQL_ROOT_PASSWORD} < ./mysql/init/wemirr_platform.sql
# 导入 Nacos 配置(通过 Web 界面或 API)4. 部署应用
bash
# 启动所有应用
docker-compose up -d gateway iam suite nginx
# 查看日志
docker-compose logs -f gateway iam suite5. 验证部署
bash
# 健康检查
curl -s http://localhost/health
curl -s http://localhost:9000/actuator/health
# 访问系统
echo "请访问: https://your-domain.com"运维管理
日志管理
bash
# 查看实时日志
docker-compose logs -f --tail=100 gateway
# 日志轮转配置
cat > /etc/docker/daemon.json << EOF
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "3"
}
}
EOF监控告警
推荐使用 Prometheus + Grafana 进行监控:
yaml
# 添加到 docker-compose.yml
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
ports:
- "9090:9090"
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin123备份策略
bash
#!/bin/bash
# backup.sh
BACKUP_DIR=/opt/wemirr/backup/$(date +%Y%m%d)
mkdir -p $BACKUP_DIR
# 备份 MySQL
docker exec wemirr-mysql mysqldump -uroot -p${MYSQL_ROOT_PASSWORD} --all-databases > $BACKUP_DIR/mysql.sql
# 备份 Redis
docker exec wemirr-redis redis-cli -a ${REDIS_PASSWORD} BGSAVE
docker cp wemirr-redis:/data/dump.rdb $BACKUP_DIR/
# 备份配置文件
cp -r /opt/wemirr/.env /opt/wemirr/nginx $BACKUP_DIR/
# 清理7天前的备份
find /opt/wemirr/backup -type d -mtime +7 -exec rm -rf {} +添加到 crontab:
bash
0 2 * * * /opt/wemirr/backup.sh安全加固
1. 防火墙配置
bash
# 只开放必要端口
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 22/tcp
sudo ufw enable2. 密码强度
- MySQL 密码至少 16 位,包含大小写字母、数字、特殊字符
- Redis 密码至少 32 位
- Nacos Token 至少 64 位
3. 定期更新
bash
# 更新镜像
docker-compose pull
docker-compose up -d