systemd指北

使用systemd管理应用程序 #

linux上管理进程的方式多种多样,有python系列的supervisord,nodejs系列的pm2,linux命令start-stop-daemon,也有较为传统的sysinit的service,还有systemd方式,各有优缺点,该文主要讲述一下systemd管理服务的方式

咋编写 #

查手册,查文档,弄清程序运行基本概念,需要啥参数搞啥参数即可

以redis.service为例搞事 #

[Unit]
Description=Advanced key-value store
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)

[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis.conf
PIDFile=/run/redis/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=2755

UMask=007
PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWritePaths=-/var/lib/redis
ReadWritePaths=-/var/log/redis
ReadWritePaths=-/var/run/redis

NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
MemoryDenyWriteExecute=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# redis-server can write to its own config file when in cluster mode so we
# permit writing there by default. If you are not using this feature, it is
# recommended that you replace the following lines with "ProtectSystem=full".
ProtectSystem=true
ReadWriteDirectories=-/etc/redis

[Install]
WantedBy=multi-user.target
Alias=redis.service

service的基本架子

[Unit]
...
[Service]
...
[Install]

[Unit] 部分,是该服务单元的描述信息,其中After可以决定依赖关系,比如该服务依赖于网络。

[Service]部分,是描述服务怎么运行的核心部分,对于简单的服务,使用以下配置就可以运行:

[Service]
ExecStart=xxxx

默认Type = simple

而redis本身配置文件/etc/redis/redis.conf中有daemonize yes的配置,所以应用本身就可以以守护进程的方式运行,这里Type就需要设置为forking,当然你也可以选择让它在前台运行,然后设置Type = simple

其他的配置就根据不同的运行需求进行配置啦,比如pid文件,重启策略,运行用户,当前工作目录,文件描述符,进程数限制,启动前准备运动,停止命令,停止前准备运动等,那是相当丰富的。

[Install]部分,是安装部分,WantedBy=multi-user.target,就是说明该服务所在target,multi-user.target就是命令行状态

Q&A #

systemd服务配置文件中的type该如何选择? #

参考 stackoverflow-1274901,大致意思如下:

可以根据平时我们命令行运行服务的情形来决定到底使用哪一种类型

  1. 如果启动服务,并且服务一直在前台运行,直到ctrl-c才能够退出服务,那么想都不用想,使用Type = simple即可。
  2. 如果命令行返回,并且服务一直在后台运行(服务直接以守护进程的方式运行啦),那么Type = forking绝对没错。
  3. 如果只是一些job类型的服务,运行一次就退出,可能做了一些变更,但是服务本身并没有遗留任何进程,那么可以选择使用Type = oneshot,可以在ExecStart=set来设置一些东西,然后在ExecStop=unset来取消一些设置,我们同时可以利用RemainAfterExit=true配置,来追踪该服务的状态。

其他的类型,对于小运维管理来说不是太常用,比如Type=notify需要结合socket使用;Type=dbus需要结合D-BUS使用。