春の入門連載2024 の4本目です。
はじめに
こんにちは、最近寒暖差が激しくて体調崩しがちなTIGの森です。
入門向け記事としてLinuxの systemd
における service unit
の起動と停止のフローについて説明します。
service unit とは
service unit
とは systemd
の設定単位の1つで、Linuxにおけるサービスの振る舞いを定義する設定をまとめたものです。主にデーモンやその他のシステムプロセスといった、起動や停止を含む管理を行います。
サービス起動の大まかな流れ
サービスの起動のおおまかな流れを説明します。
ここでは話を簡単にするため、Type
ディレクティブ(後述)がデフォルトの simple
に指定されているとします。
サービス起動の流れ
systemctl start [サービス名].service
を実行すると、systemd
は指定されたservice unit
を起動するsystemd
はservice unit
の設定ファイル(.service
)を確認し、サービスが有効かどうかなどを調べるsystemd
がfork()
を実行し、成功した時点でservice unit
がactive
になる。この新しく生成されたプロセスはサービスを起動するためのプロセスとなる- この新しいプロセスが必要な環境設定(環境変数の設定など)を行った後、
ExecStart
で指定されたプログラムをexecve()
で実行する - サービスのプログラムが実行され、サービスが開始する
以上がざっとした流れです。もちろんLinuxにおけるサービス管理全てを網羅しているということではありません。初期化だけを実施するiptables
などの例外もあります。
サービス起動・終了時の前後の処理に関して
サービス実行の主要なコマンドの前に環境変数の設定や通信路の準備や初期化などを実施する場合、ExecStart
の前処理として実行されるExecStartPre
や、active
となった時点で実行されるExecStartPost
、また終了時に実行されるExecStopPost
などのディレクトリが用意されています。
サービス起動・終了に関連するディレクティブは下記です。
名称 | 概要 |
---|---|
ExecStartPre |
依存関係を満たすためのリソースの確保、前段処理を実施する |
ExecStart |
環境変数を読み込み、サービス処理のプログラムを実行する |
ExecStartPost |
active になる前のタイミングで実施する後処理を実施する |
ExecStop |
サービス停止のプログラムを実施する |
ExecStopPost |
サービス終了後の後処理を実施する。inactive になる前の実施する |
ExecReload |
サービスのリロードを実施する |
サンプル
例として、ExecStartPre
で実際にどのような前処理が実施できるか試してみましょう。
EC2のインスタンスのメタデータから自身のリージョンを取得し、それをサービスから呼び出して出力させます。
手順
環境変数の設定ファイル
/etc/environment
に下記の行を追加して、デフォルトのリージョンを指定/etc/environment Region=default
ExecStartPre
で叩かれる事によって自分のリージョンを取得するシェル/etc/setEnvConf.sh
を作成/etc/setEnvConf.sh
REGION=$(curl -s http://169.254.169.254/latest/meta-data/placement/availability-zone | sed -e 's/.$//')
sudo sed -i "/^Region=/c\Region=$REGION" /etc/environment/etc/systemd/system
配下にtest.service
を作成test.service [Unit]
Description=Test Service
After=network.target
[Service]
EnvironmentFile=/etc/environment
ExecStartPre=/bin/bash /etc/setEnvConf.sh
ExecStart=/bin/bash -c 'echo "The region of this instance is ${Region}" > /tmp/output.txt'
[Install]
WantedBy=multi-user.targetサービスファイルを読み込んで起動
sudo systemctl daemon-reload
sudo systemctl start test
以上が手順になります。
サービスが無事起動したら/tmp/output.txt
を見てみましょう。
The region of this instance is ap-northeast-1 |
ちゃんと自身のインスタンスのリージョンが取得できています。
災対環境などでAMIからインスタンスを起動する時に自身のリージョンを取得して、処理に繋げる際などに応用できるでしょう。
注意点
今回は触れませんでしたがunit
がactive
やinactive
になるタイミングは Type
ディレクティブの指定によって微妙に変化します。
この記事ではデフォルトのsimple
を用いていますが、これは代表プロセスがfork()
の実行に成功したときにactive
になります。つまり、ExecStart
が失敗しようがその前段階の環境変数の設定やExecStartPre
ができていればactive
にはなってくれるということです。
一方で明示的にType
をexec
に指定した場合、ExecStart
で指定したプログラムからexecve()
の実行が成功したときにactive
になります。他にも様々な Type ディレクティブがありますが、active
になるタイミングがいつなのかはしっかり意識して前処置や後処理を運用していくことが運用上求められるでしょう。
まとめ
システムを安定させる上で重要なのは、サービスがactive
になるタイミングやその前後の処理の流れを正確に理解することです。
また、[Unit]
セクションにAfter
を記述し、異なるサービス間で起動順序を制御することも一般的です。したがって、これらの順序をより一層意識した運用が求められるでしょう。