努力
加油

如何在同一个Linux服务器上部署两个Spring Boot服务?

在 Linux 服务器上部署两个 Spring Boot 服务,本质上就是进程管理和端口隔离的问题。

别整那些虚的,直接上干货。根据你对运维复杂度、资源利用率和发布效率的要求,主要有三种主流方案。我会按“从简单粗暴到生产标准”的顺序给你拆解,最后给个选型建议。


方案一:最基础版——直接运行 JAR 包(适合测试/个人项目)

这是最简单的,不需要任何额外工具,但维护起来很痛苦(日志难找、挂了不会自动重启)。

核心逻辑:

  1. 确保两个服务的 application.yml 或 application.properties 中配置的 server.port 不同(比如一个 8080,一个 8081)。
  2. 确保数据库连接、Redis 缓存 Key 等没有冲突。

操作步骤:

# 1. 上传两个 jar 包到服务器
scp app-service-a.jar user@server:/opt/apps/
scp app-service-b.jar user@server:/opt/apps/

# 2. 后台启动第一个服务,并指定日志输出
nohup java -jar /opt/apps/app-service-a.jar --server.port=8080 > /var/log/service-a.log 2>&1 &

# 3. 后台启动第二个服务
nohup java -jar /opt/apps/app-service-b.jar --server.port=8081 > /var/log/service-b.log 2>&1 &

缺点:

  • 进程挂了你得手动去查。
  • 重启麻烦,得先 kill 掉旧进程。
  • 资源限制不好控。

方案二:进阶版——使用 Systemd 管理(推荐中小规模生产环境)

这是目前国内大多数中型互联网公司最常用的方式。Linux 自带的 systemd 是标准的进程管理器,自带日志轮转、开机自启、崩溃自动重启等功能。比 nohup 稳定得多。

核心逻辑:
为每个 Spring Boot 服务创建一个独立的 .service 文件。

操作步骤:

  1. 创建服务配置文件
    在 /etc/systemd/system/ 目录下创建两个文件,例如 app-a.service 和 app-b.service。

    app-a.service 内容示例:

    [Unit]
    Description=Spring Boot Service A
    After=syslog.target
    
    [Service]
    User=root
    ExecStart=/usr/bin/java -jar /opt/apps/app-service-a.jar --server.port=8080
    SuccessExitStatus=143
    Restart=on-failure
    # 可选:设置内存上限,防止 OOM 拖垮服务器
    MemoryMax=512M
    
    [Install]
    WantedBy=multi-user.target

    app-b.service 同理,修改文件名、Description、ExecStart 路径和端口。

  2. 重载配置并启动

    # 加载新的 service 文件
    systemctl daemon-reload
    
    # 启动服务
    systemctl start app-a
    systemctl start app-b
    
    # 设置开机自启
    systemctl enable app-a
    systemctl enable app-b
  3. 日常运维命令

    # 查看状态
    systemctl status app-a
    
    # 查看实时日志(替代 tail -f)
    journalctl -u app-a -f
    
    # 重启
    systemctl restart app-a

优点:

  • 原生支持,无需安装第三方软件。
  • 日志由 systemd 统一管理,可通过 journalctl 轻松排查。
  • 支持自动重启和资源限制。

方案三:专业版——Docker 容器化部署(强烈推荐,尤其是微服务架构)

如果你已经在使用 Kubernetes (K8s) 或者 Docker Swarm,或者希望环境隔离彻底,Docker 是唯一正解。即使不用 K8s,单机 Docker 也是最佳实践。

核心逻辑:
每个 Spring Boot 应用打包成一个独立的 Docker 镜像,通过 Docker Compose 或独立容器运行。

操作步骤(以 Docker Compose 为例):

  1. 编写 Dockerfile (假设两个服务结构类似,可以复用)

    FROM openjdk:17-jdk-slim
    WORKDIR /app
    COPY target/*.jar app.jar
    ENTRYPOINT ["java", "-jar", "app.jar"]
  2. 编写 docker-compose.yml

    version: '3.8'
    services:
     service-a:
       build: ./service-a
       ports:
         - "8080:8080"
       environment:
         - SPRING_PROFILES_ACTIVE=prod
       restart: always
    
     service-b:
       build: ./service-b
       ports:
         - "8081:8081"
       environment:
         - SPRING_PROFILES_ACTIVE=prod
       restart: always
  3. 启动

    docker-compose up -d

优点:

  • 环境绝对隔离:Java 版本、依赖库互不影响。
  • 迁移方便:换一台服务器,只要装好 Docker,拷贝 yaml 文件即可恢复。
  • 资源可控:可以轻松限制 CPU 和内存。
  • 易于扩展:未来如果需要横向扩展,只需改副本数。

关键注意事项(避坑指南)

无论选哪种方案,以下三点必须检查,否则必出问题:

  1. 端口冲突:
    确保两个服务的 server.port 不同。如果其中一个用了默认 8080,另一个必须显式配置其他端口(如 8081, 9090 等)。

  2. 共享资源竞争:

    • 数据库:通常没问题,DB 在网络或独立实例。
    • Redis/MQ:确认 Key 前缀是否区分?比如 user:a:info 和 user:b:info。如果共用同一个 Redis 实例且 Key 不区分,会导致数据串扰。
    • 本地文件存储:如果服务读写本地磁盘(如上传图片),确保路径不冲突,或者挂载不同的 Volume/Disk。
  3. 防火墙/安全组:
    在国内云厂商(阿里云、腾讯云、华为云等)上,仅仅在 Linux 内部开放端口是不够的。

    • 你必须在云控制台的 安全组(Security Group) 中放行对应的端口(如 8080, 8081)。
    • 同时检查 Linux 内部的 firewalld 或 iptables 是否拦截。

选型建议

场景 推荐方案 理由
个人博客/小型测试 方案一 (nohup) 快,省事,没人关心稳定性。
中小型生产项目 方案二 (Systemd) 稳定,轻量,无需引入 Docker 复杂性,运维成本低。
微服务/大型项目/团队开发 方案三 (Docker) 标准化,可移植性强,便于后续接入 CI/CD 和 K8s。
高并发/多实例 方案三 + Nginx 单个服务器扛不住时,用 Nginx 做反向XX,负载均衡到多个 Docker 容器或多个服务器。

总结:
如果你们团队还没有容器化能力,强烈建议从 Systemd 入手,它比 nohup 靠谱太多,又比 Docker 轻量。如果已经有 DevOps 流程,直接上 Docker Compose 或 K8s,这是趋势。

别纠结,先跑起来,再优化。