在现代 Linux 系统中,systemd
是默认的初始化系统,用于管理系统服务的启动、停止、重启等操作。systemd
服务文件(以 .service
为后缀)是定义服务行为的核心配置文件。本文档将详细介绍如何编写一个 systemd
服务文件,包括文件结构、常用配置项、操作步骤以及注意事项。
systemd
服务文件用于定义一个服务的以下行为:
通过服务文件,可以将自定义的应用程序或脚本作为系统服务运行,方便管理和监控。
服务文件通常存放在以下路径:
/etc/systemd/system/
:用户自定义的服务文件,推荐使用此路径。/lib/systemd/system/
:系统预装的服务文件,不要直接修改此路径下的文件。注意:用户自定义的服务文件优先级高于系统预装文件。
一个 systemd
服务文件由以下三个主要部分组成:
[Unit]
:描述服务的元信息和依赖关系。[Service]
:定义服务的具体行为(启动、停止、重启等)。[Install]
:定义服务的安装行为(例如是否开机自启)。以下是一个基本的模板:
[Unit]
Description=服务描述
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/your_program --option
ExecStop=/usr/bin/killall your_program
Restart=always
User=your_user
Group=your_group
[Install]
WantedBy=multi-user.target
[Unit]
部分[Unit]
部分用于描述服务的元信息和依赖关系,常用配置项如下:
Description
:服务的描述信息,用于说明服务的功能。例如:Description=My Python Application
。After
:指定服务在哪些目标(target)或服务启动后启动。例如,After=network.target
表示在网络服务启动后启动。Requires
(可选):指定依赖的服务。如果依赖的服务未启动,则本服务也不会启动。例如,Requires=postgresql.service
。Wants
(可选):弱依赖,建议的依赖关系。即使依赖的服务未启动,本服务仍会尝试启动。例如,Wants=redis.service
。[Service]
部分[Service]
部分用于定义服务的具体行为,常用配置项如下:
Type
:服务的类型,决定服务的启动行为。常见值包括:
simple
(默认):服务启动后,主进程就是 ExecStart
指定的进程。forking
:服务启动后,主进程会 fork 出子进程,主进程退出。oneshot
:服务执行一次后退出,常用于脚本任务。notify
:服务启动后会通知 systemd。idle
:延迟启动,直到其他服务启动完成。ExecStart
:启动服务的命令,必须是绝对路径。可以带参数。例如,ExecStart=/usr/bin/python3 /opt/myapp/main.py
。ExecStop
(可选):停止服务的命令。如果不指定,systemd 会通过信号(如 SIGTERM)终止进程。例如,ExecStop=/usr/bin/killall python3
。ExecReload
(可选):重新加载服务的命令(例如重新加载配置文件)。例如,ExecReload=/bin/kill -HUP $MAINPID
。Restart
(可选):重启策略,常见值包括:
always
:总是重启。on-failure
:仅在失败时重启。no
:不重启(默认)。User
(可选):指定运行服务的用户。例如,User=appuser
。Group
(可选):指定运行服务的用户组。例如,Group=appgroup
。WorkingDirectory
(可选):指定服务的工作目录。例如,WorkingDirectory=/opt/myapp
。Environment
(可选):设置环境变量。例如,Environment="PATH=/usr/local/bin"
。EnvironmentFile
(可选):从文件中加载环境变量。例如,EnvironmentFile=/etc/myapp/env.conf
。TimeoutStartSec
(可选):启动超时时长,超时后服务会被认为启动失败。例如,TimeoutStartSec=30
。TimeoutStopSec
(可选):停止超时时长,超时后服务会被强制终止。例如,TimeoutStopSec=10
。[Install]
部分[Install]
部分用于定义服务的安装行为,常用配置项如下:
WantedBy
:指定服务在哪个目标(target)下启用。例如,WantedBy=multi-user.target
表示在多用户模式(类似于传统的 runlevel 3)下启用服务,相当于开机自启。RequiredBy
(可选):指定哪些目标依赖此服务。以一个实际的例子为例,假设你有一个 Python 脚本 /opt/myapp/main.py
,希望将其作为服务运行,并开机自启。以下是服务文件的内容:
[Unit]
Description=My Python Application
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/myapp/main.py
ExecStop=/usr/bin/killall python3
Restart=always
User=appuser
Group=appgroup
WorkingDirectory=/opt/myapp
Environment="PYTHONPATH=/opt/myapp/lib"
[Install]
WantedBy=multi-user.target
将上述内容保存为 /etc/systemd/system/myapp.service
。
每次修改服务文件后,需要运行以下命令重新加载配置:
sudo systemctl daemon-reload
启用服务,使其在系统启动时自动运行:
sudo systemctl enable myapp.service
手动启动服务:
sudo systemctl start myapp.service
检查服务是否正常运行:
sudo systemctl status myapp.service
手动停止服务:
sudo systemctl stop myapp.service
重启服务:
sudo systemctl restart myapp.service
禁用服务,使其不再开机自启:
sudo systemctl disable myapp.service
如果服务启动失败,可以通过以下方式调试:
sudo systemctl status myapp.service
sudo journalctl -u myapp.service
sudo journalctl -u myapp.service -b
sudo journalctl -u myapp.service -f
ExecStart
和其他命令必须使用绝对路径,不能使用相对路径或 shell 别名。root
用户运行服务,尽量使用普通用户。systemd
的日志功能(journalctl
)。以下是一个更复杂的例子,展示如何编写一个依赖数据库、支持重新加载配置的服务:
[Unit]
Description=Complex Application Service
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
ExecStart=/usr/bin/your_program --config /etc/your_program.conf
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
User=appuser
Group=appgroup
WorkingDirectory=/opt/your_program
EnvironmentFile=/etc/your_program/env.conf
TimeoutStartSec=30
TimeoutStopSec=10
[Install]
WantedBy=multi-user.target
Requires=postgresql.service
)。EnvironmentFile
加载环境变量文件。ExecReload
)。编写 systemd
服务文件是管理 Linux 服务的重要技能。通过合理配置 [Unit]
、[Service]
和 [Install]
部分,可以灵活地控制服务的行为。建议在编写完成后,仔细测试并查看日志,确保服务按预期运行。