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つずつ開始しました。これはほとんどテストされていません(一度実行したが、問題のサービスで予想通りにクラッシュしました)。
#!/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
追加依存関係の追加
次のスクリプトは、特定のターゲットの直接の依存関係であるシステムユニットに対する「以前の」依存関係を宣言し、特定の順序で実行されるようにします。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