传统业务容器化

传统业务容器化
[TOC]
若依项目介绍
==RuoYi-Vue== 是一个基于经典技术栈的Java EE企业级快速开发平台,它整合了Spring Boot、Spring Security、MyBatis、JWT和Vue等主流技术
- 帮助开发者快速搭建稳定、安全且可扩展的企业应用系统


- 参考文档📄

手动部署
数据库安装
1)克隆(下载)代码[root@Docker ~]# git clone https://gitee.com/y_project/RuoYi-Vue.git'下载的时候,也会给你创建一个目录'[root@Docker ~]# lsRuoYi[root@Docker ~]# cd RuoYi-Vue/[root@Docker RuoYi-Vue]#[root@Docker RuoYi-Vue]# lsbin LICENSE README.md ruoyi-common ....xxx
2)部署MySQL# 这次使用容器[root@Docker RuoYi-Vue]# docker container run \ -e MYSQL_ALLOW_EMPTY_PASSWORD="yes" \ -d \ -p 3306:3306 \ --name mysql-server \ -e MYSQL_DATABASE="ry-vue" \ -e MYSQL_USER="jiu" \ -e MYSQL_PASSWORD="oldboy123.com" \ mysql:8.0.36 \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci \ --default-authentication-plugin=mysql_native_password# 数据库是ry-vue[root@Docker RuoYi-Vue]# docker ps3c2a88c2023b mysql:8.0.36 "docker-entrypoint.s…" 3 seconds ago Up 3 seconds 0.0.0.0:3306->3306/tcp, [::]:3306->3306/tcp, 33060/tcp mysql-server[root@Docker RuoYi-Vue]# ss -lnt | grep 3306LISTEN 0 4096 0.0.0.0:3306 0.0.0.0:*LISTEN 0 4096 [::]:3306 [::]:*
3)导入sql语句# 创建数据库ry-vue并导入数据脚本ry_2021xxxx.sql,quartz.sql# 官方文档👆,但其实并没有给你具体的sql语句位置📍[root@Docker RuoYi-Vue]# find ./ -name "*.sql"./sql/quartz.sql./sql/ry_20260417.sql# 直接把 ./sql 目录拷贝至容器中[root@Docker RuoYi-Vue]# docker cp ./sql mysql-server:/Successfully copied 415kB (transferred 419kB) to mysql-server:/[root@Docker RuoYi-Vue]# docker exec -it mysql-server /bin/bashbash-4.4# mysql ry-vue < /sql/quartz.sqlbash-4.4# mysql ry-vue < /sql/ry_20260417.sqlbash-4.4# mysqlWelcome to the MySQL monitor.mysql> show databases;+--------------------+| Database |+--------------------+| information_schema || mysql || performance_schema || ry-vue || sys |+--------------------+mysql> use ry-vue;mysql> show tables;+--------------------------+| Tables_in_ry-vue |+--------------------------+| QRTZ_BLOB_TRIGGERS || QRTZ_CALENDARS || QRTZ_CRON_TRIGGERS || xxxxx........... |
3)修改配置文件指向数据库[root@Docker RuoYi-Vue]# vim ./ruoyi-admin/src/main/resources/application-druid.yml url: jdbc:mysql://localhost:3306/ry-vue?use...xxx username: jiu password: oldboy123.com# url不需要动,本地的3306端口,传递了一些参数⚠️ 确保这个url是localhost:3306/ry-vue'后面紧跟的是数据库,我们创建的是ry-vue'# 改用户名和密码===================================✅️ 服务器配置'里面有详细的备注'[root@Docker RuoYi-Vue]# cat./ruoyi-admin/src/main/resources/application.yml📌 开发环境配置 --> 里面也有Redis缓存的东西server: port: 8080# 后端访问入口为8080# 前端我们改为80'各种服务的配置!非常详细'[root@Docker RuoYi-Vue]# ss -lntup | grep 8080⚠️ 8080端口没有被占用==================================='Redis缓存'# 直接运行容器了[root@Docker RuoYi-Vue]# docker container run -d \ --name redis-server \ -p 6379:6379 \ redis:7.2.8[root@Docker RuoYi-Vue]# ss -lnt | grep 6379LISTEN 0 4096 0.0.0.0:6379 0.0.0.0:*LISTEN 0 4096 [::]:6379 [::]:*
JDK安装

- Java SE 17.0.12
- 地址在上面👆
1)上传解压[root@Docker RuoYi-Vue]# ls /tmp/jdk-17.0.12_linux-x64_bin.tar.gz/tmp/jdk-17.0.12_linux-x64_bin.tar.gz[root@Docker RuoYi-Vue]# tar xf /tmp/jdk-17.0.12_linux-x64_bin.tar.gz -C /usr/local/[root@Docker RuoYi-Vue]# ls /usr/local/jdk-17.0.12/bin conf
2)添加环境变量[root@Docker RuoYi-Vue]# vim /etc/profile# javaexport JAVA_HOME=/usr/local/jdk-17.0.12export PATH=$PATH:$JAVA_HOME/bin[root@Docker RuoYi-Vue]# source /etc/profile[root@Docker RuoYi-Vue]# java -versionjava version "17.0.12" 2024-07-16 LTS✅️ 可以参考下面maven环境变量的添加方式Maven打包

