Linux アプリケーションの自動起動 Systemd

最終更新日

CentOS7をインストールしたら、SysvinitからSystemdに起動プロセスの仕組みが変わっていたので、調べた内容をメモしておく。

Linux起動プロセスの変更点

Systemdは、Linuxシステムの自動起動の仕組みで、古くから使われていたSysvinitの代替えとして、Fedora15、RHEL7(CentOS7系)から採用されたのがSystemdです。

  1. 電源投入後にBIOSが起動する。
  2. BIOSからブートローダー(GRUB)が呼び出される。
  3. ブートローダー(GRUB)がLinuxカーネルを実行。
  4. Linuxカーネルがinitプロセス(PID1)を起動する。

4番のinitプロセスの起動処理について、古くから使われているsysvinitの代替として、ubuntuではUpstartを採用し、RHEL系ではsystemdが採用されました。

linux起動プロセス
linux起動プロセス

Systemdについて

Systemdとは、すべてのプロセスを起動する役目をもつinitプログラムのひとつで、OS起動時に1番最初に起動され、起動されたsystemdが他のすべてのサービスを起動させます。

また、従来のchkconfigやserviceコマンドは、systemctlというコマンドに集約されています。

Linuxシステム起動時だけではなく、様々なトリガー(特定の条件により発生する)でプロセスの起動が行える。例えばタイマー、ソケット通信検出、ファイルシステムのマウント検出など。また、システム構成の変更に応じて自動的にシステムを変化させることもできる。
例えば、新しいデバイスを検出した際に特定のプロセスを起動するなど。

SysvinitではサービスをPIDによって管理していたが、Systemdではcgroupによって管理している。

PIDの場合、プロセスが2回forkすると親プロセスと孫プロセスの直接的な関係性は切れますが、cgroupの場合複数回のforkが発生しても管理下に置くことが出来ます。

ただし、cgroupはLinuxカーネルの機能であるため、Linux以外では使えません。これがSystemdの制限であり、Linuxカーネル上でのみ動作するようになっています。

シェルスクリプトでは無い

Systemdは、サービスを1つのシェルスクリプトではなくUnitという単位で管理し、設定ファイルとして持ちます。
このため処理を細分化でき個別に実効することが可能です。また処理ごとの依存関係を明確にすることが出来ます。
さらに処理が細分化されているということは、並列での実行も可能になります。
例えばAの処理の後にBとCを並列実行する、というようなきめ細やかな設定が可能になります。

メリット

  • アプリケーションの起動、停止用スクリプトが不要になる。
  • 並列起動処理のため、起動速度が速くなる。
  • 親子関係にあるプロセスの起動・停止制御を行える。
  • 各デーモンのログ出力まとめて管理できる。

ユニットタイプ

systemdでは、「Unit」という単位で処理を管理します。また拡張子で識別されている。

ユニットタイプ解説
automountオートマウント処理を実施する(automountdの代替的な機能)
deviceudevからデバイスを認識すると有効かされる。
mount指定のファイルシステムをマウントする
path指定のファイルが作成されると、指定されたサービスを起動する
service指定のバイナリを実行する(主にはデーモンの起動に使用する)
socketsystemdがSocketをListenして、接続があるとプロセスに受け渡す
(xinetdの代替的な機能)
target何もしない。複数のUnitをグループ化するために使用する

ファイル及びフォルダ構成

ディレクトリ解説
/bin/systemctl操作用のコマンド
/usr/lib/systemd/systemd 本体が格納されているディレクトリ
/usr/lib/systemd/systemd本体
/etc/systemd/system管理者が変更した設定ファイルが置かれるディレクトリ。
また、ここに同名のファイル(/usr/libのシンボリックリンク)を
配置することにより優先される。
/usr/lib/systemd/systemRPMから直接ファイルが提供される場所であり、
デフォルトの設定ファイルが配置されているディレクトリ

コマンド

稼働中のサービス

systemctl list-units --type=service

定義中の一覧

systemctl list-unit-files --type=service

failしたUNITサービス

systemctl --failed
systemctl list-unit-files --type=service | grep -Ev 'static\s+$'

サービス状態

systemctl status sshd
systemctl is-enabled sshd

手動制御


#プロセスを手動で起動
systemctl start Unit名
systemctl start httpd
  
#プロセスを手動で終了
systemctl stop Unit名
systemctl stop httpd
  
#リロード
systemctl reload Unit名
systemctl reload httpd
  
#プロセスを手動で再起動
systemctl restart Unit名
systemctl restart httpd

サービス有効・無効

