一文吃透:两台 CentOS 上 Spring Boot + Vue3 + MySQL + Redis 的传统/Docker/Compose/K8s 架构对比、脚本示例与最佳实践
·
文章目录
四种部署方式全集对比:传统部署 / Docker / Docker Compose / Kubernetes(含 Redis & MySQL)
场景约束:
两台 CentOS 服务器 —— server01(对外)、server02(数据层);
数据库 MySQL;
缓存 Redis;
项目 Spring Boot + Vue3(前后端分离)。
0) 拓扑与产物
flowchart LR
User((用户)) --> |80/443| Nginx
subgraph server01[server01(对外:Web+API)]
W[Vue3 静态资源 (Nginx)]
A[Spring Boot API]
W -->|/api| A
end
subgraph server02[server02(数据层)]
M[(MySQL 8.0)]
R[(Redis 7.x)]
end
A <--3306--> M
A <--6379--> R
通用构建产物
-
后端:
app-<version>.jar -
前端:
dist/(静态文件) -
运行时统一用环境变量注入:
DB_HOST/DB_USER/DB_PASSREDIS_HOST/REDIS_PORT/REDIS_PASS
Spring Boot(片段,所有方案通用)
spring:
datasource:
url: jdbc:mysql://${DB_HOST:server02}:3306/myapp?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
username: ${DB_USER}
password: ${DB_PASS}
data:
redis:
host: ${REDIS_HOST:server02}
port: ${REDIS_PORT:6379}
password: ${REDIS_PASS:}
timeout: 2000ms
lettuce.pool.max-active: 32
前端(Vite) .env.production
VITE_APP_API_BASE=/api
1) 总览对比(一眼看懂)
| 维度 | 传统部署(systemd+Nginx) | Docker(单容器) | Docker Compose(单机编排) | Kubernetes(集群编排) |
|---|---|---|---|---|
| 抽象层级 | 主机进程 | 镜像→容器 | 多容器应用 | 控制面编排的工作负载 |
| 环境一致性 | 一般 | 好 | 很好 | 最好(声明式期望态) |
| 依赖隔离 | 弱 | 强 | 强 | 最强 |
| 自愈与伸缩 | 基本(systemd) | 基本(重启策略) | 基本(healthcheck/依赖) | 完整(探针、自愈、HPA) |
| 发布/回滚 | 包/软链切换 | 切镜像 tag | 改 yml tag,up -d |
rollout/蓝绿/金丝雀 |
| 编排与网络 | 手工 | 弱 | 中(项目网络/卷) | 强(Service/Ingress/流量治理) |
| 观测集成 | 需自建 | 容器日志标准化 | 同左 | 原生贴合 Prom/Loki 等 |
| 成本/门槛 | 低 | 中 | 中 | 高 |
| 适用规模 | 少量服务/简单上线 | 单服务容器化 | 单机多服务/测试预发 | 多副本/高可靠生产 |
| 适合本场景 | ✔(最快) | ✔ | ✔(推荐) | 可行(较重) |
2) 传统部署(systemd + Nginx)
放置
- server02:安装并运行 MySQL + Redis(建议仅内网开放端口)。
- server01:安装 JDK + Nginx,落地
app.jar与dist/。
Redis(server02,最小配置)
sudo yum -y install epel-release redis
sudo sed -i 's/^# requirepass.*/requirepass redis_secret/' /etc/redis.conf
# 如需远程(内网)访问:设置 bind/防火墙策略;开启持久化
# appendonly yes; maxmemory 与 policy 依内存设置
sudo systemctl enable --now redis
sudo firewall-cmd --permanent --add-port=6379/tcp && sudo firewall-cmd --reload
后端 systemd(server01 /etc/systemd/system/myapp.service)
[Unit]
Description=MyApp Spring Boot
After=network.target
[Service]
WorkingDirectory=/srv/myapp/current/api
Environment=DB_HOST=server02
Environment=DB_USER=myapp_user
Environment=DB_PASS=StrongPass!123
Environment=REDIS_HOST=server02
Environment=REDIS_PORT=6379
Environment=REDIS_PASS=redis_secret
Environment=JAVA_OPTS=-Xms512m -Xmx1024m
ExecStart=/usr/bin/java $JAVA_OPTS -jar app.jar --spring.profiles.active=prod
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
前端 Nginx(server01 /etc/nginx/conf.d/myapp.conf)
server {
listen 80;
server_name your.domain.com;
root /srv/myapp/current/web;
index index.html;
location / { try_files $uri $uri/ /index.html; }
location /api/ {
proxy_pass http://127.0.0.1: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;
}
}
发版/回滚
- 发版:上传新包到
releases/→ 切current软链 →systemctl restart myapp→nginx -s reload。 - 回滚:软链指回旧版本 → 重启服务/重载 Nginx。
优点:最少变动、上手快。
注意:依赖与环境一致性差;需要手工规范。
3) Docker 部署(单容器 + 主机 Nginx)
后端 Dockerfile
FROM maven:3.9-eclipse-temurin-17 as build
WORKDIR /src
COPY . .
RUN mvn -q -DskipTests -Pprod clean package
FROM eclipse-temurin:17-jre
WORKDIR /app
COPY --from=build /src/target/app-*.jar /app/app.jar
ENV SPRING_PROFILES_ACTIVE=prod
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]
运行(server01)
docker run -d --name myapp-api --restart=always \
-e SPRING_PROFILES_ACTIVE=prod \
-e DB_HOST=server02 -e DB_USER=myapp_user -e DB_PASS=StrongPass!123 \
-e REDIS_HOST=server02 -e REDIS_PORT=6379 -e REDIS_PASS=redis_secret \
-p 8080:8080 registry.example.com/myapp/api:1.2.4
前端仍由主机 Nginx托管 dist/(与传统部署同(Nginx 配置复用))。
优点:环境可复制、回滚切 tag、主机更干净。
注意:编排弱,多容器依赖靠脚本/文档维持。
4) Docker Compose(单机多容器编排)(两台机最推荐)
方案
- server02:MySQL + Redis(主机跑或容器跑均可,生产更建议主机/托管)。
- server01:用
docker-compose.yml一次性编排web(Nginx)+ api(Spring Boot)。
docker-compose.yml(server01)
version: "3.9"
services:
api:
image: registry.example.com/myapp/api:1.2.4
container_name: myapp-api
environment:
SPRING_PROFILES_ACTIVE: prod
DB_HOST: server02
DB_USER: myapp_user
DB_PASS: StrongPass!123
REDIS_HOST: server02
REDIS_PORT: 6379
REDIS_PASS: redis_secret
ports: ["8080:8080"]
restart: always
healthcheck:
test: ["CMD","curl","-fsS","http://localhost:8080/actuator/health"]
interval: 15s
timeout: 3s
retries: 5
web:
image: registry.example.com/myapp/web:1.2.4 # 用 Nginx 托管 dist 的镜像
container_name: myapp-web
ports: ["80:80"]
depends_on:
- api
restart: always
如需把 Redis 也容器化放 server01(非强制):再加
redis: image: redis:7-alpine command: ["redis-server","--requirepass","redis_secret","--appendonly","yes"] ports: ["6379:6379"] # 仅限内网开放 volumes: ["redisdata:/data"] restart: always volumes: redisdata: {}然后
REDIS_HOST改为redis(容器服务名)。
一键操作
docker compose up -d
docker compose ps
docker compose logs -f api
# 升/回级:修改镜像 tag -> up -d 即可
docker compose pull && docker compose up -d
优点:声明式、单机多服务最顺手;可读可审计;回滚容易。
注意:单机编排;跨机多副本/灰度需 K8s/更强工具。
5) Kubernetes(K8s 小集群)
方案
- server01:control-plane + node
- server02:worker node
- MySQL/Redis 仍在 server02(集群外或独立主机),API 通过内网访问。
- Ingress-Nginx 对外统一暴露域名。
API 部署(节选)
apiVersion: apps/v1
kind: Deployment
metadata: { name: myapp-api }
spec:
replicas: 2
selector: { matchLabels: { app: myapp-api } }
template:
metadata: { labels: { app: myapp-api } }
spec:
containers:
- name: api
image: registry.example.com/myapp/api:1.2.4
ports: [{containerPort: 8080}]
env:
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: DB_HOST # 指向 server02
value: "server02"
- name: DB_USER
valueFrom: { secretKeyRef: { name: db-secret, key: user } }
- name: DB_PASS
valueFrom: { secretKeyRef: { name: db-secret, key: pass } }
- name: REDIS_HOST
value: "server02"
- name: REDIS_PORT
value: "6379"
- name: REDIS_PASS
valueFrom: { secretKeyRef: { name: redis-secret, key: pass } }
readinessProbe:
httpGet: { path: /actuator/health, port: 8080 }
initialDelaySeconds: 10
livenessProbe:
httpGet: { path: /actuator/health, port: 8080 }
---
apiVersion: v1
kind: Service
metadata: { name: myapp-api-svc }
spec:
selector: { app: myapp-api }
ports: [{ port: 80, targetPort: 8080 }]
Web(Nginx 静态)+ Ingress
apiVersion: apps/v1
kind: Deployment
metadata: { name: myapp-web }
spec:
replicas: 1
selector: { matchLabels: { app: myapp-web } }
template:
metadata: { labels: { app: myapp-web } }
spec:
containers:
- name: web
image: registry.example.com/myapp/web:1.2.4
ports: [{containerPort: 80}]
---
apiVersion: v1
kind: Service
metadata: { name: myapp-web-svc }
spec:
selector: { app: myapp-web }
ports: [{ port: 80, targetPort: 80 }]
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata: { name: myapp-ing }
spec:
ingressClassName: nginx
rules:
- host: your.domain.com
http:
paths:
- path: /api
pathType: Prefix
backend: { service: { name: myapp-api-svc, port: { number: 80 } } }
- path: /
pathType: Prefix
backend: { service: { name: myapp-web-svc, port: { number: 80 } } }
运维要点
- 发版:
kubectl set image→rollout status;回滚:rollout undo - 健康:readiness/liveness 探针
- 弹性:HPA(基于 CPU 或自定义指标)
- 观测:Prometheus/Grafana + Loki/ELK;Spring Actuator 暴露指标
优点:自愈/扩缩/灰度完善,生产级可靠。
注意:两台机也能跑,但学习与维护成本较高。
6) 发布策略与数据库/缓存协同
- 蓝绿:两套实例(或两套镜像 tag),切 Nginx upstream(传统/Docker/Compose)或 Ingress 权重(K8s)。
- 滚动:逐个替换(Compose
up -d、K8s 默认)。 - 金丝雀:K8s + Ingress/Istio 支持按流量百分比放量。
- MySQL 迁移:Flyway/Liquibase,向前兼容(先扩展字段/双写,后切读,最终清理)。
- Redis 缓存:发布前可设置短 TTL;有需要时在切换后执行精确失效/全量失效(谨慎)。
7) 安全与网络
- 开放端口:server01 仅 80/443;server02 仅内网放行 3306/6379。
- Redis:
requirepass、仅内网访问、持久化策略(AOF/RDB)、内存上限与淘汰策略。 - 机密:环境变量或(K8s)Secret,避免写死在仓库。
- HTTPS:Nginx/Ingress 终止 TLS(Let’s Encrypt/证书)。
- 备份:MySQL 定时备份;Redis AOF/RDB 备份;前端静态可归档。
8) 选型建议(两台 CentOS,Spring Boot + Vue3 + MySQL + Redis)
- 要快、可控且成本低:传统部署(加上软链回滚与简单脚本)就能稳上线。
- 要环境一致性与易回滚:Docker Compose(首选) —— server01 编排
web+api,server02 跑 MySQL+Redis。 - 要多副本/弹性/金丝雀:K8s 可上,但两台机的小集群性价比不如 Compose;除非你明确要走长期平台化。
最小清单(拎包即用)
- 传统:
myapp.service+myapp.conf(本文给出)、软链结构/srv/myapp/{releases,current,logs}。 - Docker:后端/前端 Dockerfile + 主机 Nginx 配置。
- Compose:文中
docker-compose.yml。 - K8s:
Deployment/Service/Ingress清单(上文节选)。
更多推荐



所有评论(0)