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

相關內容