在 systemd 中调试订购周期的通用方法

gal*_*ets 28 systemd

我知道以下线程,并且据说是对它回答。除了答案不是一般意义上的答案。它说明了某个特定情况下的问题,但不是一般情况下的问题。

我的问题是:有没有办法以通用方式调试订购周期?例如:是否有一个命令来描述循环以及什么将一个单元与另一个单元联系起来?

例如,我有以下内容journalctl -b(请忽略日期,我的系统没有可与之同步时间的 RTC):

Jan 01 00:00:07 host0 systemd[1]: Found ordering cycle on sysinit.target/start
Jan 01 00:00:07 host0 systemd[1]: Found dependency on local-fs.target/start
Jan 01 00:00:07 host0 systemd[1]: Found dependency on cvol.service/start
Jan 01 00:00:07 host0 systemd[1]: Found dependency on basic.target/start
Jan 01 00:00:07 host0 systemd[1]: Found dependency on sockets.target/start
Jan 01 00:00:07 host0 systemd[1]: Found dependency on dbus.socket/start
Jan 01 00:00:07 host0 systemd[1]: Found dependency on sysinit.target/start
Jan 01 00:00:07 host0 systemd[1]: Breaking ordering cycle by deleting job local-fs.target/start
Jan 01 00:00:07 host0 systemd[1]: Job local-fs.target/start deleted to break ordering cycle starting with sysinit.target/start
Run Code Online (Sandbox Code Playgroud)

其中 cvol.service (被引入并打破循环的那个)是:

[Unit]
Description=Mount Crypto Volume
After=boot.mount
Before=local-fs.target

[Service]
Type=oneshot
RemainAfterExit=no
ExecStart=/usr/bin/cryptsetup open /dev/*** cvol --key-file /boot/***

[Install]
WantedBy=home.mount
WantedBy=root.mount
WantedBy=usr-local.mount
Run Code Online (Sandbox Code Playgroud)

根据 journalctl,cvol.service 需要 basic.service,但它没有,至少不是很明显。是否有一个命令可以演示此链接的来源?一般来说,是否有一个命令可以找到循环并显示循环中每个链接的来源?

Evg*_*gin 27

您可以用可视化的命令周期systemd-analyze verifysystemd-analyze dotGraphViz的 dot工具:

systemd-analyze verify default.target |&
perl -lne 'print $1 if m{Found.*?on\s+([^/]+)}' |
xargs --no-run-if-empty systemd-analyze dot |
dot -Tsvg >cycle.svg
Run Code Online (Sandbox Code Playgroud)

您应该会看到如下内容:

在此处输入图片说明

在这里你可以看到循环: c.service->b.service->a.service->c.service

Color legend: 
    black     = Requires
    dark blue = Requisite
    dark grey = Wants
    red       = Conflicts
    green     = After
Run Code Online (Sandbox Code Playgroud)

链接:

  • `systemd-analyze verify default.target` 本身在显示循环方面做得不错...... (3认同)

int*_*lfx 26

是否有一个命令可以演示此链接的来源?

您可以做的最接近的是systemctl show -p Requires,Wants,Requisite,BindsTo,PartOf,Before,After cvol.service,它将显示给定单元的结果(有效)依赖项列表。

是否有一个命令可以找到循环并显示循环中每个链接的来源?

据我所知,没有这样的命令。实际上 systemd 没有提供任何帮助调试订购周期(叹气)。

根据 journalctl,cvol.service 需要 basic.service,但它没有,至少不是很明显。

首先,要求依赖(Wants=Requires=BindsTo=等等)是独立的顺序依赖(的Before=After=)。你在这里看到的是一个排序依赖循环,即它与其他无关Wants=

其次,在某些类型的单元之间创建了许多“默认依赖关系”。它们由部分中的DefaultDependencies=指令控制[Unit]默认情况下启用)。

特别是,除非显式禁用此指令,否则任何.service-type 单元都会获得隐式Requires=basic.targetAfter=basic.target依赖项,这正是您所看到的。这记录在systemd.service(5) 中

  • @galets:从我的经验来看,这种短缺的例子很少……也许有一天我会绕过增加循环报告器的冗长,在日志中添加一些有用的信息。同时,实际上,您可以使用`systemd-analyze verify UNIT`来检查单元的正确性。在幕后,这个命令创建了一个虚拟的 systemd 实例并尝试加载给定的 UNIT 作为初始事务(就像它是 `default.target`)。这不会显示任何新信息(与日志相比),但至少您不必在启用设备的情况下重新启动以查看它是否失败。 (2认同)

Ole*_*rin 5

步骤1:对default.target运行验证命令

systemd-analyze verify default.target
Run Code Online (Sandbox Code Playgroud)

步骤 2:观察“systemd 通过删除作业打破排序周期”消息中提到的服务或目标,并显示其完整的依赖项列表

systemctl show -p Requires,Wants,Requisite,BindsTo,PartOf,Before,After <service or target name mentioned in the "breaking cycle" message>
Run Code Online (Sandbox Code Playgroud)

步骤 3:查看服务或目标文件中通常定义的“after”和“before”组

/lib/systemd/system
Run Code Online (Sandbox Code Playgroud)

并找到已知是连续的但按出站顺序排列的服务或目标。

例子:

dbus.service
Run Code Online (Sandbox Code Playgroud)

通常标记为“之后”

multi-user.target
Run Code Online (Sandbox Code Playgroud)

“之前”

sockets.target
Run Code Online (Sandbox Code Playgroud)

通过调用可以轻松观察到这种依赖性

systemctl list-dependencies default.target
Run Code Online (Sandbox Code Playgroud)

但是如果文件

/lib/systemd/system/dbus.service
Run Code Online (Sandbox Code Playgroud)

包含如下行:

Before=multi-user.target
Run Code Online (Sandbox Code Playgroud)

或者

After=sockets.target
Run Code Online (Sandbox Code Playgroud)

或两者同时,意味着 dbus.service 被定义为出站,并导致 systemd 无限循环。

治疗方法很简单 - 将“之后”一词改为“之前”,如有必要,反之亦然。