- Download Apache Maven
- 官方下载地址👆
1)上传解压[root@Docker RuoYi-Vue]# ls /tmp/apache-maven-3.9.15-bin.tar.gz/tmp/apache-maven-3.9.15-bin.tar.gz[root@Docker RuoYi-Vue]# tar xvf /tmp/apache-maven-3.9.15-bin.tar.gz -C /usr/local/
2)配置环境变量[root@Docker RuoYi-Vue]# ls /usr/local/apache-maven-3.9.15/bin boot conf lib LICENSE NOTICE README.txt[root@Docker RuoYi-Vue]# vim /etc/profile.d/maven.sh# 放在这个目录下,每次重新打开新的终端窗口,会被自动 source 一次export MAVEN_HOME=/usr/local/apache-maven-3.9.15export PATH=$PATH:$MAVEN_HOME/bin[root@Docker RuoYi-Vue]# mvn -v-bash: mvn: command not found[root@Docker RuoYi-Vue]# source /etc/profile.d/maven.sh[root@Docker RuoYi-Vue]# mvn -vApache Maven 3.9.15Maven home: /usr/local/apache-maven-3.9.15Java version: 17.0.12/usr/local/jdk-17.0.12
3)打包编译# 在ruoyi项目的bin目录下执行package.bat打包Web工程# 生成war/jar包文件".bat脚本 用于在 Windows 操作系统中运行"# 我们是Linux操作系统[root@Docker RuoYi-Vue]# cat ./bin/package.bat@echo offecho xxx.....cd ..call mvn clean package -Dmaven.test.skip=true# 本质就是这条命令👆[root@Docker RuoYi-Vue]# mvn clean package -Dmaven.test.skip=true[INFO] --------------------[INFO] Reactor Summary for ruoyi 3.9.2:[INFO][INFO] ruoyi ............. SUCCESS [ 0.185 s][INFO] ruoyi-common ...... SUCCESS [ 10.544 s][INFO] ruoyi-system ...... SUCCESS [ 0.676 s][INFO] ruoyi-framework ... SUCCESS [ 9.742 s][INFO] ruoyi-quartz ...... SUCCESS [ 1.705 s][INFO] ruoyi-generator ... SUCCESS [ 1.354 s][INFO] ruoyi-admin ....... SUCCESS [ 11.936 s][INFO] -------------------[INFO] BUILD SUCCESS[INFO] -------------------[INFO] Total time: 36.503 s[INFO] Finished at: 2026-05-06T15:50:13+08:00'都成功了'[root@Docker RuoYi-Vue]# ls ruoyi-admin/target/classes maven-archiver ruoyi-admin.jargenerated-sources maven-status ruoyi-admin.jar.original✅️ '打包为jar包'
4)后台启动[root@Docker RuoYi-Vue]# java -jar ruoyi-admin/target/ruoyi-admin.jar(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ .-------. ____ __ | _ _ \ \ \ / / | ( ' ) | \ _. / ' |(_ o _) / _( )_ .' ' | (_,_).' __ ___(_ o _)' | |\ \ | || |(_,_)' ' | | \ `' /| `-' / | | \ / \ / ''-' `'-' `-..-'✅️ "成功启动"# 后台运行成功!
前端部署

1)下载node.js并解压[root@Docker RuoYi-Vue]# ls /tmp/node-v24.15.0-linux-x64.tar.xz/tmp/node-v24.15.0-linux-x64.tar.xz[root@Docker RuoYi-Vue]# tar xf /tmp/node-v24.15.0-linux-x64.tar.xz -C /usr/local/
2)环境变量[root@Docker RuoYi-Vue]# ls /usr/local/node-v24.15.0-linux-x64/bin CHANGELOG.md include lib# 我们依旧单独写一个脚本[root@Docker RuoYi-Vue]# vim /etc/profile.d/nodejs.sh#!/bin/bashexport NODEJS_HOME=/usr/local/node-v24.15.0-linux-x64export PATH=$PATH:$NODEJS_HOME/bin[root@Docker RuoYi-Vue]# node -v-bash: node: command not found[root@Docker RuoYi-Vue]# source /etc/profile.d/nodejs.sh[root@Docker RuoYi-Vue]# node -vv24.15.0
3)安装依赖并运行"前台服务"[root@Docker RuoYi-Vue]# cd ruoyi-ui/[root@Docker ruoyi-ui]# npm install --registry=https://registry.npmmirror.com[root@Docker ruoyi-ui]# echo $?0# 运行成功[root@Docker ruoyi-ui]# npm run dev# 启动项目App running at: - Network: http://10.0.0.99:80/ 访问webUI👆
乱码问题

