systemd: ブートをシリアル化する

systemd: ブートをシリアル化する

Ubuntu 17.04 の起動に失敗しました。デバッグしたいです。

起動がランダムに失敗しますが、これは競合状態が原因だと考えています。

systemdタスクを並列化しないように依頼して、これによってブートが予想どおりに失敗するかどうかを確認できますか?

答え1

回避策: サービスを手動で実行する

持っていた起動中にクラッシュする私の場合、クラッシュはbasic.targetターゲットに到達した後、 の前に発生したmulti-user.targetため、 によって開始されたサービスのどれがmulti-user.targetクラッシュの原因であるかを知りたいと思いました。

まず、ルートシェルを起動するように設定しましたbasic.target。これを永続的に実行できます(起動できればの話ですが)。

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

サービスdebug-shellは tty 9 でルート シェルを実行します。

カーネルコマンドラインにパラメータを追加することで、同じ効果を得ることができます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

このシェルから、次のスクリプトを実行して、サービスを 1 つずつ開始しました。これはほとんどテストされていないことに注意してください (1 回実行したところ、問題のあるサービスで予想どおりクラッシュしました)。

#!/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 ユニットに「Before」依存関係を宣言します。 または で実行することをお勧めし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

関連情報