systemctl enable Unit名
systemctl desable Unit名

ユニットの再読み込み

systemctl daemon-reload ←ユニット設定ファイルをリロード

Unit設定ファイルの記述方法とサンプル

Unitの設定ファイルは、[Unit]、[Install]などのセクションに分かれます。

  • [Unit]:Unitの依存関係・順序関係などUnitのタイプに依存しない設定を記載
  • [Install]:systemclt enable / disableコマンドに関連する設定を記載
  • [Service]:serviceタイプに固有の設定項目を記載

【サンプル】

[Unit]
 Description=My Daemon
  
[Service]
 ExecStart=/myhome/scripts/run.sh
 ExecStop=/bin/kill ${MAINPID}
 Restart=always
 Type=forking
 User=myuser
 Group=mygroup
  
[Install]
 WantedBy=multi-user.target

Unitセクション

属性解説
Requiresこのユニットが強い依存関係を持っているユニット。
このユニットが起動されるとき、設定したユニットも一緒に起動される。
どれか1つが起動に失敗した場合には、すべてのユニットが停止され、
起動に失敗する。
RequiresOverridableRequiresと同様の意味の属性。
ただし、ユーザが手動でユニットを起動した場合には、起動に失敗しても無視される。
Requisiteこのユニットが強い依存関係を持っているユニット。
ただし、このユニットが起動されたときに、
他のユニットがまだ起動されていなければ、直ちにエラー終了
RequisiteOverridableRequisiteと同様の意味の属性。
ただし、ユーザが手動でユニットを起動した場合には、
起動に失敗しても無視される。
Wantsこのユニットが弱い依存関係を持っているユニット。
このユニットが起動されるとき、設定したユニットも一緒に起動される。
依存関係にあるユニットが起動に失敗しても、特に何も行わない。
BindsToRequiresと同様の意味の属性。
ただし、設定したユニットのどれかが突然停止したときんは、
このユニットも停止する。突然の停止とは、デバイスの取り外し、
強制umountなどのsystemdの制御外の停止を意味。
PartOfRequiresと同様の意味の属性。
ただし、設定したユニットを停止したり再起動した場合には、
このユニットにも伝搬する。
逆に、このユニットが停止しても、設定したユニットには伝搬されないので
注意が必要。
Conflicts同時に起動することができないユニットを指定する。
スペース区切りで複数のユニットを設定できる
Before指定したユニットよりも、このユニットを先に起動
After指定したユニットよりも、このユニットを後に起動する。
OnFailureこのユニットがfailed状態になったときに、起動するユニットを指定する。
スペース区切りで複数のユニットを設定できる
PropagatesReloadToこのユニットがreloadされた場合に、設定したユニットにも処理を伝番する。
スペース区切りで、複数のユニットを指定可能
ReloadPropagatedFrom設定したユニットがreloadされた場合に、このユニットにも処理を伝搬する。
スペース区切りで、複数のユニットを指定可能
RequiresMountsForこのユニットの動作に必要なマウントポイントを指定する。
Mountユニットに対する依存関係が自動的に設定される。
OnFailureLsolate論理値。
isolate処理のときに、Onfailer属性で指定したユニットとその依存関係に
あるユニットを起動する。
それ以外のユニットは停止される。
lgnoreOnlsolate論理値。isolate処理のときに、このユニットは無視し、停止処理を行わない。
lgnoreOnSnapshot論理値。このユニットをスナップショットに含めない。
StopWhenUnneeded論理値。依存関係にある他のユニットがすべて停止したら、
このユニットも自動停止する。

Serviceセクション

