在单台阿里云服务器上部署两个 Spring Boot 项目,最佳实践的核心原则是:隔离性、可维护性、自动化和安全性。
以下是经过生产环境验证的最佳实践方案,分为 架构选型、具体实施步骤 和 关键注意事项 三部分。
一、 架构选型推荐
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Nginx + Systemd (推荐) | 大多数中小型项目 | 资源占用低、配置灵活、易于监控、无需额外中间件 | 需要手动配置 Nginx 反向X_X |
| Docker Compose | 希望环境一致、快速迁移 | 环境隔离好、启动停止方便、依赖管理简单 | 学习成本稍高,需安装 Docker |
| Spring Cloud Gateway / K8s | 大型微服务架构 | 功能强大、扩展性强 | 过度设计,小项目不推荐 |
✅ 强烈建议采用
Nginx + Systemd或Docker Compose方案。
以下以 Nginx + Systemd 为例(最轻量、最常用),并附带 Docker 方案简述。
二、 最佳实践详细步骤(Nginx + Systemd)
1. 项目打包与部署结构
- 将两个 Spring Boot 项目分别打包为独立的 JAR 文件(如
app1.jar,app2.jar)。 - 创建统一目录结构,例如:
/opt/apps/ ├── app1/ │ ├── app1.jar │ ├── application.yml │ └── logs/ ├── app2/ │ ├── app2.jar │ ├── application.yml │ └── logs/
2. 使用 Systemd 管理服务(关键!)
不要使用 nohup java -jar ... & 这种方式,它难以重启、日志混乱、无法开机自启。
为每个项目创建 systemd 服务文件:
# /etc/systemd/system/app1.service
[Unit]
Description=App1 Service
After=network.target
[Service]
Type=simple
User=root # 建议使用专用用户,如 deploy
WorkingDirectory=/opt/apps/app1
ExecStart=/usr/bin/java -Xms512m -Xmx1024m -jar /opt/apps/app1/app1.jar --spring.profiles.active=prod
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
💡 注意:
- 设置
-Xms和-Xmx防止内存溢出。- 指定
WorkingDirectory和日志路径。- 使用
--spring.profiles.active区分环境配置。
加载并启用服务:
sudo systemctl daemon-reload
sudo systemctl enable app1.service
sudo systemctl start app1.service
sudo systemctl status app1.service
对 app2 重复上述操作,创建 app2.service。
3. 配置 Nginx 反向X_X
通过域名或端口区分两个项目。
方式 A:不同端口(简单)
- App1:
http://your-ip:8081 - App2:
http://your-ip:8082
方式 B:不同子域名(推荐,更专业)
假设你有域名 example.com:
- App1:
app1.example.com→ X_X到localhost:8081 - App2:
app2.example.com→ X_X到localhost:8082
Nginx 配置示例 (/etc/nginx/conf.d/apps.conf):
# App1 配置
server {
listen 80;
server_name app1.example.com;
location / {
proxy_pass http://127.0.0.1:8081;
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;
}
}
# App2 配置
server {
listen 80;
server_name app2.example.com;
location / {
proxy_pass http://127.0.0.1:8082;
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;
}
}
重载 Nginx:
sudo nginx -t && sudo nginx -s reload
4. 安全组配置
在阿里云控制台 安全组 中:
- 开放 HTTP (80) 和 HTTPS (443) 端口。
- 关闭 8081、8082 等内部应用端口,只允许 Nginx 访问。
- 仅对运维 IP 开放 SSH (22) 端口。
三、 替代方案:Docker Compose(更现代)
如果你熟悉 Docker,这是更优雅的方式:
# docker-compose.yml
version: '3'
services:
app1:
image: openjdk:17-jdk-slim
container_name: app1
ports:
- "8081:8081"
volumes:
- ./app1:/app
command: ["java", "-jar", "/app/app1.jar"]
restart: always
app2:
image: openjdk:17-jdk-slim
container_name: app2
ports:
- "8082:8082"
volumes:
- ./app2:/app
command: ["java", "-jar", "/app/app2.jar"]
restart: always
nginx:
image: nginx:latest
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app1
- app2
restart: always
然后通过 Nginx 容器X_X到 app1:8081 和 app2:8082。
四、 关键注意事项与优化建议
1. 资源隔离与限制
- CPU/Memory 限制:在 Systemd 中可设置
MemoryLimit=,或在 Docker 中使用mem_limit:。 - 避免争抢资源:确保 JVM 堆内存总和不超过服务器物理内存的 70%~80%,留出空间给 OS 和 Nginx。
2. 日志管理
- 集中日志:不要只看控制台。配置 Logback/Log4j2 输出到文件,并使用
logrotate自动切割日志。 - ELK/Loki:如果预算允许,接入阿里云 SLS(日志服务)或使用 Loki+Grafana 进行日志收集和分析。
3. 数据库连接
- 共享数据库? 如果两个项目共用一个 MySQL 实例,务必:
- 使用不同的 Schema 或前缀表名。
- 合理设置连接池大小(HikariCP),避免连接耗尽。
- 独立数据库? 更推荐每个项目拥有独立的数据库实例或 Schema,便于维护和故障隔离。
4. 健康检查与监控
- 暴露 Actuator 端点
/actuator/health。 - 使用阿里云云监控或 Prometheus + Grafana 监控 CPU、内存、JVM GC 情况。
- 设置告警:当 CPU > 80% 或内存 > 90% 时通知。
5. 备份与恢复
- 定期备份数据库。
- 保存配置文件版本控制(Git)。
- 考虑使用阿里云 ECS 快照功能,定期创建系统盘和数据盘快照。
五、 总结:最佳实践清单
✅ 必须做:
- 使用 Systemd 或 Docker 管理服务生命周期。
- 使用 Nginx 作为反向X_X,隐藏后端端口。
- 配置阿里云安全组,仅开放必要端口。
- 设置 JVM 内存参数,防止 OOM。
- 配置日志轮转(logrotate)。
❌ 避免做:
- 直接暴露 Java 进程端口到公网。
- 使用
nohup &运行应用。 - 两个项目共用同一个数据库账号且无权限隔离。
- 忽略监控和日志。
通过以上方案,你可以在一台阿里云服务器上稳定、安全、高效地运行多个 Spring Boot 项目。
CLOUD技术博