我想要使用 systemd (systemctl) 管理 TeamSpeak 3 服务器。
当我使用 systemctl 命令启动/停止/重新启动 TeamSpeak 3 服务器时,systemctl 返回正确的状态:
$ systemctl status ts3server.service
● ts3server.service - TeamSpeak 3 Server
Loaded: loaded (/etc/systemd/system/ts3server.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2019-02-12 23:15:18 CET; 1min 11s ago
Main PID: 842 (ts3server)
CGroup: /system.slice/ts3server.service
└─842 ./ts3server inifile=ts3server.ini
Feb 12 23:15:18 hostname.local systemd[1]: Starting TeamSpeak 3 Server...
Feb 12 23:15:18 hostname.local ts3server_startscript.sh[838]: Starting the TeamSpeak 3 server
Feb 12 23:15:18 hostname.local ts3server_startscript.sh[838]: TeamSpeak 3 server started, for details please view the log file
Feb 12 23:15:18 hostname.local systemd[1]: Started TeamSpeak 3 Server.
但是,当服务以其他方式停止(例如,通过自动更新过程)然后再次启动时(没有使用 systemctl),该systemctl status
命令将返回不正确的状态:
$ systemctl status ts3server.service
● ts3server.service - TeamSpeak 3 Server
Loaded: loaded (/etc/systemd/system/ts3server.service; enabled; vendor preset: enabled)
Active: inactive (dead) since Mon 2019-02-11 03:15:16 CET; 1 day 19h ago
Condition: start condition failed at Mon 2019-02-11 03:15:16 CET; 1 day 19h ago
└─ ConditionPathExists=!/home/teamspeak/.update.lock was not met
Process: 21740 ExecStop=/home/teamspeak/ts3server_startscript.sh stop (code=exited, status=0/SUCCESS)
Process: 29220 ExecStart=/home/teamspeak/ts3server_startscript.sh start (code=exited, status=0/SUCCESS)
Main PID: 29224 (code=exited, status=0/SUCCESS)
Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.
此时PID文件存在:
$ stat /home/teamspeak/ts3server.pid
File: /home/teamspeak/ts3server.pid
Size: 4 Blocks: 8 EA Block: 4096 regular file
Device: ca01h/51713d Inode: 534471 Symbolic Links: 1
Access: (0644/-rw-r--r--) Uid: ( 1001/teamspeak) Gid: ( 1001/teamspeak)
Access : 2019-02-12 23:15:09.192927211 +0100
Modified: 2019-02-12 23:15:09.188927218 +0100
Changed : 2019-02-12 23:15:09.188927218 +0100
Birth : -
具有此 PID 的进程正在运行,我可以连接到此 TeamSpeak 3 服务器。
/home/teamspeak/.update.lock
自动更新过程运行时存在。更新后,该文件将被移除/删除,不再存在。
systemctl
显示正确的状态,当我终止正在运行的服务 PID 时,systemctl
稍后使用 systemd 重新启动该服务。
这是我的/etc/systemd/system/ts3server.service
文件:
[Unit]
Description=TeamSpeak 3 Server
After=network.target mysqld.service
ConditionPathExists=!/home/teamspeak/.update.lock
[Install]
WantedBy=multi-user.target
Alias=ts3server.service
[Service]
User=teamspeak
Group=teamspeak
WorkingDirectory=/home/teamspeak/
ExecStart=/home/teamspeak/ts3server_startscript.sh start
ExecStop=/home/teamspeak/ts3server_startscript.sh stop
ExecReload=/home/teamspeak/ts3server_startscript.sh restart
PIDFile=/home/teamspeak/ts3server.pid
Restart=always
Type=forking
为什么systemctl
虽然 TeamSpeak 3 服务器以不同的方式正确启动,却无法返回正确的状态?
答案1
您应该将单元文件中的更改为,这样它就可以正常工作。IIRCType
需要显式调用方法,而您从 bash 脚本启动它,则根本没有调用。simple
forking
fork()
fork()
答案2
您的“为什么”问题的答案是,systemd 正在寻找它知道的 PID(上面示例输出中的 842),它不跟踪服务自己的 PID 信息。如果该进程不再运行,systemd 不知道该进程发生了什么。它也无法重新启动它(因为端口已经由新实例绑定)。
可能更干净的升级方法是
- 使用 systemctl 停止服务
- 执行更新,然后
- 使用 systemctl 启动该进程。
答案3
诀窍是指定Type=oneshot
和RemainAfterExit=yes
不指定PIDFile=
最小示例:
[Unit]
Description=service that is restarted by externalities.
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/startup.sh
ExecStop=/stop.sh
[Install]
WantedBy=multi-user.target
文档称之为“可停止的一次性服务“
与一次性服务类似,有时一些单元需要执行一个程序来设置某些东西,然后执行另一个程序来关闭它,但是在它们被视为“启动”时,没有任何进程保持活动状态。
但是他们没有考虑启动的程序改变 PID 值的用例,尽管它也可以适用于这种情况。
答案4
使用systemctl --user get-default
获取默认目标
$ systemctl --user get-default
default.target
改变
WantedBy=default.target