属性解説
TypeServiceユニットのプロセス起動方法を設定。
RemainAfterExit論理値。
trueの場合には、すべてのプロセスが終了してもサービスが稼働中とする。
GuessMainPID論理値。
trueの場合には、Typeがforkingに設定されているのにPIDFile属性が
設定されていない場合に、メインプロセスのPIDを推測する。
デフォルトTrue
PIDFileデーモンのPIDが保管されるファイルを指定
BusNameD-Busでの名称を設定。Typeがdbusの場合には必須。
Typeがdbusでない場合でも、dbusを使う場合には名称を設定することが
推奨される。
ExecStartサービスを起動するときに使うコマンドとその引数を指定
ExecStartPreExecStartで指定したコマンドを実行する前に、この属性に指定したコマンドを実行
ExecStartPostExecStartで指定したコマンド実行した後に、この属性で指定したコマンドを実行。
TimeoutStartSecサービスの起動待ち時間。この時間を超えても起動処理が終了しない場合には、
サービスの起動が失敗したものとして、停止処理を行う。
0を指定すると、この処理は無効になる。
デフォルトでは、Systemdのデフォルト値に従う。
ただし、Typeがoneshotの場合には、デフォルトではこの処理を行わない。
TimeoutStopSecサービスの停止待ち時間。この時間を越えても停止処理が終了しない場合には、
TERMシグナルを送って停止する。
さらに、しばらく後でKILLシグナルを送って強制的に停止する。
0を指定すると、この処理は無効になる。
デフォルトでは、Systemdのデフォルト値に従う
TimeoutSecTimeoutStartSecとTimeoutStopSecに設定した値を設定する。
WatchdogSecサービスの起動が終わったあと、watchdogタイマーを有効にする。
サービスは、起動処理が終わったあと、sd_notify(3)を使って定期的に
WATCHDOG=1というメッセージを送らなければならない。
設定した時間の間にメッセージが届かない場合には、
サービスはfailed状態になる。
この属性を指定した場合には、NotifyAccess属性にSystemdへの通知に利用する
ソケットを設定しなければならない。
なお、プロセスの起動時にWATCHDOG_USECという環境変数が自動的に
設定される。
そのため、プロセスは環境変数を確認することで、タイマーに設定された時間を
取得できる。
0を指定すると、機能を無効にすることができる。
PermissionsStartOnly論理値。
trueに設定すると、User属性で指定したユーザ権限で行う処理は
ExecStartで指定したコマンドだけに適用される。
Falseに設定すると、ExecStart、ExecStartPre、ExecStartPost、ExecReload、
ExecStop、ExecStopPostの場合にも適用。
デフォルトはfalse
RootDirectoryStartOnly論理値。
Trueに設定すると、RootDirectory属性で指定したディレクトリに
Chrootを行う処理をExecStartの場合だけに適用。
Falseに設定するとExecStartPre、ExecStartPost、ExecReload、ExecStop、
ExecStopPostの場合にも適用
NonBlockingSocketユニットと一緒に使う。
起動処理のときに、すべてのファイルディスクリプタにO_NONBLOCKフラグを設定
NotifyAccesssd_notify(3)で利用する状態通知用のソケットへのアクセスを制御する。
main、all、noneが指定できる。
Mainは、メインプロセスからの通知のみを受け取る。
allは、サービスに関連した制御グループに所属する、どのプロセスからの
通知でも受け取る。
Noneの場合には受け取らない。デフォ=none
SocketsSocketユニットと関連したユニットで、Socketユニットの名前を指定。
指定がない場合には、Serviceユニットの名称から、
.serviceを除き、.socketを付けたものを使う
StartLimitInterval起動制限の基底となる時間間隔を設定
StartLimitBurstStartLimitIntervalで設定した時間の間に許容される起動回数を指定
StartLimitAction起動制限に達したときのアクション指定。
reboot、reboot-force、reboot-immediate、noneが指定できる。
noneの場合には、単純に次の起動が禁止され、処理中のものには影響しない。Rebootを指定すると、システムは停止処理の実行後にrebootする。
reboot-immediateの場合には、停止処理を行わずに直ちにリブートする。
デフォルトはnone

Installセクション

オプション解説
WantedByenable時にこのUnitの.wantsディレクトリにリンクを作成する
Requiredbyenable時にこのUnitの.requiredディレクトリにリンクを作成する

タイプ

タイプ解説
Restartサービスが終了したときに再起動すべきかどうかを設定
RestartSecサービスを再起動するときに、サービスを停止した後に待つ時間を指定する。
デフォルトでは100ms
SuccessExitStatusサービスが終了したときに正常とみなす条件。
終了コードとシグナル名をスペース区切りで指定する。
標準は、「0 SIGHUP SIGINT SIGTERM SIGPIPE」
RestartPreventExitStatus再起動処理を行わない終了条件をスペース区切りで指定。
標準では何も設定されていない。
no再起動処理は行わない
on-successサービスプロセスが正常終了したときだけ、再起動処理を行う。
ただし、HUP、INT、TERM、PIPEシグナルによって停止された場合も正常終了と
みなす。
SuccessExitStatus属性で、判断基準を変更することができる。
on-failerサービスプロセスが異常終了しときだけ、サービスを再起動する。
on-watchdogWatchdog処理でプロセスが終了したときだけ、サービスを再起動
on-abortサービスプロセスがシグナルによって終了し、正常終了できない場合に、
サービスを再起動
alwaysサービスの終了状態にかかわらず、サービスを再起動する