systemd:序列化启动

systemd:序列化启动

我的 Ubuntu 17.04 启动失败,我想调试它。

启动随机失败,我相信这是由于竞争条件造成的。

我可以要求systemd不要并行化任何任务,这样我就可以看看这是否会导致引导失败?

答案1

解决方法:手动运行服务

我曾有一个启动时崩溃。就我而言,崩溃是在达到basic.target目标之后但之前multi-user.target,所以我想找出哪个服务启动multi-user.target导致了崩溃。

首先,我安排启动以basic.target添加 root shell。您可以永久执行此操作(假设您成功启动!)

systemctl set-default basic.target
systemctl enable debug-shell

debug-shell服务在 tty 9 上运行 root shell。

systemd.unit=basic.target systemd.debug-shell通过在内核命令行中添加参数可以获得相同的效果。例如,在 Grub 中,将命令行编辑为类似的内容

linux /vmlinuz-4.13.0-38-generic root=/dev/mapper/crypt-root ro systemd.unit=basic.target systemd.debug-shell

在这个 shell 中,我运行了以下脚本来一一启动服务。请注意,这在很大程度上未经测试(我运行了一次,它在有问题的服务上按预期崩溃了)。

#!/bin/sh
wants=$(systemctl show -p Wants multi-user.target | sed 's/^Wants=//' | tr ' ' '\n' | sort)
log=/var/tmp/multi-user-steps-$(date +%Y%m%d-%H%M%S)

log () {
  echo "$* ..." | tee -a "$log"
  sync
  "$@"
  ret=$?
  echo "$* -> $ret" | tee -a "$log"
  sync
  return $ret
}

# systemd services
for service in $wants; do
  log systemctl start $service
  sleep 2
done

# upstart services
for conf in /etc/init/*.conf; do
  service=${conf##*/}; service=${service%.conf}
  log service ${service} start
  sleep 2
done

# sysvinit services
for service in /etc/rc3.d/S*; do
  log ${service} start
  sleep 2
done

添加额外的依赖项

下面的脚本声明了对 systemd 单元的“之前”依赖关系,这些单元是给定目标的直接依赖关系,以强制它们按特定顺序运行。您可能想在multi-user.target或上运行它basic.target

注意这个脚本一般不起作用因为它没有考虑现有的依赖关系:它可能会导致依赖循环。正确的脚本应该收集现有的依赖关系并进行拓扑排序。我已经解决了我的问题,所以我不想再继续解决它了;我将其发布,以防有​​人想要对其进行调整以适应他们的需求。

另请注意,这不会影响 Upstart 和 SysVinit 服务。

/etc在运行之前先备份! (我强烈建议使用等等管理员.)

#!/bin/sh
set -e

if [ $# -eq 0 ] || [ "$1" = "--help" ]; then
  cat <<EOF
Usage: $0 TARGET
Linearize the dependencies of a systemd target so it starts deterministically.
This scripts adds systemd unit files called linearize-for*.conf containing
extra Before= dependencies for each dependency of TARGET.
EOF
fi

service_dir=/etc/systemd/system
target=$1

wants=$(systemctl show -p Wants "$target" | sed 's/[^= ]*=//' |
                                            tr ' ' '\n' | sort)
previous=
for want in $wants; do
  [ -d "$service_dir/$want.d" ] || mkdir "$service_dir/$want.d"
  cat <<EOF >"$service_dir/$want.d/linearize-for-${target%.*}.conf"
[Unit]
Before=$previous
EOF
  previous=$want
done

相关内容