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つずつ開始しました。これはほとんどテストされていません(一度実行したが、問題のサービスで予想通りにクラッシュしました)。

#!/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

おすすめ記事