实战部署:若依(RuoYi-Vue)
将若依前后端分离项目完整部署到 K8s 集群的实操指南,涵盖 Redis、MySQL、后端应用、前端应用、私有镜像仓库和 Ingress。
1. 部署架构概览
┌───────────────────────────────────────────────────────────────┐
│ K8s 集群 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Redis │ │ MySQL │ │ Registry │ │
│ │ (Helm) │ │ (Helm) │ │ (Docker) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ▲ ▲ │
│ │ │ │
│ ┌────┴──────────────┴────┐ │
│ │ RuoYi-Admin │ │
│ │ (Deployment) │ │
│ └──────────┬─────────────┘ │
│ │ │
│ ┌──────────┴─────────────┐ ┌──────────────┐ │
│ │ RuoYi-UI │────▶│ Ingress │──── 外部用户 │
│ │ (Deployment) │ │ (Traefik/K3s)│ │
│ └────────────────────────┘ └──────────────┘ │
└───────────────────────────────────────────────────────────────┘2. 安装 Redis
使用 Helm 部署单节点 Redis 用于开发/测试:
helm install redis \
--set architecture=standalone \
--set auth.password="123456" \
--set master.persistence.enabled=false \
--set master.persistence.medium=Memory \
--set master.persistence.sizeLimit=1Gi \
bitnami/redis \
--kubeconfig=/etc/rancher/k3s/k3s.yaml安装成功后注意记录 Redis 的 DNS 名称(输出中会显示),后续配置后端时需要,格式通常为 redis-master 或 redis.<namespace>.svc.cluster.local。
3. 安装 MySQL
3.1 准备 SQL 初始化脚本
将若依项目的 SQL 文件(ry_2024xxxx.sql 和 quartz.sql)放到一个目录中:
mkdir -p /home/app/sql
cp ry_2024xxxx.sql quartz.sql /home/app/sql/3.2 创建 ConfigMap
# 将整个 SQL 目录创建为 ConfigMap(Helm 会使用它初始化数据库)
kubectl create cm ruoyi-init-sql --from-file=/home/app/sql3.3 编写 values.yaml
# ruoyi-mysql.yaml
auth:
rootPassword: "123456"
database: ry-vue
initdbScriptConfigMap: ruoyi-init-sql
primary:
persistence:
enabled: true
size: 2Gi
secondary:
persistence:
enabled: true
size: 2Gi
replicaCount: 2
architecture: replication3.4 安装
helm install db -f ruoyi-mysql.yaml bitnami/mysql --kubeconfig=/etc/rancher/k3s/k3s.yaml
# 记录主库 DNS
# 输出示例:db-mysql-primary.dev.svc.cluster.local4. 构建后端镜像
4.1 Dockerfile(多阶段构建)
# 阶段 1:编译
FROM maven:3.8-openjdk-8 AS builder
WORKDIR /app/build
COPY . .
RUN mvn clean package
# 阶段 2:打包运行
FROM openjdk:8u342-jre
WORKDIR /app/ruoyi
COPY --from=builder /app/build/ruoyi-admin/target/ruoyi-admin.jar .
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "ruoyi-admin.jar"]4.2 构建与推送
docker build -t ruoyi-admin:v3.8 .
docker tag ruoyi-admin:v3.8 <私有仓库>:5000/ruoyi-admin:v3.8
docker push <私有仓库>:5000/ruoyi-admin:v3.84.3 准备配置文件
将 application.yml 中数据库和 Redis 相关配置提取到 application-k8s.yaml:
# /home/app/conf/application-k8s.yaml
spring:
datasource:
master:
url: jdbc:mysql://db-mysql-primary:3306/ry-vue
username: root
password: "123456"
slave:
url: jdbc:mysql://db-mysql-secondary:3306/ry-vue
username: root
password: "123456"
redis:
host: redis-master
password: "123456"kubectl create cm ruoyi-admin-config --from-file=/home/app/conf/application-k8s.yaml5. 构建前端镜像
5.1 Dockerfile(多阶段构建)
FROM node:14-alpine AS builder
WORKDIR /build/ruoyi-ui
COPY . .
RUN npm install --registry=https://registry.npmmirror.com && npm run build:prod
FROM nginx:1.22
WORKDIR /app/ruoyi-ui
COPY --from=builder /build/ruoyi-ui/dist .
EXPOSE 80
# 自动继承基础镜像的启动命令🚨 注意:
- 推荐使用 Node 14(最新版本可能报错)
- 使用
build:prod打包(不要打包预发布环境,否则部署后报错)- 强烈建议在容器中编译,避免本地环境差异
5.2 构建与推送
docker build -t ruoyi-ui:v3.8 .
docker tag ruoyi-ui:v3.8 <私有仓库>:5000/ruoyi-ui:v3.8
docker push <私有仓库>:5000/ruoyi-ui:v3.86. 部署后端应用
# app/svc-ruoyi-admin.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruoyi-admin
labels:
app: ruoyi-admin
spec:
replicas: 1
selector:
matchLabels:
app: ruoyi-admin
template:
metadata:
labels:
app: ruoyi-admin
spec:
containers:
- name: ruoyi-admin
image: <私有仓库>:5000/ruoyi-admin:v3.8
ports:
- containerPort: 8080
volumeMounts:
- mountPath: /app/ruoyi/config
name: config
args: ["--spring.profiles.active=k8s"]
volumes:
- name: config
configMap:
name: ruoyi-admin-config
---
apiVersion: v1
kind: Service
metadata:
name: ruoyi-admin
spec:
type: ClusterIP
selector:
app: ruoyi-admin
ports:
- port: 8080
targetPort: 8080💡 说明:Spring Boot 会自动在 jar 包所在目录的
config/子目录中查找配置文件。ConfigMap 挂载到/app/ruoyi/config,配合--spring.profiles.active=k8s启动参数,Spring Boot 会加载application-k8s.yaml。
7. 部署前端应用
7.1 Nginx 配置
# /home/app/conf/nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /app/ruoyi-ui;
try_files $uri $uri/ /index.html;
index index.html index.htm;
}
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-admin:8080/;
}
# 避免 actuator 暴露
if ($uri ~ "/actuator") {
return 403;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}kubectl create cm ruoyi-ui-config --from-file=/home/app/conf/nginx.conf7.2 Deployment 和 Service
# app/svc-ruoyi-ui.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ruoyi-ui
labels:
app: ruoyi-ui
spec:
replicas: 1
selector:
matchLabels:
app: ruoyi-ui
template:
metadata:
labels:
app: ruoyi-ui
spec:
initContainers: # 等待后端启动
- name: wait-for-ruoyi-admin
image: nginx:1.22
command:
- sh
- -c
- |
until curl -m 3 ruoyi-admin:8080; do
echo "Waiting for ruoyi-admin...";
sleep 5;
done
containers:
- name: ruoyi-ui
image: <私有仓库>:5000/ruoyi-ui:v3.8
ports:
- containerPort: 80
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: config
volumes:
- name: config
configMap:
name: ruoyi-ui-config
items:
- key: nginx.conf
path: default.conf
---
apiVersion: v1
kind: Service
metadata:
name: ruoyi-ui
spec:
type: NodePort
selector:
app: ruoyi-ui
ports:
- port: 80
targetPort: 80
nodePort: 300808. 配置 Ingress
K3s 内置 Traefik Ingress 控制器,直接创建 Ingress 资源即可:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ruoyi-ingress
annotations:
traefik.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ruoyi-ui
port:
number: 80kubectl apply -f ruoyi-ingress.yaml
kubectl get ingress9. 启动顺序控制
背景:当服务重启时,若 ruoyi-admin 在 MySQL 或 Redis 之前启动,会因数据库连接失败而报错终止。
9.1 使用 Init Container 控制顺序
spec:
initContainers:
- name: wait-for-mysql
image: busybox:1.36
command:
- sh
- -c
- |
until nslookup db-mysql-primary; do
echo "Waiting for MySQL...";
sleep 5;
done
- name: wait-for-redis
image: busybox:1.36
command:
- sh
- -c
- |
until nslookup redis-master; do
echo "Waiting for Redis...";
sleep 3;
done
containers:
- name: ruoyi-admin
# ...💡 最佳实践:在 Init Container 中增加重试上限和超时,避免无限等待。超过阈值后以失败退出,让 Pod 重启重试:
for i in $(seq 1 30); do nslookup db-mysql-primary && exit 0 echo "Attempt $i/30: Waiting for MySQL..." sleep 5 done exit 1
10. 部署验证清单
| 检查项 | 命令 |
|---|---|
| Redis 状态 | kubectl get pod -l app.kubernetes.io/name=redis |
| MySQL 状态 | kubectl get pod -l app.kubernetes.io/name=mysql |
| 后端状态 | kubectl get pod -l app=ruoyi-admin |
| 前端状态 | kubectl get pod -l app=ruoyi-ui |
| 后端日志 | kubectl logs -f deploy/ruoyi-admin |
| 前端日志 | kubectl logs -f deploy/ruoyi-ui |
| Service | kubectl get svc |
| Ingress | kubectl get ingress |
| 访问测试 | curl http://<NodeIP>:30080 或通过 Ingress |
11. 私有镜像仓库配置
11.1 启动简单 Registry
docker run -d -p 5000:5000 --restart always --name registry registry:211.2 配置 insecure registry
Docker 侧(/etc/docker/daemon.json):
{
"insecure-registries": ["<私有仓库IP>:5000"]
}K3s 侧(/etc/rancher/k3s/registries.yaml):
mirrors:
"<私有仓库IP>:5000":
endpoint:
- "http://<私有仓库IP>:5000"重启 K3s:sudo systemctl restart k3s
🚨 多节点集群:每个节点都需要配置。
11.3 在 K8s 中使用私有镜像
# 拉取验证
sudo k3s crictl pull <私有仓库IP>:5000/ruoyi-admin:v3.8