Ubuntu新建systemd服务

本文讲述在ubuntu系统中新建service服务。

一、环境

  • 系统:ubuntu 16.04 64 bit。
  • 测试命令:/home/latelee/test/server

二、创建service文件

新建文件 /lib/systemd/system/myserver.service (经测试,在 /etc/systemd/system/ 目录下亦可),内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=A tcp server test service
After=network.target
StartLimitInterval=0

[Service]
Type=notify
Restart=always
TimeoutStartSec=0
ExecStart=/home/latelee/test/server

[Install]
WantedBy=multi-user.target

释义:
Description 为本服务的描述信息,After表示本服务必须在某些服务之后(有依赖关系的服务需要指明),Restart=always表示程序退出就会重启。TimeoutStartSec 表示启动耗时超时时间(如为3,表示程序必须3秒内启动完毕,超时则无法成功启动),默认为0即可。ExecStart 为需要启动的程序或命令。WantedBy 参见开机使能。

二、命令

文件修改后,必须重新加载:

1
systemctl daemon-reload

启动:

1
systemctl start myserver.service

停止:

1
systemctl stop myserver.service

重新启动:

1
systemctl restart myserver.service

三、验证

服务配置文件有 Restart=always,表示程序退出时会重启。
查看进程,杀死进程,再查看进程。

1
2
3
4
5
ps aux | grep server
root 11152 0.0 0.0 80272 692 ? Ssl 10:35 0:00 /home/latelee/test/server &
kill -9 11152
ps aux | grep server
root 11164 0.0 0.0 80272 708 ? Ssl 10:36 0:00 /home/latelee/test/server &

PID已变化。说明systemd检测到程序退出后,会重新启动。

四、开机启动

使能开机启动:

1
2
$ sudo systemctl enable myserver
Created symlink from /etc/systemd/system/multi-user.target.wants/myserver.service to /etc/systemd/system/myserver.service.

释义:直接用 systemctl enable 可使能服务,该命令将创建服务配置文件的链接文件到 /etc/systemd/system/multi-user.target.wants 目录。
查看使能列表:

1
sudo systemctl list-unit-files | grep enabled

查看本服务:

1
2
$ sudo systemctl list-unit-files | grep enabled | grep myserver
myserver.service enabled

禁止开机启动:

1
2
$sudo systemctl disable faced
Removed symlink /etc/systemd/system/multi-user.target.wants/faced.service.

五、试验

本节以前述服务为基础,尝试一些小实验。只列出有差异的地方。

5.1 特定条件不重启

有些场合,不需要 systemd 帮忙重启,如更新程序文件,可以先停止服务,再开启服务。也可以设置不让 systemd 重启程序。添加:

1
2
3
Type=notify
RestartPreventExitStatus=42 SIGKILL
Restart=always // !! 此值保持

释义:
RestartPreventExitStatus表示遇到后面指定的退出码、信号不会重启,其它情况则照旧。

测试:
启动服务后,执行 kill -9 <PID>,服务不再重启。而执行 killall myserver,服务会重启。

5.2 涉及子进程

场合:主进程(业务程序)会创建子进程(升级程序),并退出。由升级程序接管。
使用前述配置,主进程退出后,并没有启动子进程。相当于所有与此有关的进程都退出了。
修改:

1
2
3
Type=forking
RestartPreventExitStatus=42 SIGKILL
Restart=always // !! 此值保持

主进程退出后,子进程启动,子进程又可创建子进程。
遗留:RestartPreventExitStatus 无效果,需要手动停止服务。

方式二,与前述相同,但添加 KillMode=process 选项:

1
2
3
4
Type=notify
KillMode=process
RestartPreventExitStatus=42 SIGKILL
Restart=always

效果:主进程以42退出码退出,但systemd不再管理。其后创建的子进程亦不会被管理。相当于该服务已经被退出。

六、试错记录

配置文件原写 StartLimitIntervalSec,但开机后无法启动服务,提示:
出错:

1
Unknown lvalue 'StartLimitIntervalSec' in section 'Unit'

将 StartLimitIntervalSec 改为 StartLimitInterval。但是,使用 StartLimitIntervalSec 时,手动启动服务会成功。原因未知。

如果不使能开机启动,当重新开机时,查看状态如下:

1
2
3
4
$ systemctl status myserver.service
● myserver.service - A tcp server test service
Loaded: loaded (/etc/systemd/system/myserver.service; disabled; vendor preset: e
Active: inactive (dead)

释义:服务只是加载,并未运行。因此,必须要使能开机启动。

可以使用 man 查看帮助信息。如 man systemd.service、man systemd.unit、man systemd.kill 等。