现在越来越多的Linux发行版将init
系统从upstart
(or other)换成了systemd
,当然systemd
相比于旧的init系统更加灵活和高效,所以本文介绍一下systemd的常用命令。目前已经切换为systemd的常见发行版有:Ubuntu 15.04、Debian 8、CentOS 7、Fedora 15及其这些发行版的高版本。本文使用的是Ubuntu 16.04 LTS,用户为root,非root执行时需要加sudo.当然最全的文档还是man文档,所以细节可以查看man文档。本文主要包括三部分:
- systemctl常用命令,很多情况下我们会使用systemctl来管理自己的系统就够了。
- systemd的文件语法介绍,有兴趣的可以了解一下。
systemd管理的基本对象称之为unit
,这个unit可以是很多类型,,比如.service
、.socket
、.device
、.mount
、.swap
、.automount
等,其实任何系统知道如何操作和管理的资源systemd都可以去管理。不过我们最常见的类型是service
(一般后缀为.service
),本文第二部分的学习总结也主要是这个,所以本文提到的unit和服务指的是同一个东西,不再细分。本文中所。当然,systemd和upstart的区别本文没有涉及,这里推荐一篇文章,有兴趣的可以看一下:《浅析 Linux 初始化 init 系统,第 3 部分: Systemd》。
systemctl常用命令
我们主要使用systemctl
命令来管理使用systemd的系统,下面以nginx
为例进行说明。先安装一个nginx:
apt install nginx # Ubuntu 16.04开始不需要使用apt-get了
装好以后,我们就可以使用systemctl来管理nginx服务了:
服务的启动、停止、重启、重新加载配置文件依次为
start
、stop
、restart
、reload
:systemctl start/stop/restart/reload nginx.service
开机自启/关闭开机自启动分别为
enable
和disable
:systemctl enable/disable nginx.service
列出所有已经启动(active)的unit,即已经被加载到内存的unit:
systemctl list-units
当然可以省略掉
list-units
,因为systemctl默认就执行的是上述命令。如果想查看所有的已启动和未启动的unit(已加载到内存,但未启动),在后面加上--all
即可。列出系统已经安装的所有unit,包括那些没有被加载到内存的unit:
systemctl list-unit-files
journald
是systemd
中专门收集日志的模块,我们可以用他来查看日志。
查看所有日志(从最旧的开始显示):journalctl
如果
journald
配置了保存上次启动的日志的话, 这个默认显示的自系统上次启动到现在的所有日志。有的发行版可能没有配置(比如我现在正在用的Ubuntu 16.04,其他的不知道),我们可以在/etc/systemd/journald.conf
中将Storage
设置为persistent
,或者创建/var/log/journal
目录。当然如果我们只想查看本次启动之后的日志,可以加上-b
标志:journalctl -b
如果只想查看内核日志的话,可以加上
-k
(可以和-b
联合使用):journalctl -k
查看unit的状态:
systemctl status nginx.service
查看服务的日志:
journalctl -u nginx.service # 还可以配合`-b`一起使用,只查看自本次系统启动以来的日志
查看unit文件等信息:
# 查看unix文件 systemctl cat nginx.service # 查看unit所有依赖 systemctl list-dependencies nginx # 递归的列出所有依赖 systemctl list-dependencies --all nginx.service # 列出unit的详细信息 systemctl show nginx.service
修改unit文件:
systemctl edit nginx.service
这样会创建一个新的配置文件,我们做的修改会覆盖默认的。当然我们想直接修改原来的配置文件的话,可以加上
--full
参数。必须注意的是,如果修改了unit文件,一定要执行systemctl daemon-reload
让修改的配置生效。使用
Target
。我们都知道Linux有个运行级别(Runlevel),对应不同的模式,比如Ubuntu一般运行在5上面。在systemd中,这个运行级别就是Target
:# 查看所有target下的unit systemctl list-unit-files --type=target # 查看默认target,即默认的运行级别。对应于旧的`runlevel`命令 systemctl get-default # 设置默认的target systemctl set-default multi-user.target # 查看某一target下的unit systemctl list-dependencies multi-user.target # 切换target,不属于新target的unit都会被停止 systemctl isolate multi-user.target
管理主机:
systemctl poweroff # 关机 systemctl reboot # 重启 systemctl rescue # 进入rescue模式
systemd的配置文件
文件位置
这里我们先要说明一下unit的文件位置,一般主要有三个目录:
- /lib/systemd/system
- /run/systemd/system
- /etc/systemd/system
这三个目录的配置文件优先级依次从低到高,如果同一选项三个地方都配置了,优先级高的会覆盖优先级低的。系统安装时,默认会将unit文件放在/lib/systemd/system目录。如果我们想要修改系统默认的配置,比如nginx.service,一般有两种方法:
- 在
/etc/systemd/system
目录下创建nginx.service文件,里面写上我们自己的配置。 - 在
/etc/systemd/system
下面创建nginx.service.d
目录,在这个目录里面新建任何以.conf
结尾的文件,然后写入我们自己的配置。推荐这种做法。
/run/systemd/system
这个目录一般是进程在运行时动态创建unit文件的目录,一般很少修改,除非是修改程序运行时的一些参数时,即Session级别的,才在这里做修改。
文件语法
上面我们安装了nginx,其实装完以后就会在/lib/systemd/system
有一个nginx.service
文件,内容如下:
# Stop dance for nginx
# =======================
#
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
# and sends SIGTERM (fast shutdown) to the main process.
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
#
# nginx signals reference doc:
# http://nginx.org/en/docs/control.html
#
[Unit]
Description=A high performance web server and a reverse proxy server
After=network.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
[Install]
WantedBy=multi-user.target
unit文件由一些Section组成,Section的名字用中括号括起来,而且是区分大小写的。每个Section的作用域到下一个Section开始或者到文件尾。Section的通用格式如下:
[Section]
Directive1=value
Directive2=value
. . .
虽然Section之间是没有先后顺序之分的,但unit文件一般都把[Unit]
作为第一部分(Section),[Install]
作为最后一部分,然后中间是每种类型特性的部分,比如Service
就是[Service]
,当然我们也可以自定义自己的Section,不过需要在前面加上X-
前缀。本文就只介绍Service这种类型的,下面依次介绍。
[Unit]
Unit一般是第一部分,用来描述unit文件元数据以及服务的依赖关系。常用的命令有:
Description=
:这里一般写服务简短的描述。Documentation=
:这里一般是服务文档的链接等。Requires=
:这里写本服务依赖的其他服务,启动本服务时,一般会并行的启动该服务和它所依赖的服务,如果它依赖的服务启动失败了,本服务将无法启动成功。Wants=
:这个命令和Requires=
类似但是相对宽松一些,即使依赖的服务启动失败了,本服务也可以继续正常启动。一般的依赖都推荐使用这个命令。BindsTo=
:和Requires=
类似,但是如果依赖的服务停止了,本服务也会停止。Before=
和After=
:这两个需要和上面描述依赖关系的命令一起使用,表示依赖的当前服务与依赖的服务启动的先后顺序:Before=
表示当前服务启动成功后才可以启动依赖服务,After=
相反。Conflicts=
:这个命令后面跟的服务将不能和当前服务同时运行,如果当前服务运行则会导致该命令列举的服务被停止。Condition...=
:这个命令往往和许多其他命令一起使用,用来测试一些条件,比如测试当前的操作系统。如果条件不满足,则跳过当前服务的启动。Assert...=
:和Condition...=
类似,但是如果条件检测不满足会导致失败。
[Install]
Install一般是最后一部分,用来描述unit的行为或者是否开机自启动等,是可选的。而且只有可以开机自启的(即可以被enable)的才会有这个Section。一般常用的命令有:
WantedBy=
:这个命令是最通用的用来指定服务如何被enable,即在哪些target/runlevel下被设置为开机自启动。我们可以通过这个命令来指定服务捡的依赖关系,有点像[Unit]部分的Wants=
,但是这个只是辅助性的。当一个unit被enable后,就会在/etc/systemd/system
目录下创建以.wants
为后缀的目录,比如当前unit文件里面写了WantedBy=multi-user.target
,那么enable当前unit后,就会在/etc/systemd/system
目录下创建multi-user.target.wants
目录,并且将当前unit及其依赖的unit的符号链接放在新创建的目录里面。disable该unit之后,它的软连接及其依赖的unit的软连接都将被删除。RequiredBy=
:和WantedBy=
类似,但是它指定的依赖条件如果不满足,就会导致服务启动失败。如果enable的话,创建的是.requires
结尾的目录。Alias=
:给服务创建别名。Also=
:将多个unit设置为一个组,可以一起操作。
[Service]
我们之前说了,unit对象有很多种类型,其中device
,target
,snapshot
,scope
这几种类型没有对应该类型的Section,其他的都有,比如service
这种类型特有的section就是[Service],也就是本节要介绍的。[Service]有一个必须的命令就是Type
,它根据进程的行为将服务分为好多类别,不同的类别管理不是不太一样:
simple
:这种是最普遍的类型,在启动行(使用ExecStart=
指定)指定进程,如果Type=
和Busname=
没有设置,但是ExecStart=
却指定了的话,那默认就是这种类型。forking
:这种类别指的是那种fork出来子进程后,父进程就马上退出的情况。这种类型下,父进程退出后,systemd仍然认为进程是OK的。而且可以使用PIDFile=
命令来指定存放主子进程pid的文件。Nginx就属于这种类型。oneshot
:这种一般用在存活时间不长的一次性任务的进程上,它告诉systemd应该等待进程退出后再接着去处理其它的unit。dbus
:这种类别的告诉systemd该unit会在D-Bus上面获取一个名字。notify
:这种类别的服务会在启动完之后发出一个消息,systemd必须等到接收到这个消息后才可以接着去处理其它unit。idle
:这种类别表示在收到所有任务前,服务都不会运行。
OK,上面就是Type=
可取得值。下面介绍除Type=
以外的其他命令:
ExecStart=
:用来指定进程文件(必须是绝对路径)和启动参数,一般该命令只能指定一次。有一个特殊的用法就是比如其他文件里面已经设置了,我们现在想在优先级更高的地方覆盖它,就可以先写一行ExecStart=
(前面的表示清空之前的设置),然后再在另外一行写上完整的命令ExecStart=***
。另外,如果在命令之前加上-
的话表示进程如果以非0退出,也不算失败。ExecStartPre=
和ExecStartPost=
:看名字就看出来了,通过这两个指令可以指定在进程运行前和运行后执行的命令,同样也可以加-
,表示接受非0的退出状态。ExecReload=
:重新加载服务的配置。ExecStop=
:指定停止服务的命令,如果未指定,服务停止后将使用kill来杀掉进程。ExecStopPost=
:指定服务停止后运行的命令。RestartSec=
:如果服务的自动重启设置了的话,这个命令指定多久重启。Restart=
:指定systemd在何种状态下重启服务,可用值有:"always", "on-success", "on-failure", "on-abnormal", "on-abort", "on-watchdog".TimeoutSec=
:指定systemd在标记服务失败多久前强制杀掉进程。也可以分别指定TimeoutStartSec=
和TimeoutStopSec=
。
更多systemd和systemctl的信息可以查看Linux man文档。
参考:
确实有用啊
:mrgreen: