Linux环境下SpringBoot Jar包服务化部署:从基础命令到Systemd守护进程
1. SpringBoot Jar包部署基础在Linux环境下部署SpringBoot应用最常见的方式就是将项目打包成可执行的Jar文件。这种方式简单直接特别适合中小型项目的快速部署。我刚开始接触SpringBoot部署时也是从最基础的java -jar命令开始的。先说说最基本的启动方式。假设我们已经把项目打包成myapp.jar最简单的启动命令就是java -jar myapp.jar这个命令虽然简单但有个明显的缺点它会占用当前终端一旦关闭终端或者断开SSH连接应用就会停止。对于生产环境来说这显然是不可接受的。为了解决这个问题我们通常会使用nohup命令让程序在后台运行nohup java -jar myapp.jar app.log 21 这个命令有几个关键点需要注意nohup确保程序不会因为终端关闭而停止app.log 将标准输出重定向到日志文件21 将标准错误也重定向到标准输出 让程序在后台运行我曾经在一个项目中忘记加nohup结果半夜服务挂了第二天被客户投诉才发现问题。从那以后我都会特别注意这个问题。2. 进阶部署方案Shell脚本管理虽然nohup解决了后台运行的问题但日常运维中我们还需要停止、重启等操作。每次都手动查进程ID再kill显然太麻烦了。这时候编写一个Shell脚本就很有必要了。下面是我在实际项目中常用的一个脚本模板#!/bin/bash APP_NAMEmyapp.jar LOG_FILEapp.log usage() { echo Usage: sh app.sh [start|stop|restart|status] exit 1 } is_running() { pid$(ps -ef | grep $APP_NAME | grep -v grep | awk {print $2}) if [ -z $pid ]; then return 1 else return 0 fi } start() { is_running if [ $? -eq 0 ]; then echo $APP_NAME is already running. pid$pid else nohup java -jar $APP_NAME $LOG_FILE 21 echo $APP_NAME started successfully fi } stop() { is_running if [ $? -eq 0 ]; then kill -9 $pid echo $APP_NAME stopped else echo $APP_NAME is not running fi } status() { is_running if [ $? -eq 0 ]; then echo $APP_NAME is running. pid$pid else echo $APP_NAME is not running fi } restart() { stop sleep 2 start } case $1 in start) start ;; stop) stop ;; restart) restart ;; status) status ;; *) usage ;; esac这个脚本提供了start、stop、restart和status四个命令基本覆盖了日常运维需求。使用时只需要sh app.sh start # 启动 sh app.sh stop # 停止 sh app.sh restart # 重启 sh app.sh status # 查看状态记得给脚本添加执行权限chmod x app.sh3. 生产级部署Systemd服务化虽然Shell脚本已经能解决大部分问题但在生产环境中我们还需要考虑更多因素开机自启、服务监控、自动重启等。这时候Systemd就是更好的选择。Systemd是Linux系统的初始化系统和服务管理器它提供了强大的服务管理能力。下面我们来看看如何将SpringBoot应用配置为Systemd服务。首先创建一个服务配置文件sudo vim /etc/systemd/system/myapp.service文件内容如下[Unit] DescriptionMy SpringBoot Application Aftersyslog.target network.target [Service] Userappuser WorkingDirectory/path/to/app ExecStart/usr/bin/java -jar /path/to/app/myapp.jar SuccessExitStatus143 Restartalways RestartSec30 StandardOutputsyslog StandardErrorsyslog SyslogIdentifiermyapp EnvironmentJAVA_HOME/path/to/java [Install] WantedBymulti-user.target这个配置文件中几个关键点User指定运行服务的用户WorkingDirectory设置工作目录ExecStart是启动命令Restartalways确保服务异常退出时自动重启Environment可以设置环境变量配置完成后执行以下命令启用服务sudo systemctl daemon-reload sudo systemctl enable myapp # 开机自启 sudo systemctl start myapp # 启动服务Systemd还提供了丰富的管理命令systemctl status myapp # 查看状态 systemctl stop myapp # 停止服务 systemctl restart myapp # 重启服务 journalctl -u myapp -f # 查看日志我曾经遇到过一个内存泄漏问题服务每隔几天就会崩溃。通过配置Restartalways服务能够自动恢复为我们争取了修复问题的时间。同时journalctl的日志查看功能也比直接看日志文件方便很多。4. 高级配置与优化对于生产环境我们还需要考虑更多优化措施。下面分享几个我在实际项目中总结的经验。JVM参数调优默认的JVM参数通常不适合生产环境。我们可以根据服务器配置调整内存设置ExecStart/usr/bin/java -Xms512m -Xmx1024m -XX:HeapDumpOnOutOfMemoryError -jar /path/to/app/myapp.jar这里-Xms设置初始堆大小-Xmx设置最大堆大小-XX:HeapDumpOnOutOfMemoryError在OOM时生成堆转储文件多环境配置SpringBoot支持通过profile指定环境配置。生产环境应该使用专门的profileExecStart/usr/bin/java -jar /path/to/app/myapp.jar --spring.profiles.activeprod日志管理Systemd默认会管理服务日志但有时我们还需要额外的日志配置。可以在application.properties中配置logging.file.namemyapp.log logging.file.max-size10MB logging.file.max-history7资源限制为了防止服务占用过多资源可以设置cgroup限制[Service] ... MemoryLimit1G CPUQuota200%这些优化措施需要根据实际业务需求和服务器配置进行调整。建议先在测试环境验证效果再应用到生产环境。5. 常见问题排查在实际部署过程中难免会遇到各种问题。下面分享几个常见问题的排查方法。服务启动失败首先查看服务状态systemctl status myapp如果状态显示失败可以查看详细日志journalctl -u myapp -xe常见原因包括文件权限问题端口被占用配置文件错误内存不足如果服务频繁重启可能是内存不足。可以通过以下命令检查内存使用free -h top -p $(pgrep -d, java)适当增加Xmx参数或者优化应用内存使用。性能问题如果服务响应慢可以使用arthas等工具进行诊断curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar日志文件过大如果不加控制日志文件可能会占用大量磁盘空间。除了前面提到的日志配置外还可以使用logrotate管理日志sudo vim /etc/logrotate.d/myapp添加以下内容/path/to/app/myapp.log { daily rotate 7 compress missingok notifempty copytruncate }6. 安全注意事项在生产环境部署服务时安全是不可忽视的重要方面。下面分享几个安全实践。使用专用用户不要使用root用户运行服务。应该创建一个专用用户sudo useradd -r -s /bin/false appuser sudo chown -R appuser:appuser /path/to/app文件权限确保配置文件权限正确chmod 750 /path/to/app chmod 640 /path/to/app/*.properties防火墙配置只开放必要的端口sudo ufw allow 8080/tcp定期更新保持系统和Java环境更新sudo apt update sudo apt upgrade7. 实际案例分享最后分享一个我在实际项目中遇到的案例。我们有一个重要的后台服务需要保证高可用性。最初使用Shell脚本管理但发现有以下问题服务器重启后需要手动启动服务服务崩溃后不能自动恢复日志分散难以排查问题后来我们改用Systemd管理解决了上述问题。具体改进包括配置Restartalways确保服务自动恢复使用systemd enable实现开机自启通过journalctl集中管理日志设置MemoryLimit防止内存泄漏导致系统崩溃改进后服务的可用性从99.5%提升到了99.95%运维工作量也大幅减少。