Docker 部署指南
使用 Docker 容器化部署全部服务(MySQL、Redis、后端、Nginx),适合追求环境一致性和快速部署的场景。
如需传统 JAR 包方式部署,请参考 普通部署指南。
一、整体流程
本地/构建机 生产服务器(仅需 Docker)
┌──────────────────┐ ┌──────────────────────────┐
│ 1. 拉取代码 │ │ 3. 安装 Docker │
│ 2. 构建后端+前端 │ ── 上传产物 ──▶ │ 4. 部署 MySQL + Redis │
│ (JAR + dist) │ │ 5. 初始化数据库 │
└──────────────────┘ │ 6. 部署后端(Docker 镜像) │
│ 7. 部署前端(Nginx 容器) │
└──────────────────────────┘⚠️ 不建议在生产服务器上执行构建。构建过程消耗大量 CPU 和内存,且需要安装 Maven、Node.js 等工具链,会污染生产环境。请在本地开发机或专用构建机上完成构建,仅将产物上传到服务器。
二、本地构建(开发机 / 构建机)
以下操作在本地开发机或构建机上执行,不在生产服务器上操作。
2.1 构建环境要求
| 软件 | 版本要求 | 用途 |
|---|---|---|
| JDK | 17 或 21 | 编译后端 |
| Maven | 3.8+ | 构建后端项目 |
| Node.js | ≥ 20.19.0 | 构建前端项目 |
| pnpm | ≥ 10.0.0 | 前端包管理器 |
| Git | 2.x | 拉取代码 |
2.2 拉取代码
mkdir -p ~/workspace && cd ~/workspace
git clone <后端仓库地址> ruoyi-office
git clone <前端仓库地址> ruoyi-office-vben2.3 构建后端
cd ~/workspace/ruoyi-office
mvn clean package -Dmaven.test.skip=true -Dskip.repackage=true -pl yudao-server -am -Pprod
# 确认产物
ls -lh yudao-server/target/yudao-server.jar⚠️ 关键参数:
-Dskip.repackage=true:子模块跳过 repackage,由 yudao-server 统一打 Fat JAR-pl yudao-server -am:仅构建 yudao-server 及其依赖-Pprod:激活生产环境 Profile首次构建需下载依赖,约 5-15 分钟。
💡 Maven 国内加速:编辑
$MAVEN_HOME/conf/settings.xml,在<mirrors>中添加:xml<mirror> <id>aliyun</id> <mirrorOf>central</mirrorOf> <url>https://maven.aliyun.com/repository/public</url> </mirror>
2.4 构建前端
cd ~/workspace/ruoyi-office-vben
# 1. 安装依赖
pnpm install
# 2. 构建 Monorepo 内部依赖包
pnpm -r --filter "./packages/**" --filter "./internal/**" build
# 3. 构建前端应用
cd apps/web-antd
pnpm build构建产物位于 apps/web-antd/dist/。
💡 内存不足报 OOM?执行
export NODE_OPTIONS="--max-old-space-size=4096"后重试。💡
vite.config.mts已配置生产环境base: '/web/',无需额外修改。
2.5 上传产物到服务器
# 在服务器上预先创建目录
ssh root@服务器IP "mkdir -p /data/app/yudao-server/target /data/nginx/html/web /data/"
# 上传后端 JAR 和 Dockerfile
scp ~/workspace/ruoyi-office/yudao-server/target/yudao-server.jar root@服务器IP:/data/app/yudao-server/target/
scp ~/workspace/ruoyi-office/yudao-server/Dockerfile root@服务器IP:/data/app/yudao-server/
# 上传前端产物
scp -r ~/workspace/ruoyi-office-vben/apps/web-antd/dist/* root@服务器IP:/data/nginx/html/web/
# 上传数据库 SQL(首次部署时需要)
scp ~/workspace/ruoyi-office-db/ruoyi-office-20260301.sql root@服务器IP:/data/也可使用 FTP、rsync 或其他文件传输方式,效果相同。
三、安装 Docker(生产服务器)
以下所有操作均在生产服务器上执行。生产服务器只需要安装 Docker,不需要 Maven、Node.js 等构建工具。
3.1 服务器配置要求
| 项目 | 最低配置 | 推荐配置 |
|---|---|---|
| CPU | 2 核 | 4 核+ |
| 内存 | 4 GB | 8 GB+ |
| 磁盘 | 40 GB | 100 GB+ |
| 操作系统 | CentOS 7+ / Ubuntu 20.04+ | CentOS Stream 9 / Ubuntu 22.04 |
3.2 端口规划
| 服务 | 端口 | 容器名 |
|---|---|---|
| Nginx | 80 | nginx |
| yudao-server | 48080 | yudao-server |
| MySQL | 3306 | mysql |
| Redis | 6379 | redis |
3.3 安装 Docker
# ==================== CentOS / RHEL ====================
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl start docker && systemctl enable docker
# ==================== Ubuntu / Debian ====================
apt-get update
apt-get install -y ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io3.4 配置镜像加速(推荐)
mkdir -p /etc/docker
cat > /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
EOF
systemctl daemon-reload && systemctl restart docker3.5 验证
docker --version
docker compose version四、部署 MySQL
4.1 创建目录和配置
mkdir -p /data/mysql/{data,conf}
cat > /data/mysql/conf/my.cnf << 'EOF'
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
default-authentication-plugin=mysql_native_password
lower_case_table_names=1
max_connections=500
innodb_buffer_pool_size=512M
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
EOF4.2 启动容器
docker run -d \
--name mysql \
--restart always \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD='YourPassword123!' \
-v /data/mysql/data:/var/lib/mysql \
-v /data/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf \
mysql:8.0.334.3 验证
sleep 20
docker exec -it mysql mysql -uroot -p'YourPassword123!' -e "SELECT VERSION();"五、部署 Redis
5.1 创建目录和配置
mkdir -p /data/redis/{data,conf}
cat > /data/redis/conf/redis.conf << 'EOF'
bind 0.0.0.0
port 6379
appendonly yes
maxmemory 512mb
maxmemory-policy allkeys-lru
dir /data
EOF5.2 启动容器
docker run -d \
--name redis \
--restart always \
-p 6379:6379 \
-v /data/redis/data:/data \
-v /data/redis/conf/redis.conf:/etc/redis/redis.conf \
redis:7.2 \
redis-server /etc/redis/redis.conf5.3 验证
docker exec -it redis redis-cli ping
# 返回 PONG六、初始化数据库
6.1 创建数据库
docker exec -it mysql mysql -uroot -p'YourPassword123!' -e \
"CREATE DATABASE IF NOT EXISTS \`ruoyi-office\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"6.2 导入数据
# SQL 文件已在 2.5 步上传到 /data/ 目录
docker exec -i mysql mysql -uroot -p'YourPassword123!' ruoyi-office < /data/ruoyi-office-20260301.sql6.3 验证
docker exec -it mysql mysql -uroot -p'YourPassword123!' -e "USE ruoyi-office; SHOW TABLES;" | head -20
# 能看到 system_users 等表即成功七、部署后端
7.1 确认文件
# JAR 和 Dockerfile 已在 2.5 步上传
ls -lh /data/app/yudao-server/target/yudao-server.jar
ls -lh /data/app/yudao-server/Dockerfile项目自带 Dockerfile(
yudao-server/Dockerfile),基于eclipse-temurin:21-jre:dockerfileFROM eclipse-temurin:21-jre RUN mkdir -p /yudao-server WORKDIR /yudao-server COPY ./target/yudao-server.jar app.jar ENV TZ=Asia/Shanghai ENV JAVA_OPTS="-Xms1024m -Xmx4096m -Djava.security.egd=file:/dev/./urandom" ENV ARGS="" EXPOSE 48080 CMD java ${JAVA_OPTS} -jar app.jar $ARGS
7.2 构建镜像
cd /data/app/yudao-server
docker build -t yudao-server:latest .7.3 获取宿主机 IP
容器内不能用 127.0.0.1 访问宿主机上的 MySQL / Redis,需要使用宿主机内网 IP:
hostname -I | awk '{print $1}'
# 假设结果为 192.168.1.100,后续命令中替换7.4 启动容器
docker stop yudao-server 2>/dev/null; docker rm yudao-server 2>/dev/null
docker run -d \
--name yudao-server \
--restart always \
-p 48080:48080 \
-e "SPRING_PROFILES_ACTIVE=prod" \
-e "JAVA_OPTS=-Xms512m -Xmx2048m -Djava.security.egd=file:/dev/./urandom" \
-e "TZ=Asia/Shanghai" \
-e "MYSQL_URL=jdbc:mysql://192.168.1.100:3306/ruoyi-office?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true" \
-e "MYSQL_USERNAME=root" \
-e "MYSQL_PASSWORD=YourPassword123!" \
-e "REDIS_HOST=192.168.1.100" \
-e "REDIS_PORT=6379" \
-e "REDIS_PASSWORD=" \
-v /data/app/logs:/yudao-server/logs \
yudao-server:latest将
192.168.1.100替换为你的宿主机实际内网 IP。💡 简化方案:使用
--network host模式,容器直接使用宿主机网络,此时可用127.0.0.1:bashdocker run -d \ --name yudao-server \ --restart always \ --network host \ -e "SPRING_PROFILES_ACTIVE=prod" \ -e "JAVA_OPTS=-Xms512m -Xmx2048m" \ -e "MYSQL_PASSWORD=YourPassword123!" \ -e "REDIS_PASSWORD=" \ -v /data/app/logs:/yudao-server/logs \ yudao-server:latest
7.5 验证
docker ps | grep yudao-server
docker logs -f yudao-server --tail 100
# 等待 30-60 秒
curl http://127.0.0.1:48080/actuator/health
# 返回 {"status":"UP"} 即成功八、部署前端(Nginx)
8.1 确认文件
mkdir -p /data/nginx/{conf/conf.d,logs}
# 前端文件已在 2.5 步上传到 /data/nginx/html/web/
ls -la /data/nginx/html/web/index.html8.2 创建 Nginx 配置
cat > /data/nginx/conf/conf.d/ruoyi-office.conf << 'NGINXEOF'
server {
listen 80;
server_name _;
charset utf-8;
# Gzip 压缩
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml text/javascript
application/json application/javascript application/xml+rss
application/x-javascript image/svg+xml;
# ========== 前端静态文件 ==========
location /web {
alias /usr/share/nginx/html/web;
index index.html;
try_files $uri $uri/ /web/index.html;
}
# 静态资源长缓存
location ~* ^/web/(.+)\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
root /usr/share/nginx/html;
expires 30d;
add_header Cache-Control "public, immutable";
access_log off;
}
# ========== 后端 API 反向代理 ==========
location /admin-api {
proxy_pass http://宿主机IP:48080/admin-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;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
# ========== 根路径跳转 ==========
location = / {
return 302 /web;
}
}
NGINXEOF⚠️ 务必替换
proxy_pass中的宿主机IP为实际内网 IP(如192.168.1.100)。Nginx 容器内127.0.0.1指向的是 Nginx 容器自身,无法访问后端容器。💡 如果后端使用了
--network host,Nginx 也可以使用--network host,此时proxy_pass可直接写http://127.0.0.1:48080/admin-api。
8.3 启动 Nginx 容器
docker run -d \
--name nginx \
--restart always \
-p 80:80 \
-v /data/nginx/conf/conf.d:/etc/nginx/conf.d \
-v /data/nginx/html:/usr/share/nginx/html \
-v /data/nginx/logs:/var/log/nginx \
nginx:latest8.4 验证
docker exec nginx nginx -t
curl -I http://127.0.0.1/web
# 返回 200 OK浏览器访问 http://服务器IP/web,出现登录页即成功。
| 账号 | 密码 |
|---|---|
| admin | admin123 |
九、Docker Compose 一键部署(可选)
项目提供了 yudao-server/docker-compose.yml,可一键编排 MySQL + Redis + 后端。结合手动部署 Nginx,实现全容器化:
cd /data/app/yudao-server
# 确保已构建镜像
docker build -t yudao-server:latest .
# 确保目录和配置已创建(参考第四、五章)
# 一键启动
docker compose up -d
# 查看状态
docker compose ps
docker compose logs -f yudao-server十、日常更新
更新流程同样遵循「本地构建 → 上传产物 → 服务器重部署」的原则。
更新后端
# ===== 本地/构建机 =====
cd ~/workspace/ruoyi-office && git pull origin master
mvn clean package -Dmaven.test.skip=true -Dskip.repackage=true -pl yudao-server -am -Pprod
scp yudao-server/target/yudao-server.jar root@服务器IP:/data/app/yudao-server/target/
# ===== 生产服务器 =====
cd /data/app/yudao-server
docker build -t yudao-server:latest .
docker stop yudao-server && docker rm yudao-server
# 重新执行 docker run 命令(同第七章)更新前端
# ===== 本地/构建机 =====
cd ~/workspace/ruoyi-office-vben && git pull origin master
pnpm install
pnpm -r --filter "./packages/**" --filter "./internal/**" build
cd apps/web-antd && pnpm build
# 上传(先清理再上传)
ssh root@服务器IP "rm -rf /data/nginx/html/web/*"
scp -r dist/* root@服务器IP:/data/nginx/html/web/
# 静态文件替换即时生效,无需重启 Nginx更新数据库
# 将增量 SQL 上传到服务器后执行
docker exec -i mysql mysql -uroot -p'YourPassword123!' ruoyi-office < 增量SQL文件.sql十一、容器管理速查
# ==================== 查看所有容器状态 ====================
docker ps -a --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
# ==================== 后端 ====================
docker stop yudao-server
docker start yudao-server
docker restart yudao-server
docker logs -f yudao-server --tail 200
# ==================== Nginx ====================
docker exec nginx nginx -t # 检查配置
docker exec nginx nginx -s reload # 重载配置
docker restart nginx
# ==================== MySQL ====================
docker exec -it mysql mysql -uroot -p # 进入 MySQL
docker restart mysql
# ==================== Redis ====================
docker exec -it redis redis-cli # 进入 Redis CLI
docker restart redis
# ==================== 日志 ====================
docker logs -f yudao-server --tail 200 # 后端日志
docker exec nginx tail -f /var/log/nginx/error.log # Nginx 错误日志
tail -f /data/app/logs/*.log # 挂载的后端日志
# ==================== 清理 ====================
docker image prune -f # 清理无用镜像
docker system df # 查看 Docker 磁盘占用十二、常见问题
Q1:后端容器启动后立即退出?
docker logs yudao-server --tail 200常见原因:①数据库连接失败(检查 IP、端口、密码)②Redis 连接失败 ③内存不足(减小 -Xmx)④端口冲突。
Q2:容器内后端无法连接 MySQL / Redis?
容器内 127.0.0.1 指向容器自身,不是宿主机。三种解决方案:
# 方案一:使用宿主机内网 IP(推荐)
-e "REDIS_HOST=192.168.1.100"
# 方案二:使用 --network host(容器共享宿主机网络)
docker run --network host ...
# 方案三:所有容器放同一 Docker 网络,用容器名互访
docker network create ruoyi-net
docker run --network ruoyi-net --name mysql ...
docker run --network ruoyi-net -e "REDIS_HOST=redis" ...Q3:Nginx 反代后端接口报 502?
检查 ruoyi-office.conf 中 proxy_pass 的 IP 是否正确。Nginx 容器内的 127.0.0.1 无法访问后端容器。
Q4:Docker 镜像拉取慢或失败?
确认镜像加速已配置(参考 3.4 节),或手动指定国内源:
docker pull swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/mysql:8.0.33
docker tag swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/mysql:8.0.33 mysql:8.0.33Q5:前端构建报 JavaScript heap out of memory?
export NODE_OPTIONS="--max-old-space-size=4096"
pnpm buildQ6:JAR 包超过 500MB?
构建命令必须包含 -Dskip.repackage=true,否则子模块各自打 Fat JAR 造成重复。
Q7:如何修改后端配置而不重新构建镜像?
通过 -e 环境变量覆盖即可,配置文件支持环境变量占位符:
docker run ... \
-e "MYSQL_PASSWORD=新密码" \
-e "REDIS_HOST=新地址" \
yudao-server:latestQ8:如何备份数据?
# MySQL
docker exec mysql mysqldump -uroot -p'YourPassword123!' ruoyi-office > backup_$(date +%Y%m%d).sql
# Redis
docker exec redis redis-cli BGSAVE
# 前端
tar -czf web-backup-$(date +%Y%m%d).tar.gz /data/nginx/html/web/