在 Linux 系统中,通过 systemd 管理自定义程序(如 Python 脚本、Node.js 应用、Go 二进制程序等)非常常见。要实现这一点,你需要创建一个 .service 单元文件。
本文将详细讲解 .service 文件的结构、常用配置项、编写规范及完整示例。
一、.service 文件的位置
- 系统级服务(推荐用于生产环境):/etc/systemd/system/your-service-name.service
- 发行版默认服务:/usr/lib/systemd/system/(或 /lib/systemd/system/)
“注意:
- 系统级服务仅 root 可写,优先级高,不会被软件包更新覆盖。
- 发行版默认服务通常由软件包管理器安装,不建议手动修改。
- 自定义服务一律放在 /etc/systemd/system/
二、基本结构
.service 文件采用 INI 风格语法,分为若干节(section),最常用的有:
- [Install]:定义启用(enable)时的行为
三、各节详解
[Unit] 节
| |
|---|
Description= | 服务的简短描述(必填,用于 systemctl status 显示) |
Documentation= | |
After= | 在哪些单元启动之后启动本服务(如 network.target) |
Before= | |
Wants= | |
Requires= | |
Conflicts= | |
示例:
[Unit]
Description=My Custom Web Application
Documentation=https://example.com/docs
After=network.target
Wants=network.target
⚠️ 注意:After 不表示依赖!它只控制启动顺序。要建立依赖,请配合 Wants 或 Requires。
[Service] 节(核心)
这是最关键的部分,定义服务如何运行。
基础类型
- Type=simple(默认):主进程立即启动,systemd 认为服务已就绪。
- Type=forking:服务会 fork 子进程后退出父进程(传统守护进程)。
- Type=oneshot:执行一次即退出(如初始化脚本),常配合 RemainAfterExit=yes。
- Type=notify:服务通过 sd_notify() 通知 systemd 已就绪(需程序支持)。
- Type=idle:延迟启动,直到其他任务完成(较少用)。
关键指令
| |
|---|
ExecStart= | |
ExecStartPre= | |
ExecStartPost= | |
ExecStop= | |
ExecReload= | 重载配置时执行的命令(对应 systemctl reload) |
Restart= | 何时自动重启(always, on-failure, on-abnormal, on-watchdog, on-success, no) |
RestartSec= | |
User= | |
WorkingDirectory= | |
Environment= | 设置环境变量(如 Environment=NODE_ENV=production) |
EnvironmentFile= | 从文件加载环境变量(如 /etc/myapp.conf) |
PIDFile= | 指定 PID 文件路径(仅用于 Type=forking) |
StandardOutput= | 重定向标准输出/错误(如 journal, syslog, file:/var/log/app.log) |
TimeoutStartSec= | |
KillMode= | 终止方式(control-group 默认,杀掉整个 cgroup) |
[Install] 节
控制 systemctl enable 的行为。
| |
|---|
WantedBy= | 启用服务时,将其链接到哪个 target(最常用) |
RequiredBy= | |
Alias= | |
最常见写法:
[Install]
WantedBy=multi-user.target
这表示:当系统进入多用户模式(即正常运行状态)时,自动启动该服务。
四、案例
案例1:启动一个jar
创建一个服务单元文件,例如 demo.service:
[Unit]
Description=a demo project
After=network.target
[Service]
Type=simple
ExecStart= /usr/java/jdk/bin/java -jar /usr/project/demo.jar
[Install]
WantedBy=multi-user.target
相关命令
# 重载 systemd 配置
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start demo
# 设置开机自启
sudo systemctl enable demo
# 查看状态
sudo systemctl status demo
# 实时查看日志
sudo journalctl -u demo -f
# 查看最近 100 行
sudo journalctl -u demo -n 100
五、常见问题
为什么用 systemd 管理 Java 应用?
很多 Java 后端服务(如 Spring Boot、Quarkus、Micronaut 等)最终会打包成一个可执行的 fat JAR 文件。虽然可以直接用 nohup java -jar app.jar & 启动,但这种方式存在明显缺陷:
- 无法通过统一命令管理(start/stop/status)
而通过 systemd 自定义服务,你可以获得: