1. 自定义 systemctl 服务
1. 自定义 systemctl 服务
问题:有一个脚本或后台程序,希望它能像系统服务一样被 systemctl start、systemctl stop、systemctl enable 管理。
核心:systemctl 只是管理入口,真正需要自定义的是 systemd 的 unit 文件。把服务描述写进 /etc/systemd/system/*.service,再让 systemd 重新加载配置即可。
最小服务文件
假设有一个可执行程序:
/opt/my-app/bin/server
可以新建:
sudo vim /etc/systemd/system/my-app.service
内容如下:
[Unit]
Description=My App Service
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/my-app
ExecStart=/opt/my-app/bin/server
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
这三个区块分别负责不同事情:
[Unit]:描述服务本身,以及它和其他系统组件的关系。[Service]:定义服务怎么启动、在哪个目录运行、失败后是否重启。[Install]:定义执行enable时要挂到哪个启动目标下。
让配置生效
写完 unit 文件后,需要重新加载 systemd 配置:
sudo systemctl daemon-reload
然后就可以像普通服务一样管理:
sudo systemctl start my-app
sudo systemctl stop my-app
sudo systemctl restart my-app
sudo systemctl status my-app
如果希望开机自启:
sudo systemctl enable my-app
取消开机自启:
sudo systemctl disable my-app
常用字段
ExecStart 是最关键的字段,它必须指向实际启动命令。最好使用绝对路径,避免环境变量和工作目录不一致带来的问题。
ExecStart=/usr/bin/node /opt/my-app/dist/server.js
如果服务需要指定运行用户,可以加上:
User=app
Group=app
如果程序依赖环境变量,可以直接写在 unit 文件中:
Environment=NODE_ENV=production
Environment=PORT=3000
也可以放到独立文件里:
EnvironmentFile=/etc/my-app.env
查看日志
服务启动失败时,先看状态:
sudo systemctl status my-app
再看日志:
journalctl -u my-app -e
实时跟踪日志:
journalctl -u my-app -f
常见错误
修改了 service 文件但没有生效
改完 /etc/systemd/system/my-app.service 后,需要重新执行:
sudo systemctl daemon-reload
sudo systemctl restart my-app
命令在终端能跑,放进 systemd 后失败
systemd 启动服务时不会继承你当前 shell 的完整环境。把命令、解释器、配置文件都写成绝对路径,必要时显式设置 WorkingDirectory 和 EnvironmentFile。
服务启动后立刻退出
如果程序本身是常驻进程,通常用 Type=simple。如果脚本执行完就退出,systemd 会认为服务结束了。此时要么让程序保持前台运行,要么根据实际行为选择更合适的 service 类型。
自定义
systemctl的本质不是改systemctl命令,而是定义一个 systemd unit,让系统知道这个服务如何启动、停止、重启和开机自启。