@Tmacy
2018-09-03T05:42:30.000000Z
字数 11882
阅读 2681
systemd
linux
Systemd是Linux系统中最新的初始化系统(init)。它主要是用来取代笨重的sysvinit的。Systemd提供了一整套系统管理套件,完全接管了整个系统的运行管理。
Systemd相比传统的Sysvinit,具有很大的优势。它提供了更快的系统启动速度,更方便的服务管理,满足按需启动服务的需求。它还可以提供事务依赖性管理,挂载点管理,日志管理,容器管理等多种功能。
本文会简略举例介绍Systemd对于系统管理各方面的工具的使用。Systemd的原理等细节,请参考附录。
Systemd可以并行的启动服务进程,并且只有必须的服务会被启动,极大的减少了系统引导时间。
查看系统引导用时:
>systemd-analyze
Startup finished in 5.524s (kernel) + 22.232s (userspace) = 27.756s
systemd-analyze
是用来衡量系统引导的性能,检索其他状态以及追踪系统和服务管理器的信息,来确认单元文件的正确性。输出可以看出,启动时间分为内核态占用时间以及用户态占用时间。
实际上,该输出也是systemd-analyze time
的输出。systemd-analyze time 输出了内核启动时间,初始化RAM磁盘的时间以及用户空间启动的时间。 要注意的是,这个时间是简单统计了所有服务开始启动的时间,不代表他们完全初始化完成。
systemd-analyze blame
命令是用来列出所有运行的单元,并以初始化时间来排序。注意,你很可能会误解这个启动时间,因为它可能会等待其他服务启动完成。
systemd-analyze blame
12.626s dev-sda4.device
8.246s accounts-daemon.service
7.862s irqbalance.service
6.855s saslauthd.service
6.333s systemd-logind.service
6.171s systemd-user-sessions.service
6.169s console-setup.service
5.885s sysstat.service
5.812s alsa-restore.service
5.811s gpu-manager.service
5.809s rsyslog.service
5.751s hostapd.service
5.751s rc-local.service
5.728s avahi-daemon.service
(输出已精简)
systemd-analyze critical-chain [UNIT...]
输出一个单元精确的时序链:
wpa_supplicant.service +1.448s
└─basic.target @8.248s
└─sockets.target @8.248s
└─avahi-daemon.socket @8.248s
└─sysinit.target @8.206s
└─sys-fs-fuse-connections.mount @16.945s
└─systemd-modules-load.service @2.032s +707ms
└─system.slice @1.993s
└─-.slice @1.878s
在@符号后的时间表示该单元激活或启动的时间,而+号后面是该单元所花费的时间。注意不要被这个时间误导,因为有的服务初始化会依赖套接字激活,或者被并行处理了。
systemd-analyze plot
可以输出svg格式的图像,显示每个服务的启动时间。
systemd-analyze dump
可以输出完整可读的服务状态。输出会非常长。
systemd-analyze verify
可以加载单元文件并且输出错误信息。命令行中的文件会被加载,以及其引用的其他单元。这个工具可以用来检测你写的单元是否有语法错误。
以下大写的为参数,省略号表示多个参数
systemctl list-units
或者systemctl
都可以列出正在运行的单元,包括service,mount,target,socket等
对于运行失败的单元,可以用systemctl --failed
来显示。
查看已知的单元:systemctl list-units
列出一直的单元,-t参数可以限制类型,例如-t service,表示仅列出服务。
查看套接字单元:systemctl list-sockets
查看定时器单元:systemctl list-timers
查看单元状态:systemctl status NAME...
启动单元:systemctl start NAME...
停止单元:systemctl stop NAME...
重启单元:systemctl restart NAME...
重新加载单元配置,而不重启:systemctl reload NAME...
检查指定单元是否处于活动状态:systemctl is-active NAME...
检查指定单元是否处于失败状态:systemctl is-failed NAME...
显示单元的属性以及值:systemctl show NAME...
该命令不适合人类阅读,可以用于程序分析。
查看指定单元的文件内容:systemctl cat NAME...
显示单元的依赖关系:systemctl list-dependencies NAME...
显示单元的依赖关系,也就是显示 Requires=, RequiresOverridable=, Requisite=, RequisiteOverridable=, Wants=, BindsTo= 所形成的依赖关系。如果没有明确指定单元的名称,则表示显示 default.target 的依赖关系树。
孤立单元:systemctl isolate NAME...
所谓孤立单元,表示启动指定的单元以及该单元的所有依赖单元,同时停止所有其他单元。如果没有给出单元的后缀名,那么视为以".target"作为后缀名。该命令将会立即停止所有在新的目标单元中不需要的进程,这其中有可能包含当前正在运行的图形环境以及正在使用的终端。
注意:该命令仅用于AllowIsolate=true的单元。
列出已安装的单元文件以及启用状态:systemctl list-unit-files
启动与激活单元文件,使得在开机时运行:systemctl enable NAME...
这将会按照单元文件中"[Install]"小节的指示,在单元配置目录中创建指向所列单元文件的软链接。创建完软连接之后,systemd 将会重新加载自身的配置(相当于执行daemon-reload命令)以确保所做的变更立即生效。除非使用了--now选项(相当于额外再执行start命令),否则启用单元文件并不会导致该单元被启动。注意,对于单元实例,软链接自身的文件名是实例化之后的名称,但是所指向的目标文件则是该单元的模板文件。
除非使用了 --quiet 选项,否则此命令会打印出所执行的动作。
不要将 enable 命令与start命令混淆,它们是相互独立的命令:可以启动一个尚未启用的单元,也可以启用一个尚未启动的单元。enable命令只是设置单元的启动钩子(通过创建软链接),例如在系统启动时或者某个硬件插入时。而 start命令则是执行单元的具体动作,例如对于服务单元来说是启动守护进程,而对于套接字单元来说则是绑定套接字
若与 --user选项连用,则表示变更仅作用于用户实例,否则默认作用于系统实例(相当于使用 --system 选项)。
若与 --runtime选项连用,则表示仅作临时性变更(重启后所有变更都将丢失),否则默认为永久性变更。
若与 --global选项连用,则表示变更作用于所有用户(在全局用户配置目录上操作),否则默认仅作用于当前用户。
注意,当与--runtime选项连用时,systemd守护进程不会重新加载配置。
禁用单元,与激活相对:systemctl disable NAME...
禁用指定的单元文件。这将会从单元配置目录中删除所有指向所列单元文件的软链接(包括手动创建的软链接)。删除完软连接之后,systemd将会重新加载自身的配置(相当于执行daemon-reload命令)以确保所做的变更立即生效。其他选项与enable类似
检查单元是否已被激活启用:systemctl is-enabled NAME...
检查是否有至少一个指定的单元文件已经被启用。
如果有至少一个单元文件已经被启用,那么返回"0",否则返回非零。
除非使用了 --quiet选项,否则此命令会打印出指定的单元文件的当前启用状态:
状态列表
返回值 | NAME | 含义 |
---|---|---|
0 | "enabled" | 已经通过 /etc/systemd/system/ 下的 .requires/ 或 .wants/ 目录中的软链接被永久启用 |
0 | "enabled-runtime" | 已经通过 /run/systemd/system/ 下的 .requires/ 或 .wants/ 目录中的软链接被临时启用 |
大于零 | "linked" | 虽然单元文件尚不在搜索目录中,但指向此单元文件的软连接已经存在于 /etc/systemd/system/ 目录中 |
大于零 | "linked-runtime" | 虽然单元文件尚不在搜索目录中,但指向此单元文件的软连接已经存在于/run/systemd/system/ 目录中 |
大于零 | "masked" | 已经被 /etc/systemd/system/ 目录永久屏蔽,因此 start 操作会失败 |
大于零 | "masked-runtime" | 已经被 /run/systemd/systemd/ 目录临时屏蔽,因此 start 操作会失败 |
0 | "static" | 尚未被启用,且"[Install]"小节中没有可用于 enable 命令的选项 |
0 | "indirect" | 尚未被启用,但"[Install]"小节中 Also= 选项的值列表非空(其中的某些单元可能已被启用) |
大于零 | "disabled" | 尚未被启用,但"[Install]"小节中存在可用于 enable 命令的选项 |
大于零 | "bad" | 单元文件不正确或者出现其他错误。is-enabled 不会返回此状态,而是会显示一条出错信息。list-unit-files 命令有可能会显示此单元。 |
屏蔽单元:systemctl mask NAME...
屏蔽指定的单元文件。也就是将这些单元文件指向/dev/null 文件,以从根本上确保这些单元无法被启动。
这比 disable 命令禁用的更彻底,可以通杀一切启动方法(包括手动启动),所以应该谨慎使用该命令。
若与 --runtime选项连用,则表示仅作临时性屏蔽(重启后屏蔽将失效),否则默认为永久性屏蔽。
除非使用了 --now选项(相当于额外再执行stop命令),否则仅仅屏蔽单元文件并不会导致该单元被停止。
解除屏蔽:systemctl unmask NAME...
解除对单元文件的屏蔽
获得默认启动目标:systemctl get-default
返回默认的启动目标
设置默认启动目标:systemctl set-default NAME
systemctl list-machines NAME...
列出主机和所有运行的本地容器,以及他们的状态。该命令需要root权限。
systemctl show-environment
显示systemd环境变量以及值。这些环境变量会被传递给所有由systemd所派生的进程。
systemctl set-environment VARIABLE=VALUE...
设置环境变量
systemctl unset-environment VARIABLEE...
撤销指定的环境变量。如果仅仅指定了变量名,那么表示无条件的撤消该变量(无论其值是什么)。如果以VARIABLE=VALUE 格式同时给出了变量值,那么表示仅当VARIABLE的值恰好等于 VALUE 时,才撤消 VARIABLE 变量。
systemctl is-system-running
检查当前系统是否处于正常运行状态。所谓正常运行状态是指:系统完成了全部的启动操作,整个系统已经处于完全可用的状态,特别是没有处于启动/关闭/维护状态,并且没有任何单元处于失败(failed)状态。
状态 | 含义 |
---|---|
initializing | 启动的早期阶段。也就是尚未到达 basic.target/rescue.target/emergency.target 之前的阶段。 |
starting | 启动的晚期阶段。也就是任务队列首次达到空闲之前的阶段,或者进入了某个救援 target 中。 |
running | 完成了全部的启动操作,整个系统已经处于完全可用的状态,并且没有任何单元处于失败(failed)状态。 |
degraded | 完成了全部的启动操作,系统已经可用,但是某些单元处于失败(failed)状态。 |
maintenance | 进入了 rescue.target/emergency.target 状态中。 |
stopping | 系统正处于关闭过程中。 |
offline | 整个系统已经处于完全可用的状态,但init进程(PID=1)不是systemd |
unknown | 由于资源不足或未知原因,无法检测系统的当前状态 |
systemctl default
进入默认模式,差不多相当于systemctl isolate default.target
systemctl rescue
进入救援模式。差不多相当于执行systemctl isolate rescue.target
命令
systemctl emergency
进入维护模式。差不多相当于执行systemctl isolate emergency.target
systemctl halt
systemctl poweroff
systemctl reboot
halt
关闭系统,但不切断电源。差不多相当于执行"systemctl start halt.target --job-mode=replace-irreversibly"命令。若使用了 --force 选项,则跳过服务的正常关闭步骤而直接杀死所有进程,强制卸载所有文件系统(或只读挂载),并立即关闭系统。若使用了两次 --force 选项,则跳过杀死进程和卸载文件系统的步骤,并立即关闭系统,这会造成数据丢失或损坏。
poweroff
关闭系统,同时切断电源。差不多相当于执行"systemctl start poweroff.target --job-mode=replace-irreversibly"命令。--force选项与halt相同
reboot
关闭系统,然后重新启动。差不多相当于执行"systemctl start reboot.target --job-mode=replace-irreversibly"命令。--force选项与halt相同。
systemctl suspend
休眠到内存
systemctl hibernate
休眠到硬盘
systemctl hybrid-sleep
进入混合休眠模式,同时休眠到内存与硬盘。
jounald是systemd中独有的日志系统,它汇总了所有系统的日志信息。
查看系统日志:journalctl
查看本次引导的信息:journalctl -b
动态查看日志(类似tail -f):journalctl -f
查看指定程序的日志:journalctl /usr/bin/startdde
查看指定服务的日志:journalctl -u NetworkManager.service
一些有用的参数:
systemd 的其中一部分是systemd-networkd,它负责systemd中的网络配置。使用systemd-networkd,你可以为网络设备配置基础的DHCP/静态 IP网络。它还可以配置虚拟网络功能,例如网桥、隧道和VLAN。systemd-networkd目前还不能直接支持无线网络,但你可以使用wpa_supplicant 服务配置无线适配器,然后把它和systemd-networkd联系起来.
Network文件分别位于系统网络目录(/usr/lib/systemd/network)、运行时网络目录(/run/systemd/network)、本机网络目录(/etc/systemd/network)。/etc目录的优先级最高、/run目录的优先级居中、/usr/lib目录的优先级最低。有三种配置文的类型:.link,.netdev和.network。可以通过查阅man手册的systemd-link(5),systemd-netdev(5)和systemd-network(5)可以获得更多关于这些配置文件的详细介绍。
使用systemd管理network,需要的服务有两个
systemd-networkd.service
systemd-resolved.service
你可以使用start来启动服务,或者用enable来启用激活服务。
# cat /etc/systemd/network/10-static-eth0.network
[Match]
Name=eth0
[Network]
Address=192.168.0.2/24
Gateway=192.168.0.1
DNS=192.168.0.1
当然可以指定多个DNS条目。
udev 可能根据你电脑的物理设备特性将网卡接口设置为不同的名称,比如 enp2s1。如果你不能确定你的网卡名称,可以在系统启动后执行 ip link 命令查看
Network文件中的"[Match]"小节决定了应该匹配哪个网卡,而"[Network]"小节则决定了应该怎样配置匹配的网卡。如果"[Match]"小节中的每一项都与某个网卡匹配("[Match]"小节为空也视为匹配),那么视为该Network文件与该网卡匹配。所有可用于匹配的选项参考文档。
如果有多个Network文件匹配同一个网卡,那么以第一个匹配的Network文件为准(按Network文件名的字典顺序)。文件 "10-static-enp3s0.network" 在 "20-dhcp.network" 之前被处理。
# cat /etc/systemd/network/10-dhcp-eth0.network
[Match]
Name=eth0
[Network]
DHCP=yes
# Begin /etc/resolv.conf
domain <Your Domain Name>
nameserver <IP address of your primary nameserver>
nameserver <IP address of your secondary nameserver>
# End /etc/resolv.conf
domain 声明可以忽略或者以search声明替换。参考man手册的resolv.conf部分获得更多信息。<IP address of the nameserver>
替换为最合适的DNS的IP地址。通常会有多个条目(需要备选服务器具有相关兼容性)。如果你只需要一台DNS服务器,请不要输入第二行nameserver的内容。该 IP 地址也可以是本地网络中的一台路由。
当使用 systemd-networkd配置网络,另一个守护进程systemd-resolved将会创建/etc/resolv.conf文件。
对于在.network文件中指定了DNS或者使用内置DHCP客户端获得DNS这两种情况,必须要做如上操作
$sudo vi /etc/systmd/network/bridge-br0.netdev
[NetDev]
Name=br0
Kind=bridge
然后按照下面的文件配置网桥接口br0和从接口eth1
$sudo vi /etc/systemd/network/bridge-br0-slave.network
[Match]
Name=eth1
[Network]
Bridge=br0
$ sudo vi /etc/systemd/network/bridge-br0.network
[Match]
Name=br0
[Network]
Address=192.168.10.100/24
Gateway=192.168.10.1
DNS=8.8.8.8
之后重启systemd-networkd
sudo sytemctl restart systemd-networkd
可以用brctl show
工具来验证是否创建好了网桥br0
wpa_supplicant@wlp2s0.service
$ vi /etc/systemd/network/wireless.network
[Match]
Name=wlp2s0
[Network]
DHCP=ipv4
如果需要静态地址,可以按照上面的介绍进行配置。
# vi /etc/systemd/network/wired.network
[Match]
Name=enp1s0
[Network]
DHCP=ipv4
[DHCP]
RouteMetric=10
# vi /etc/systemd/network/wireless.network
[Match]
Name=wlp2s0
[Network]
DHCP=ipv4
[DHCP]
RouteMetric=20
systemd的定时器是指以".timer"结尾的单元文件,封装了一个由 systemd 管理的定时器,以支持基于定时器的激活。
每个.timer文件所在目录都得有一个对应的.service文件(如foo.timer 和 foo.service)。.timer 用于激活并控制 .service 文件。 .service 文件中不需要包含 [Install] 部分,因为这由timer单元接管。必要时通过在定时器的[Timer]部分指定Unit=选项来控制一个与定时器不同名的服务单元。
即从一个时间点过一段时间后激活定时任务。
我们来利用systemd的定时器来实现单调定时器任务。假设每小时要运行一次/usr/local/bin/mytest.sh
脚本。
首先,我们需要建立一个service文件,你可以放在/etc/systemd/system/目录下,或者/lib/systemd/system/目录下。推荐放在/lib/systemd/system下。
mytest.service
[Unit]
Description=MyTest
[Service]
Type=simple
ExecStart=/usr/local/bin/mytest.sh
注意: 务必要Type变量的值设置为simple而不是oneshot。使用onshot只会让脚本运行一次,系统会关掉下面的定时器。
mytest.timer
[Unit]
Description=Runs mytest every hour
[Timer]
# 首次运行要在启动后10分钟后
OnBootSec=10min
# 每次运行间隔时间
OnUnitActiveSec=1h
Unit=mytest.service
[Install]
WantedBy=multi-user.target
每个定时器单元都必须有一个与其匹配的单元,以用于在特定的时间激活。默认是与该单元名称相同的.service单元。也可以通过Unit=选项明确指定匹配的单元。
启动计时器:systemctl start mytest.timer
引导后启动计时器:systemctl enable mytest.timer
如果你想运行多个脚本:
可以创建一个mytimer.target文件,然后每个service都配置WantedBy=mytimer.target
,并且根据依赖顺序具体指定After=something.service和Before=whatever.service中的参数。
创建一个mytimer.target文件
[Unit]
Description=Mytimer
# Lots more stuff could go here, but it's situational.
# Look at systemd.unit man page.
当然,你也可以写到一个脚本里面,只要你能处理好依赖顺序。
当设置的时间间隔小于1分钟时,需要配置AccuracySec=选项。设置定时器的触发精度。如果不配置,则默认值是一分钟。如果时间间隔较大,可以考虑设置AccuracySec为较大的值,可以省电。具体参考手册(见参考)
定义基于挂钟时间(wallclock)的日历定时器,值是一个日历事件表达式,这是与传统cron任务类似的定时器
定义一个每周执行一次(明确时间为周一上午十二点)且上次未执行就立即执行的定时器。
mytest.timer
[Unit]
Description=Run test weekly
[Timer]
OnCalendar=weekly
Persistent=true
[Install]
WantedBy=multi-user.target
特殊的事件表达式如 daily 和 weekly 表示 特定的启动时间,因此任何共享该日历事件的定时器将同时启动。如果该定时器的服务会计算系统资源,那么定时器共享启动事件可能会引起系统性能下降。可以考虑手动错开该定时器运行特定事件的时间,如 OnCalendar=Wed, 23:15
参考:
systemd.timer中文手册
使用systemd中的定时器
arch wiki的systemd/Timer
systemd很容易实现自动挂载目录
首先,编辑一个.mout文件。要注意的是,该文件名称应与实际的路径相对应,例如要挂载到/home/tmacy/abc目录下,就需要命名为home-tmacy-abc.mount。参考:http://www.jinbuguo.com/systemd/systemd.mount.html
$ sudo vim /usr/lib/systemd/system/home-tmacy-c.mount
[Unit]
Description=Auto mount sdb1
[Mount]
What=/dev/sdb1
Where=/home/tmacy/c
Type=ntfs
然后,systemd提供了automount的文件,用来并发加载和自启动。
手册:http://www.jinbuguo.com/systemd/systemd.automount.html
其内容很简单:
$ vim /usr/lib/systemd/system/home-tmacy-c.automount
[Unit]
Description=Auto mount c
[Automount]
Where=/home/tmacy/c
[Install]
WantedBy=multi-user.target
当不存在目录时,会自动创建目录进行挂载,还可以设定挂载权限以及等待时间。
之后启动服务即可:sudo systemctl enable home-tmacy-c.automount
参考链接:
1. 浅析Linux初始化init系统
2. systemd 中文手册
3. 从NetworkManager切换到systemd-networkd(中文)
4. systemd的网络配置
5. systemd使用简介