"数据库字符集有问题!"[root@Docker ~]# docker exec -it mysql-server /bin/bashbash-4.4# mysqlWelcome to the MySQL monitor.mysql> SHOW VARIABLES LIKE 'character_set_server';+----------------------+---------+| Variable_name | Value |+----------------------+---------+| character_set_server | utf8mb4 |+----------------------+---------+1 row in set (0.01 sec)✅️ 服务端默认就是它 --> utf8mb4mysql> SHOW VARIABLES LIKE 'character%';+--------------------------+-------------+| Variable_name | Value |+--------------------------+-------------+| character_set_client | latin1 ❌️ || character_set_connection | latin1 ❌️ || character_set_results | latin1 ❌️ |............xxxxxx"主要就是这三个"mysql> SET NAMES utf8mb4;+--------------------------+--------| Variable_name | Value+--------------------------+--------| character_set_client | utf8mb4| character_set_connection | utf8mb4| character_set_results | utf8mb4'一键给这3个直接改过来'⚠️ 上面是临时修改,不是永久性的bash-4.4# egrep -v "^#|^$" /etc/my.cnf[mysqld]skip-host-cacheskip-name-resolvedatadir=/var/lib/mysqlsocket=/var/run/mysqld/mysqld.socksecure-file-priv=/var/lib/mysql-filesuser=mysqlpid-file=/var/run/mysqld/mysqld.pidcharacter-set-server = utf8mb4collation-server = utf8mb4_unicode_ci
[mysql]default-character-set = utf8mb4
[client]socket=/var/run/mysqld/mysqld.sockdefault-character-set = utf8mb4
!includedir /etc/mysql/conf.d/
# 以cat > /etc/my.cnf <<EOF 追加的方式永久修改 ✅️bash-4.4# exitexit[root@Docker ~]# docker restart mysql-server[root@Docker ~]# docker exec -it mysql-server /bin/bashbash-4.4# mysqlWelcome to the MySQL monitor.mysql> SHOW VARIABLES LIKE 'character%';✅️ 重启容器后,依旧生效!
- 但我打开后 —> ==还是乱码==
- 因为已经写到了数据库中
✅️ 删除数据库 --> 重新导入数据[root@Docker ~]# docker exec -it mysql-server /bin/bashbash-4.4# mysqlWelcome to the MySQL monitormysql> DROP DATABASE ry-vue;'-vue' at line 1# 因为中间有 -杠 得用反引号包裹起来mysql> DROP DATABASE `ry-vue`;Query OKmysql> CREATE DATABASE `ry-vue`;Query OKmysql> exitByebash-4.4# mysql ry-vue < /sql/quartz.sqlbash-4.4# mysql ry-vue < /sql/ry_20260417.sqlmysql> SHOW GRANTS FOR 'jiu'@'%';+-------------------------------------------------+| Grants for jiu@% |+-------------------------------------------------+| GRANT USAGE ON *.* TO `jiu`@`%` || GRANT ALL PRIVILEGES ON `ry-vue`.* TO `jiu`@`%` |+-------------------------------------------------+# 用户jiu依旧对 `ry-vue` 表拥有权限
🌰 分别启动前后端[root@Docker ~]# cd RuoYi-Vue/[root@Docker RuoYi-Vue]# java -jar ruoyi-admin/target/ruoyi-admin.jar'上面是后端,下面是运行前端'# 分别用两个终端进行启动[root@Docker ~]# cd RuoYi-Vue/[root@Docker RuoYi-Vue]# cd ruoyi-ui/[root@Docker ruoyi-ui]# npm run dev
项目容器化
后端
MySQL,和Redis它们都有对应的容器流程步骤: 1.修改配置文件(MySQL,Redis数据指向) 2.Maven重新打包 3.手动测试运行jar包 # 配置JDK,拷贝jar包1)修改mysql地址指向[root@Docker RuoYi-Vue]# vim ./ruoyi-admin/src/main/resources/application-druid.yml# 主库数据源 master: url: jdbc:mysql://mysql-server:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: jiu password: oldboy123.com'后面改为容器名(域名) --> mysql-server'# 原来是localhost
2)Redis地址指向[root@Docker RuoYi-Vue]# vim ./ruoyi-admin/src/main/resources/application.yml # redis 配置 redis: # 地址 host: redis-server # 端口,默认为6379 port: 6379'主机改为redis-server'
3)重新打jar包'打包之前先清理一下环境'[root@Docker RuoYi-Vue]# ls ruoyi-admin/target/classes maven-archiver ruoyi-admin.jargenerated-sources maven-status ruoyi-admin.jar.original'现在是有jar包的'[root@Docker RuoYi-Vue]# cat ./bin/clean.bat@echo offxxxx.......cd ..call mvn clean 👆这个[root@Docker RuoYi-Vue]# mvn clean[root@Docker RuoYi-Vue]# ls ruoyi-admin/target/ls: cannot access 'ruoyi-admin/target/': No such file or directory[root@Docker RuoYi-Vue]# mvn clean package -Dmaven.test.skip=true# 重新打包[INFO] ruoyi .................. SUCCESS[INFO] ruoyi-common ........... SUCCESS[INFO] ruoyi-system ........... SUCCESS[INFO] ruoyi-framework ........ SUCCESS[INFO] ruoyi-quartz ........... SUCCESS[INFO] ruoyi-generator ........ SUCCESS[INFO] ruoyi-admin ............ SUCCESS[INFO] -----------------------------[INFO] BUILD SUCCESS[root@Docker RuoYi-Vue]# cp ruoyi-admin/target/ruoyi-admin.jar /root# 把它移动到/root目录下!jdk部署
| 版本 | 发布时间 | 状态 | 说明 |
|---|---|---|---|
| JDK 8 | 2014-03 | LTS(长期支持) | 老但仍在用 |
| JDK 11 | 2018-09 | LTS | ✅️ 企业主流之一 |
| JDK 17 | 2021-09 | LTS | ✅️ 当前最广泛使用的 LTS |
| JDK 21 | 2023-09 | LTS | ✅ 最新 LTS(2023年9月发布) |
| JDK 22 | 2024-03 | GA(正式版) | 最新正式版 |
| JDK 23 | 2024-09 | GA(2024-09-17 刚发布) | 当前最新正式版 |
- 标签说明:
21/17/11为 Java LTS 版本 jre表示仅运行时(无编译器),jdk含编译器与调试工具
- 在书写Dockerfile之前, 先手动跑容器把它部署起来
- 生产运行 JAR 包(RHEL 9)
- eclipse-temurin:21-jre-ubi9-minimal
- 本来想用ubuntu的,但是没有找到❌️
jre—> 只有运行环境(无编译器)ubi9—> RHEL 9minimal—> 最小化安装
- 轻量运行 JAR 包(Alpine)
- eclipse-temurin:21-jre-alpine-3.22
- 生产运行 JAR 包(RHEL 9)
OpenJDK 全指南:替代方案、实操步骤与最佳实践-阿里云开发者社区
- 参考👆的文档
# 关于基础镜像的选择刚开始想着用 openjdk,但是官方已经弃用了!"Eclipse Temurin --> 构建OpenJDK二进制文件官方镜像" ✅️ 适用于开发、测试及生产环境 ✅️ 确保良好的兼容性与稳定性 ✅️ 是企业级应用开发的可靠选择1)基础镜像拉取[root@Docker ~]# docker pull docker.xuanyuan.run/eclipse-temurin:21-jre-ubi9-minimal# 当然你也可以用上面的21-jre-alpine-3.22标签🏷️[root@Docker ~]# docker imageseclipse-temurin:21-jre-ubi9-minimal
2)运行 & 拷贝jar包[root@Docker ~]# docker run -d --name c1 eclipse-temurin:21-jre-ubi9-minimal tail -f /etc/hosts'先给它阻塞住'[root@Docker ~]# lsruoyi-admin.jar RuoYi-Vue[root@Docker ~]# docker cp ruoyi-admin.jar c1:/homeSuccessfully copied 89.7MB (transferred 89.7MB) to c1:/tmp
2)试运行[root@Docker RuoYi-Vue]# docker exec mysql-server tail -1 /etc/hosts172.17.0.2 b96869f20e32[root@Docker RuoYi-Vue]# docker exec redis-server tail -1 /etc/hosts172.17.0.3 1daf7a9a3ff3'因为我们配置文件中写的是 mysql-server 和 redis-server'[root@b5c4c899d58a /]# cat >> /etc/hosts <<EOF172.17.0.2 mysql-server172.17.0.3 redis-serverEOF[root@b5c4c899d58a /]# java -jar /home/ruoyi-admin.jar(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ .-------. ____ __ | _ _ \ \ \ / / | ( ' ) | \ _. / ' |(_ o _) / _( )_ .' ' | (_,_).' __ ___(_ o _)' | |\ \ | || |(_,_)' ' | | \ `' /| `-' / | | \ / \ / ''-' `'-' `-..-'
✅️ 后端启动成功可以优化的点: 1.可以指定物理机路径挂载 --> 不用手动COPY至容器内了 # -v /myapp.jar:/app.jar:rw 2.使用自建网络 --> 不用手动映射域名 3.自定义启动命令 --> java -jar /app.jar # 自动阻塞,放在前台运行Vue & Node.js
先搞清楚你的位置
你现在的知识:
- HTML(结构)、CSS(样式)、JS(交互)— 浏览器直接认识的三件套
- Nginx(反向代理、静态文件托管)
- 运维思维(服务怎么跑、怎么部署)
现在突然冒出来 Vue 和 Node.js,感觉凭空多了两个”层”
下面从根源讲起
Vue
为什么需要 Vue?原生 JS 哪里不够用?
以前的写法(你熟悉的)
<div id="counter"> <span id="count">0</span> <button onclick="add()">+1</button></div>
<script> let n = 0; function add() { n++; document.getElementById('count').innerText = n; // 手动更新 DOM }</script>一个计数器,十几行代码,还行。
页面复杂以后…
假设你要做一个后台管理面板:
- 侧边栏菜单(展开/折叠)
- 表格(排序、分页、搜索)
- 弹窗(新增/编辑用户)
- 登录状态(未登录跳转)
- 权限控制(管理员看到不同菜单)
- 多个页面切换(列表页 → 详情页 → 编辑页)
用原生 JS 写:
手动操作 DOM:document.getElementById、innerHTML、appendChild...数据和页面不同步:数据变了,你得记住去更新页面上"所有相关"的地方====================代码组织混乱:一个 script.js 几千行,变量满天飞核心矛盾:数据变了,你得手动把页面上所有用到这个数据的地方全部更新一遍
漏一个地方就出 bug
==Vue 解决的就是这个问题==
Vue 是一个前端框架
它的核心思想:
你只管改数据,页面自动跟着变
上面的计数器用 Vue 写:
<template> <div> <span>{{ count }}</span> <!-- 自动绑定,count 变了这里自动更新 --> <button @click="add">+1</button> </div></template>
<script setup> import { ref } from 'vue'; const count = ref(0); function add() { count.value++; } // 只改数据,不管 DOM</script>你发现区别了吗?
没有 document.getElementById,没有 innerText
你只改了 count.value,页面上所有用到 count 的地方自动刷新
Vue 还解决了第二个问题:==组件化==
一个页面拆成独立组件,每个组件管自己那一摊:
App.vue(整体布局)├── Sidebar.vue ← 侧边栏,里面有自己的展开/折叠逻辑├── Header.vue ← 顶栏,里面有用户头像、退出按钮├── UserTable.vue ← 表格,里面有排序、分页逻辑│ └── UserRow.vue ← 每一行└── Modal.vue ← 弹窗,通用组件到处复用-
每个
.vue文件包含自己的 HTML + CSS + JS,互不干扰 -
就跟 Nginx 配多个
server块一样,各管各的
==小结==:Vue 解决什么?
| 原生 JS 的痛点 | Vue 的方案 |
|---|---|
| 手动操作 DOM,容易漏 | 响应式: 改数据,页面自动更新 |
| 代码堆在一个文件,难以维护 | 组件化: 拆成小块,每个管自己 |
| 页面切换要自己写路由逻辑 | Vue Router: 自动管理页面切换 |
| 数据在页面间传递混乱 | 状态管理(Pinia): 集中管理共享数据 |
Vue = 让你用更少、更清晰的代码,写出更复杂的页面
Node.js
那 Node.js 是干嘛的?
你可能会问:“我用原生 JS 从来没有 Node.js,为什么用 Vue 就多出来一个 Node.js”
答案很简单: ==浏览器只认识三样东西:HTML、CSS、JS==
你写的 .vue 文件长这样:
<template>...</template> ← 这既不是 HTML,也不是 JS<script setup>...</script> ← 这段 JS 里有 import 语句,浏览器不认识<style scoped>...</style> ← 这段 CSS 浏览器也不直接认识浏览器拿到 .vue 文件 = 完全看不懂
所以需要一个”翻译工”
Node.js 就是这个翻译工
Node.js 本质是什么?
Node.js = 把 Chrome 浏览器的 JS 引擎(V8)单独拆出来,让你在服务器/本机也能跑 JS
浏览器里的 JS:能操作网页,但不能读写你电脑上的文件 Node.js 里的 JS:==能读写文件==、==启动网络服务==、==执行命令行==——因为它跑在操作系统上,不跑在浏览器里
在前端项目里,Node.js 是编译工具,不是服务
你写的源码 Node.js(运行 Vite) 浏览器看到的────────── ─"编译"→ ────────────────── ─"返回"→ ────────App.vue 解析 .vue → 拆成三部分 index.htmlcomponents/Header.vue 打包所有 JS → 一个 app.js app.js(纯 JS)style.css PostCSS 处理 → 加浏览器前缀 style.css(处理好的)article.md markdown-it → 转成 HTML 内嵌在 JS 里的 HTMLNode.js 在这里的角色 = 编译流水线
==它把源码加工成浏览器能吃的静态文件,仅此而已==
为什么开发时要一直开着?
npm run dev → Node.js 启动 Vite → 监听文件变化 ↓ 你改了 App.vue → Vite 检测到 → 重新编译 → 通过 WebSocket 推给浏览器 ↓ 浏览器只更新变动的组件,不刷新页面(HMR 热更新)开着它是为了边改边看
开发 vs 生产
"开发时:" npm run dev → Node.js + Vite 开发服务器(localhost:5175) - 编译 .vue 文件 - 热更新 - 只用于开发,性能差,绝不能对外暴露=============================================="生产时:" npm run build → Node.js 跑一次编译 → 生成 dist/ 静态文件夹 ↓ 之后 Node.js 退出,不再需要 ✅️ ↓ Nginx 托管 dist/ → 返回 HTML/CSS/JS → 用户浏览器 + 反向代理 /api/* 到后端(Java/Go)部署后,没有 Node.js 进程,只有 Nginx + 一堆静态文件
这一点经常被误解
很多运维看到项目里有 Node.js,以为部署时也要装 Node.js 跑服务——不需要❌️
npm run build 之后那堆 dist/ 文件,跟你以前丢到 Nginx html/ 目录下的 index.html、style.css、script.js 本质上是一回事
完整的请求链路
用户浏览器 │ ├── 请求 index.html → Nginx → dist/index.html │ ↓ │ <!DOCTYPE html> │ <script src="/assets/app.js"> ← 浏览器再请求这个 JS │ ├── 请求 /assets/app.js → Nginx → dist/assets/app.js │ ↓ │ 里面就是 Vue 编译后的纯 JS │ 浏览器拿到后执行,页面就出来了 │ └── 请求 /api/users → Nginx → proxy_pass → 后端(Go/Python/Java) ↓ 返回 JSON 数据跟以前纯 HTML 时代的区别只有一个:以前 app.js 你手写的;现在 app.js 是 Vue 源码编译出来的
打个比方总结
Vue 源码 = 面粉(浏览器吃不了)Node.js = 烤箱(只参与加工)Vite = 烤箱的控制面板(调温度、定时)npm run dev = 开着烤箱门,边烤边尝(热更新)npm run build = 一次性烤好(生成 dist/)dist/ = 烤好的面包(纯 HTML/CSS/JS)Nginx = 服务员端给顾客(浏览器)后端 API = 厨房(提供数据)
"开发时":烤箱开着,你边改配方边尝味道"上线后":面包早就烤好了,服务员直接端,烤箱早就关了node.js容器
[root@Docker ~]# docker pull docker.xuanyuan.run/library/node:24.10.0;# 改了一个标签[root@Docker ~]# docker imagesnode:24.10.0 06e54ecf113a 1.63GB[root@Docker ~]# docker run -d -it -p 80:80 --name c2 node:24.10.0'映射了一下端口,方便我们后面浏览器访问它'[root@Docker ~]# docker ps -lc56a40e88634 node:24.10.0 "docker-entrypoint.s…" 4 seconds ago Up 3 seconds[root@Docker ~]# docker cp ~/RuoYi-Vue/ruoyi-ui c2:/Successfully copied 198MB (transferred 226MB) to c2:/'把前端页面都拷贝过去'[root@Docker ~]# docker exec -it c2 /bin/bashroot@c56a40e88634:/# ls /ruoyi-ui/README.md babel.config.js bin build node_modules package-lock.json package.json public src vue.config.js'我们之前nmp install下载了一些依赖'# node_modules/目录 和 package-lock.json文件root@c56a40e88634:/# rm -rf /ruoyi-ui/node_modules/ /ruoyi-ui/package-lock.json'把它们都删除了 <-- 也可以不删除'root@c56a40e88634:/# cd /ruoyi-ui/✅️ 更改一下后端接口(java)root@c56a40e88634:/ruoyi-ui# grep -r localhost:8080 /ruoyi-ui....xxxx/ruoyi-ui/vue.config.js:const baseUrl = 'http://localhost:8080' // 后端接口# 用grep过滤出更改后端接口的配置文件root@c56a40e88634:/ruoyi-ui# sed -i "s#localhost:8080#c1:8080#g" /ruoyi-ui/vue.config.js'我们后端容器(运行jar包)为c1容器'root@c56a40e88634:/ruoyi-ui# echo 172.17.0.2 c1 >> /etc/hostsroot@c56a40e88634:/ruoyi-ui# tail -1 /etc/hosts172.17.0.2 c1root@c56a40e88634:/ruoyi-ui# npm install --registry=https://registry.npmmirror.com# 下载nmp依赖root@c56a40e88634:/ruoyi-ui# npm run dev# 启动前端项目App running at: - Local: http://localhost:80/✅️ 最后也是能够成功访问到了'有验证码,没有接口报错'
nginx容器

- 我们这次直接模拟生产环境
npm run build → Node.js 跑一次编译 → 生成 dist/ 静态文件夹
1)打包build[root@Docker ~]# cd RuoYi-Vue/ruoyi-ui/'容器外的代码'# 里面的接口地址,数据啥的都没有改变[root@Docker ruoyi-ui]# lsbabel.config.js bin build node_modules package.json ...[root@Docker ruoyi-ui]# npm run build:prod# 打包正式环境[root@Docker ruoyi-ui]# ls ./dist/favicon.ico html index.html index.html.gz robots.txt static styles'所有的静态文件都在这里面了'# 在前端构建过程中,会自动生成 gzip 压缩版本的静态资源文件✅️ 提高网络传输效率
2)停止node.js & 运行nginx容器[root@Docker ruoyi-ui]# docker stop c2[root@Docker ruoyi-ui]# docker run -d --name c3 -p 80:80 nginx:latest[root@Docker ruoyi-ui]# docker exec -it c3 /bin/bash# 修改/etc/nginx/conf.d子配置文件即可root@dca1989d9174:~# cd /etc/nginx/conf.d/root@dca1989d9174:/etc/nginx/conf.d# > default.confroot@dca1989d9174:/etc/nginx/conf.d# cat default.conf'提前写到宿主机中, 然后COPY过来'[root@Docker ~]# docker cp default.conf c3:/etc/nginx/conf.d/Successfully copied ... to c3:/etc/nginx/conf.d/server { listen 80; server_name localhost; charset utf-8;
location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; index index.html; }
location /prod-api/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_pass http://localhost:8080/; proxy_pass http://c1:8080/; # c1运行着后端程序 }
# springdoc proxy location ~ ^/v3/api-docs/(.*) { # proxy_pass http://localhost:8080/v3/api-docs/$1; proxy_pass http://c1:8080/v3/api-docs/$1; # 同上 }
error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }}root@dca1989d9174:/etc/nginx/conf.d# echo 172.17.0.2 c1 >> /etc/hostsroot@dca1989d9174:/etc/nginx/conf.d# nginx -tnginx: the configuration file ... is oknginx: configuration file ... is successfulroot@dca1989d9174:/etc/nginx/conf.d# ls /usr/share/nginx/html/50x.html index.html'还没拷贝前端代码文件'[root@Docker ~]# ls ~/RuoYi-Vue/ruoyi-ui/dist/favicon.ico html index.html index.html.gz robots.txt static styles[root@Docker ~]# docker cp ~/RuoYi-Vue/ruoyi-ui/dist/ c3:/usr/share/nginx/html/Successfully ... to c3:/usr/share/nginx/html/root@dca1989d9174:/etc/nginx/conf.d# ls /usr/share/nginx/html/50x.html dist index.html'多个dist目录'# 把目录里面的东西全部拿出来root@dca1989d9174:/etc/nginx/conf.d# cp -r /usr/share/nginx/html/dist/* /usr/share/nginx/html/root@dca1989d9174:/etc/nginx/conf.d# rm -rf /usr/share/nginx/html/dist/root@dca1989d9174:/etc/nginx/conf.d# cd /usr/share/nginx/html/root@dca1989d9174:/usr/share/nginx/html# ls -lhtotal 40K-rw-r--r-- 1 root root 497 Apr 7 11:37 50x.html-rw-r--r-- 1 root root 5.6K May 8 07:48 favicon.icodrwxr-xr-x 2 root root 39 May 8 07:48 html-rw-r--r-- 1 root root 13K May 8 07:48 index.html-rw-r--r-- 1 root root 4.2K May 8 07:48 index.html.gz-rw-r--r-- 1 root root 26 May 8 07:48 robots.txtdrwxr-xr-x 6 root root 51 May 8 07:48 staticdrwxr-xr-x 3 root root 25 May 8 07:48 styles'权限有问题 ❌️'root@dca1989d9174:/usr/share/nginx/html# chown -R nginx:nginx ../html/# 都改为nginx用户[root@Docker ~]# docker psnginx:latest Up [::]:80->80/tcp c3eclipse-temurin:21-jre-ubi9-minimal Up c1redis:7.2.8 Up [::]:6379->6379/tcp redis-servermysql:8.0.36 Up [::]:3306->3306/tcp mysql-server'node.js容器并没有运行'
✅️ 通过nginx依旧可以访问
Dockerfile书写
[root@Docker ~]# mkdir RuoYi-compose && cd RuoYi-compose[root@Docker RuoYi-compose]# mkdir {conf,dockerfile,data}[root@Docker RuoYi-compose]# tree ././├── conf├── data└── dockerfile数据库
1)准备sql文件[root@Docker RuoYi-compose]# cd /root/RuoYi-Vue/sql/[root@Docker sql]# lsquartz.sql ry_20260417.sql[root@Docker sql]# cp ./* /root/RuoYi-compose/data/[root@Docker sql]# cd -/root/RuoYi-compose[root@Docker RuoYi-compose]# ls data/quartz.sql ry_20260417.sql
2)以防字符乱码my.cnf[root@Docker RuoYi-compose]# docker exec -it mysql-server /bin/bashbash-4.4# cat /etc/my.cnf[mysqld]skip-host-cacheskip-name-resolvedatadir=/var/lib/mysqlsocket=/var/run/mysqld/mysqld.socksecure-file-priv=/var/lib/mysql-filesuser=mysqlpid-file=/var/run/mysqld/mysqld.pidcharacter-set-server = utf8mb4collation-server = utf8mb4_unicode_ci
[mysql]default-character-set = utf8mb4
[client]socket=/var/run/mysqld/mysqld.sockdefault-character-set = utf8mb4
!includedir /etc/mysql/conf.d/bash-4.4# exitexit[root@Docker RuoYi-compose]# docker cp mysql-server:/etc/my.cnf ./conf/Successfully copied ... to /root/RuoYi-compose/conf/[root@Docker RuoYi-compose]# ls ./conf/my.cnf
3)docker-entrypoint-initdb.d目录✅️ 是 MySQL Docker 官方镜像的一个特殊目录 1.存放数据库初始化时要执行的脚本或sql语句 2.只有在首次初始化数据库时才会执行'把sql语句放在这个目录中'- 因为本身MySQL镜像里面的环境变量、启动命令…就够用了
- 这里的Dockerfile只是为了解决乱码和sql脚本导入
- vim ./dockerfile/mysql-1.0
- 太多COPY —> 后期考虑写shell脚本
- 这里的Dockerfile只是为了解决乱码和sql脚本导入
FROM mysql:8.0.36LABEL maintainer="jiuzhao"EXPOSE 3306COPY ./conf/my.cnf /etc/my.cnfCOPY ./data/quartz.sql /docker-entrypoint-initdb.d/COPY ./data/ry_20260417.sql /docker-entrypoint-initdb.d/4)镜像构建[root@Docker RuoYi-compose]# docker build -f ./dockerfile/mysql-1.0 -t ruoyi-mysql:1.0 .[+] Building 0.6s (8/8) FINISHED'还是很顺利的'
5)清理环境 & 创建网络[root@Docker RuoYi-compose]# docker rm -f $(docker ps -aq)[root@Docker RuoYi-compose]# docker network prune -f[root@Docker RuoYi-compose]# docker volume prune -fa[root@Docker RuoYi-compose]# docker network create -d bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet[root@Docker RuoYi-compose]# docker network ls | grep mynet691fc0a12189 mynet bridge local
6)测试验证[root@Docker RuoYi-compose]# docker container run \ -e MYSQL_ALLOW_EMPTY_PASSWORD="yes" \ -d \ --net mynet \ --name mysql-server \ -e MYSQL_DATABASE="ry-vue" \ -e MYSQL_USER="jiu" \ -e MYSQL_PASSWORD="oldboy123.com" \ ruoyi-mysql:1.0 \ --character-set-server=utf8mb4 \ --collation-server=utf8mb4_unicode_ci \ --default-authentication-plugin=mysql_native_password# 没有暴漏端口 & 用的自己的镜像[root@Docker RuoYi-compose]# docker exec -it mysql-server /bin/bashbash-4.4# mysqlWelcome to the MySQL monitor.mysql> use ry-vue;Database changed
'数据库中有对应的数据!'mysql> show tables;+--------------------------+| Tables_in_ry-vue |+--------------------------+| QRTZ_BLOB_TRIGGERS || QRTZ_CALENDARS || QRTZ_CRON_TRIGGERS |
mysql> SHOW VARIABLES LIKE 'character%';mysql> SET NAMES utf8mb4;+--------------------------+--------| Variable_name | Value+--------------------------+--------| character_set_client | utf8mb4 ✅️| character_set_connection | utf8mb4 ✅️| character_set_results | utf8mb4 ✅️'字符集也是对的'
7)Redis数据库# 不需要书写对应的Dockerfile,直接跑起容器就可以了[root@Docker RuoYi-compose]# docker container run -d \ --name redis-server \ --net mynet \ redis:7.2.8# 隐藏端口[root@Docker RuoYi-compose]# docker psredis:7.2.8 "docker-entrypoint.s…" UP redis-server后端
"ruoyi-server"
1)清理与检查[root@Docker RuoYi-compose]# cd /root/RuoYi-Vue/[root@Docker RuoYi-Vue]# mvn clean# 清理target目录# 删除编译后的类文件、打包的 JAR/WAR 文件⚠️ mave打包为jar包之前,需要先检查相应配置# mysql和redis的地址指向[root@Docker RuoYi-Vue]# grep "mysql-server" /root/RuoYi-Vue/ruoyi-admin/src/main/resources/application-druid.yml url: jdbc:mysql://mysql-server:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8[root@Docker RuoYi-Vue]# grep "redis-server" /root/RuoYi-Vue/ruoyi-admin/src/main/resources/application.yml host: redis-server
2)打为jar包[root@Docker RuoYi-Vue]# ls ruoyi-admin/target/ls: cannot access 'ruoyi-admin/target/': No such file or directory[root@Docker RuoYi-Vue]# mvn clean package -Dmaven.test.skip=true[root@Docker RuoYi-Vue]# ls ruoyi-admin/target/ruoyi-admin.jarruoyi-admin/target/ruoyi-admin.jar[root@Docker RuoYi-Vue]# mv ruoyi-admin/target/ruoyi-admin.jar /root/RuoYi-compose/data/[root@Docker RuoYi-Vue]# cd -/root/RuoYi-compose[root@Docker RuoYi-compose]# ls ./data/ruoyi-admin.jar./data/ruoyi-admin.jar
3)编写Dockerfile文件[root@Docker RuoYi-compose]# vim ./dockerfile/jre-1.0FROM eclipse-temurin:21-jre-ubi9-minimalLABEL maintainer="jiuzhao"EXPOSE 8080COPY ./data/ruoyi-admin.jar /CMD ["java", "-jar", "/ruoyi-admin.jar"]4)构建镜像[root@Docker RuoYi-compose]# docker build -f ./dockerfile/jre-1.0 -t ruoyi-backend:1.0 .[+] Building 4.7s (7/7) FINISHED[root@Docker RuoYi-compose]# docker imagesruoyi-backend:1.0 2eead08a0bbf 603MB
5)运行测试[root@Docker RuoYi-compose]# docker run -d --net mynet --name ruoyi-server ruoyi-backend:1.0[root@Docker RuoYi-compose]# docker ps -l17133f983cb0 ruoyi-backend:1.0 "/__cacert_entrypoin…" 4 seconds ago Up 3 seconds 8080/tcp ruoyi-server[root@Docker RuoYi-compose]# docker logs ruoyi-server(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ .-------. ____ __ | _ _ \ \ \ / / | ( ' ) | \ _. / ' |(_ o _) / _( )_ .' ' | (_,_).' __ ___(_ o _)' | |\ \ | || |(_,_)' ' | | \ `' /| `-' / | | \ / \ / ''-' `'-' `-..-'前端
"ruoyi-ui"
1)拷贝dist目录下的资源[root@Docker RuoYi-compose]# cp -r /root/RuoYi-Vue/ruoyi-ui/dist/ ./data/[root@Docker RuoYi-compose]# ls -d ./data/dist/./data/dist/# 把整个dist拷贝过来了
2)Nginx配置文件[root@Docker RuoYi-compose]# vim ./conf/default.confserver { listen 80; server_name localhost; charset utf-8;
location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; index index.html; }
location /prod-api/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://ruoyi-server:8080/; # 后端容器的名字 }
# springdoc proxy location ~ ^/v3/api-docs/(.*) { proxy_pass http://ruoyi-server:8080/v3/api-docs/$1; # 同上 }
error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; }}
3)编写Dockerfilefile[root@Docker RuoYi-compose]# vim ./dockerfile/nginx-1.0FROM nginx:latestLABEL maintainer="jiuzhao"EXPOSE 80COPY ./conf/default.conf /etc/nginx/conf.d/COPY ./data/dist /usr/share/nginx/htmlRUN chown -R nginx:nginx /usr/share/nginx/html4)构建镜像[root@Docker RuoYi-compose]# docker build -f ./dockerfile/nginx-1.0 -t ruoyi-frontend:1.0 .[+] Building 1.5s (9/9) FINISHED[root@Docker RuoYi-compose]# docker imagesruoyi-frontend:1.0 becfb6f20726 257MB
5)测试运行[root@Docker RuoYi-compose]# docker run -d --name ruoyi-ui --net mynet -p 80:80 ruoyi-frontend:1.0'这个得映射端口'[root@Docker RuoYi-compose]# docker logs ruoyi-ui2026/05/08 11:30:16 [notice] 1#1: nginx/1.29.82026/05/08 11:30:16 [notice] 1#1: built by gcc 14.2.0 (Debian 14.2.0-19)2026/05/08 11:30:16 [notice] 1#1: OS: Linux 6.12.0-124.8.1.el10_1.x86_642026/05/08 11:30:16 [notice] 1#1: start worker processes2026/05/08 11:30:16 [notice] 1#1: start worker process 292026/05/08 11:30:16 [notice] 1#1: start worker process 30'也是启动起来了!'# 浏览器访问http://10.0.0.99
Docker compose编排
services: mysql-server: image: ruoyi-mysql:1.0 container_name: mysql-server healthcheck: test: ["CMD", "mysqladmin", "ping"] interval: 5s timeout: 5s retries: 3 environment: MYSQL_ALLOW_EMPTY_PASSWORD: "yes" MYSQL_DATABASE: "ry-vue" MYSQL_USER: "jiu" MYSQL_PASSWORD: "oldboy123.com" command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"] volumes: - db:/var/lib/mysql:rw networks: - ruoyi # 指定容器的重启策略 restart: unless-stopped
redis-server: image: redis:7.2.8 restart: unless-stopped container_name: redis-server healthcheck: test: ["CMD", "redis-benchmark", "-h","127.0.0.1","-p", "6379","-n", "1", "-c","2"] interval: 5s timeout: 5s retries: 3 networks: - ruoyi
ruoyi-server: image: ruoyi-backend:1.0 restart: unless-stopped container_name: ruoyi-server healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/"] interval: 15s timeout: 15s retries: 3 # 依赖的服务要优先启动 depends_on: mysql-server: condition: service_healthy # MySQL和Redis 健康检查通过才启动 redis-server: condition: service_healthy networks: - ruoyi
ruoyi-ui: image: ruoyi-frontend:1.0 restart: unless-stopped container_name: ruoyi-ui healthcheck: test: ["CMD", "curl", "-f", "http://localhost/"] interval: 15s timeout: 15s retries: 3 depends_on: ruoyi-server: condition: service_healthy ports: - "80:80" networks: - ruoyi
networks: ruoyi: name: ruoyi-net driver: bridge ipam: driver: default config: - subnet: 172.18.0.0/16 gateway: 172.18.0.1
volumes: db: name: mysql-volume健康检查重要性
💡
depends_on默认只等容器启动,不等服务就绪,加healthcheck可以解决启动顺序问题
- ==笨方法== —> 重启策略 —> unless-stopped
[root@Docker RuoYi-compose]# vim docker-compose.yml# 内容如上
1)清理环境[root@Docker RuoYi-compose]# docker rm -f $(docker ps -aq)[root@Docker RuoYi-compose]# docker network prune -f[root@Docker RuoYi-compose]# docker volume prune -fa
2)一键启动[root@Docker RuoYi-compose]# docker compose up -d[+] up 6/6 ✔ Network ruoyi-net Created ✔ Volume mysql-volume Created ✔ Container redis-server Healthy ✔ Container mysql-server Healthy ✔ Container ruoyi-server Healthy ✔ Container ruoyi-ui Started[root@Docker RuoYi-compose]# docker compose lsruoyi-compose running(4) /root/RuoYi-compose/docker-compose.yml[root@Docker RuoYi-compose]# docker compose psruoyi-mysql:1.0 "docker-entrypoint.s…" mysql-server About a minute ago Up About a minute 3306/tcp, 33060/tcpredis:7.2.8 "docker-entrypoint.s…" redis-server About a minute ago Up About a minute 6379/tcpruoyi-backend:1.0 "/__cacert_entrypoin…" ruoyi-server About a minute ago Up 50 second 8080/tcpruoyi-frontend:1.0 "/docker-entrypoint.…" ruoyi-ui About a minute ago Up About a minute [::]:80->80/tcp- 最后也是可以成功访问到 ✅️

文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!



