Systemdによるサービス管理ノウハウ (基本)
Systemdは、RHEL7、CentOS7以降における基本的なサービス管理機能 (等を含むシステム管理デーモンやツールの一式) です。従来はUpstart、SysVinitがありました。
本記事では、SystemdによるRHEL、CentOSのサービス管理に関する基本的なポイントをまとめます。
関連記事として、Systemdのネットワーク関連ユニットについて以下にまとめてあります。
本記事の目的
- Systemdで管理されているサービスやその設定を確認する。
- Systemdで管理されているサービスを手動で停止、起動する。
- 自身で作成したプログラム等をSystemdのサービスとして登録する。
基本
Systemd の基本的なサービス管理コマンドについて説明します。
操作対象とするサービスは、httpd.serviceを例にします。
httpd.service は Apache HTTP Server のサービスが Systemd に登録されたものです。適宜、サービス名を読み替えてください。
サービス管理 (systemctl)
基本的なサービス管理コマンド、systemctl
です。
各項目の詳細は$ man systemctl
で確認できます。
サービスの起動状態の一覧表示(systemctl list-units)
現在のサービスの起動状態を一覧で確認する方法です。
$ systemctl list-units --all --type=service
UNIT LOAD ACTIVE SUB DESCRIPTION … httpd.service loaded active running The Apache HTTP Server …
ACTIVE
列にてサービス起動状態を確認可能- active : サービスが起動した状態である
- inactive : サービスが停止した状態である
- failed : サービスが何らかエラーの状態である(サービス起動失敗等)
- (その他) reloading, activating, deactivating
SUB
列でもサービス起動状態を確認可能(typeがサービスの場合)- running: プロセスが起動した状態である
- exited: 処理を終えてプロセスが終了した状態である
--type service
はサービスのみを表示するためのオプションです。省略するとサービス以外のUnitも表示されます。
特定のサービスのみ表示させる場合は、$ systemctl list-units httpd*
のようにパターン指定するか、$ systemctl list-units | grep httpd
のように実行します。
ACTIVE
列とSUB
列の違いは微妙ですが、プロセスが常時起動するサービスの場合、基本的にACTIVE
列がactiveのときはSUB
列はrunningになっているはずです。対して、処理の実行後、プロセスが終了する類の特殊なサービスはACTIVE
列がactiveかつSUB
列がexitedになります。
参考までに、コマンド実行時に以下の説明が表示されます。
ACTIVE = The high-level unit activation state, i.e. generalization of SUB. SUB = The low-level unit activation state, values depend on unit type.
サービスの自動起動設定の一覧表示(systemctl list-unit-files)
サービスが自動起動する設定かどうかを確認する方法です。
$ systemctl list-unit-files --type service
UNIT FILE STATE … httpd.service enabled …
- STATE列にてサービスの自動起動設定を確認可能
- enabled : 自動起動が有効
- disabled : 自動起動が無効
- static : 単体では自動起動しない (staticはsystemctlで有効化、無効化できないもの。他サービスとの依存関係に従い起動するもの等)
サービスの起動/停止/再起動/リロード(systemctl start / stop / restart / reload)
サービスの起動や停止等の操作方法です。
(例としてhttpdサービスに対するコマンドを記載)
-
サービス起動
# systemctl start httpd
-
サービス停止
# systemctl stop httpd
-
サービス再起動
# systemctl restart httpd
-
サービスリロード
# systemctl reload httpd
reloadは、設定ファイルの変更点を反映する際に使用されます。
例えばhttpdであれば、httpd.confの変更点の反映などです。そのサービスの詳細仕様によりますが、reloadはrestartと異なり、基本的にサービス停止せず設定反映できます。ただし、サービスによってはreloadに対応していない場合があります(ユニットファイルにExecReloadが定義されていない場合)。
補足として、httpdの場合は reload
により、内部的には httpd -k graceful
が実行されるはずです。詳細はhttpdのマニュアルやユニットファイル (後述) を参照願います。
サービスの状態確認(systemctl status)
現在のサービスの起動状態を確認する方法です。
(例としてhttpdサービスに対するコマンドを記載)
$ systemctl status httpd
(★マークは説明用の目印です)
● httpd.service - The Apache HTTP Server Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled★; vendor preset: disabled) Active: active (running)★ since Thu 2022-05-01 02:02:02 UTC; 2min 2s ago Docs: man:httpd(8) man:apachectl(8) Main PID: 5001 (httpd) Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec" CGroup: /system.slice/httpd.service ├─5002 /usr/sbin/httpd -DFOREGROUND ├─5003 /usr/sbin/httpd -DFOREGROUND …
Loaded:
行は、Unitファイルのパスと、サービスの自動起動設定(enabled or disabled)が表示されます。前述のサービスの自動起動設定の一覧表示と同様の内容です。
Active:
行は、サービスの起動状態(active or inactive等)が表示されます。前述のサービスの起動状態の一覧表示(systemctl list-units)と同様の内容です。
Main PID:
行、CGroup:
行は、それぞれメインプロセスと、メインプロセスからフォークされた子プロセスです。
詳細
もう少し詳しい内容です。
Unitの構成、種類
systemdはサービス等をUnitの単位で扱います。
ここでは、Unitの構成や配置について簡単に説明します。
ユニットファイル
Unitはファイル形式で定義されます。
そのファイル名の書式はunit_name.type_extension
です。
unit_nameは、そのユニットの名前(サービスであればサービス名)です。
type_extensionは、.service(サービスを定義するもの)、.target(複数のサービスをまとめるためのもの)、.device(デバイス)、.timer(cronのように使えるもの)等、他にもあります。
詳細は、man systemd.unit
や、
RedHat社のマニュアルが参考になります。
ユニットファイルに関する主なパス
ユニットファイルの主な格納パスは以下です。
/usr/lib/systemd/system/
:パッケージマネージャによって配置/etc/systemd/system/
:システム管理者によって配置
前者が、RPM等にデフォルトで含まれるユニットファイルが格納されるパスです。後者は、システム管理者が個別にユニットファイルを用意して格納するためのパスです。
同名のユニットファイルが /usr/lib/systemd/system/
と /etc/systemd/system/
の両方に配置された場合、/etc/systemd/system
内のファイルが優先されます。
詳細は、 man systemd.unit
の “UNIT FILE LOAD PATH” セクションや、開発元のドキュメントに記載があります。
例:httpdの場合
例えば、httpdの場合、関連するユニットファイルは以下です。
$ ls -l /usr/lib/systemd/system/
(★マークは説明用の目印です) … -rw-r--r-- 1 root root 314 3月 22 02:27 httpd-init.service -rw-r--r-- 1 root root 944 3月 22 02:27 httpd.service ★ drwxr-xr-x 2 root root 26 4月 13 09:32 httpd.service.d -rw-r--r-- 1 root root 244 3月 22 02:27 httpd.socket drwxr-xr-x 2 root root 31 4月 13 13:17 httpd.socket.d -rw-r--r-- 1 root root 662 3月 22 02:27 httpd@.service …
ファイルがたくさんありますが、通常のWebサーバとして使用するhttpdサービスのユニットファイルはhttpd.serviceです。
ユニットを有効化した際の動作
# systemctl enable httpd
によりユニットを有効化すると、そのユニットファイル内の定義 (後述の[Install]セクション) に従い動作します。
一般的なサービスであれば、/etc/systemd/system/multi-user.target.wants/
配下にシンボリックリンクが作成されます。
このディレクトリ配下にあるユニットファイルは通常のマルチユーザモード(multi-user.target)でのシステム起動時に読み込まれますので、システム起動時にサービス自動起動することになります。
例として、httpd.serviceユニットファイル内の[Install]セクションは以下のように記載されています。
[Install] WantedBy=multi-user.target
上記の記載により、このユニットを有効化すると、multi-user.target配下にシンボリックリンクが作成されるということです。
作成されたシンボリックリンクは以下です。
$ ls -l /etc/systemd/system/multi-user.target.wants/
… lrwxrwxrwx 1 root root 37 4月 14 11:29 httpd.service -> /usr/lib/systemd/system/httpd.service …
ユニットファイルをカスタマイズする場合
サービス起動時のオプション変更等、ユニットファイルをカスタマイズしたい場合については、以下の記事にまとめてあります。
ユニットファイルの読み方
任意のプログラム等をSystemdのサービスとして登録にまとめて記載してあります。
(補足)テンプレート形式のユニット(name@xxx.service)
httpd@.service
のように@(アットマーク)がついたサービスは、テンプレートです。例えば仮想コンソール(gettyやvnd等)で複数インスタンス起動するようなサービスの場合に使用されます。
systemctl start name@1.service
やsystemctl enable name@1.service
のように、@の後に任意の文字列を指定できます。(getty@tty1.service等)
@の後に指定した文字列は、ユニットファイル内の%l %i 変数に置き換えられます。
任意のプログラム等をSystemdのサービスとして登録
以下の流れです。
- サービスとして実行するプログラムを準備
- ユニットファイルを作成
- 作成したユニットファイルを読み込み、有効化
1. サービスとして実行するプログラムを準備
任意のプログラムを準備します。
プログラムの例として、簡単なシェルスクリプトを作成します。
# vi /usr/local/bin/sleeping.sh
#!/bin/sh while true; do echo "zzz..." >> /tmp/sleeping.log; sleep 5 ; done
2. ユニットファイルを作成
/etc/systemd/system/
配下にユニットファイルを作成します。各オプションの詳細はman systemd.service
、man systemd.unit
で確認できます。
# vi /etc/systemd/system/sleeping.service
[Unit] Description = just keep sleeping process [Service] ExecStart = /usr/local/bin/sleeping.sh Type = simple [Install] WantedBy = multi-user.target
上記はとてもシンプルなユニットファイルの例です。実際の運用に際しては、マニュアルを参照の上、各オプションの精査が必要です。
-
[Unit]セクションのオプション ([Unit]セクションは任意)
- Description:ユニットの説明
- After:このAfterオプションで指定したユニットの起動開始後に自身のユニットを起動開始する。
- Before:Afterの逆。
- Wants:自身のユニットの起動時に、このWantsオプションで指定したユニットを起動する。緩い依存関係を指定しており、指定したユニットの起動が失敗しても自身のユニットは起動しようとする。
- Requires:Wantsと同様に依存関係を指定するが、必須の依存関係を指定しており、指定したユニットの起動が失敗した場合に自身のユニットは起動失敗として扱われる。
After、Beforeはサービス起動の「順序関係」を指定するオプションです。Wants、Requiresは「依存関係」を指定するオプションです。なお、Wants、Requiresを指定しても、起動の「順序」は制御されません。
-
[Service]セクションのオプション ([Service]セクションは必須)
[Service]セクションは、サービス定義において重要です。いくつか記載しますが、他にも多くのオプションがあります。- ExecStart:サービス起動時(systemctl start)に実行するコマンド。
- ExecStop:サービス停止時(systemctl stop)に実行するコマンド。
- ExecReload:サービスリロード時(systemctl reload)に実行するコマンド。
- Restart:サービスのプロセス停止時の挙動を指定。デフォルトはno(再起動しない)。例えばalwaysに指定するとプロセスが終了時には再起動される。
- Type:サービスの起動方法。この指定に従いサービスが正常起動したかを判定する。例えば、プログラム単体を実行し続けるものであればsimpleを指定、子プロセスがそのサービスのメインプロセスになるものであればforkingを指定する。より詳細にサービスの起動判定を行いたい場合はnotify(やdbus)の指定が推奨される。
- simple:ExecStartで指定したコマンドがサービスのメインプロセスである場合に使用する。プロセス生成した時点でサービス起動完了と判定する。ただし、プロセス生成後にExecStartで指定したコマンドを正常に実行できなくてもサービス起動が成功した扱いとなる(例:Userオプションで指定したユーザが存在しない場合でもサービス起動成功となる、等)。
- forking:ExecStartで指定したコマンドにより実行されたプロセス(親)から起動(フォーク)された子プロセスがサービスとして動作する場合に使用する。親プロセスが終了した時点で起動完了と判定する。PIDFileオプションの使用が推奨される。なお、
man systemd.service
には、近年PIDFileが使用されないため、特に必要性が無ければType=notifyかType=simpleを使用するよう記載がある。 - notify:simpleと同様、ExecStartで指定したコマンドがサービスのメインプロセスである場合に使用するが、そのプロセスがsystemdのライブラリ関数sd_notify()に対応している場合に使用する。プロセスは自身の起動完了をsd_notify()にてsystemdに通知する。
- oneshot:simpleと同様、ExecStartで指定したコマンドがサービスのメインプロセスである場合に使用するが、そのプロセスが終了した時点で起動完了と判定する。その後、(RemainAfterExit=yesを指定しない限り)activeになることはなく、そのままサービスは停止(deactivatingやdead)となる。なお、RemainAfterExit=yesを指定した場合、コマンド終了後もサービスはactiveな状態となる。
- PIDFile:PIDファイルのパスを指定する。主に、Type=forkingのサービスではこのオプションでメインプロセスのPIDファイルを指定することが推奨される。
- [Install]セクションのオプション ([Install]セクションは任意)
- WantedBy:このWantedByオプションで指定したユニットの起動時、自身のユニットを起動する。
[Install]セクションでは、
systemctl enable
やsystemctl disable
でユニットを有効化、無効化した際の処理を定義します。例えば、enable時にはWantedByで指定したユニットの.wantsディレクトリに自身のユニットを登録する等です。
前述のWantsの逆でWantedBy、Requiresの逆でRequiredByというオプションがあります。これらは、そのオプションで指定したユニットの起動時に自身のユニットを起動するものです。
3. 作成したユニットファイルを読み込み、有効化
ユニットファイルを作成後、以下のように反映、有効化することでシステム起動時に自動起動するサービスとして設定完了です。
ユニットファイルの変更後は以下のようにsystemdにて読み込みが必要です。
# systemctl daemon-reload
作成したユニットファイルのサービスを有効化します。
# systemctl enable sleeping
手動でサービスを起動する際には以下のコマンドを実行します。
# systemctl start sleeping
上記のシェルスクリプトは、ファイル/tmp/sleeping.logに文字列を出力するものなので、ファイルの中身を確認すると、その動作を確認できます。
# tail -f /tmp/sleeping.log
参考
サービス起動時のエラー等
systemctlコマンドによるサービス起動が失敗した際には以下のようなメッセージが表示されます。
# systemctl start httpd
(サービス起動失敗時のメッセージ例) Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details.
メッセージの指示に従い、# systemctl status httpd.service
and journalctl -xe
にてログを確認することが可能です。あるいは、messagesにもログが出力されている場合があります。
ユニットファイルの例
備忘用に、httpdデフォルトのユニットファイルを記載しておきます(RHEL8系)。
httpd.service (httpd本体)
/usr/lib/systemd/system/httpd.service
# See httpd.service(8) for more information on using the httpd service. # Modifying this file in-place is not recommended, because changes # will be overwritten during package upgrades. To customize the # behaviour, run "systemctl edit httpd" to create an override unit. # For example, to pass additional options (such as -D definitions) to # the httpd binary at startup, create an override unit (as is done by # systemctl edit) and enter the following: # [Service] # Environment=OPTIONS=-DMY_DEFINE [Unit] Description=The Apache HTTP Server Wants=httpd-init.service After=network.target remote-fs.target nss-lookup.target httpd-init.service Documentation=man:httpd.service(8) [Service] Type=notify Environment=LANG=C ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND ExecReload=/usr/sbin/httpd $OPTIONS -k graceful # Send SIGWINCH for graceful stop KillSignal=SIGWINCH KillMode=mixed PrivateTmp=true [Install] WantedBy=multi-user.target
httpd-init.service (TLS用の鍵生成をするためのoneshotのサービス)
/usr/lib/systemd/system/httpd-init.service
[Unit] Description=One-time temporary TLS key generation for httpd.service Documentation=man:httpd-init.service(8) ConditionPathExists=|!/etc/pki/tls/certs/localhost.crt ConditionPathExists=|!/etc/pki/tls/private/localhost.key [Service] Type=oneshot RemainAfterExit=no ExecStart=/usr/libexec/httpd-ssl-gencerts
httpd\@.service (テンプレート)
/usr/lib/systemd/system/httpd\@.service
# This is a template for httpd instances. # See httpd@.service(8) for more information. [Unit] Description=The Apache HTTP Server After=network.target remote-fs.target nss-lookup.target Documentation=man:httpd@.service(8) [Service] Type=notify Environment=LANG=C Environment=HTTPD_INSTANCE=%i ExecStartPre=/bin/mkdir -m 710 -p /run/httpd/instance-%i ExecStartPre=/bin/chown root.apache /run/httpd/instance-%i ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND -f conf/%i.conf ExecReload=/usr/sbin/httpd $OPTIONS -k graceful -f conf/%i.conf # Send SIGWINCH for graceful stop KillSignal=SIGWINCH KillMode=mixed PrivateTmp=true [Install] WantedBy=multi-user.target
まとめ
本記事では、SystemdによるRHEL、CentOSのサービス管理に関する基本的なポイントをまとめてみました。
参考
開発プロジェクト (アップストリーム)
RHELのマニュアル
-
第12章 systemd の管理 Red Hat Enterprise Linux 9 | Red Hat Customer Portal
-
第14章 systemd の管理 Red Hat Enterprise Linux 8 | Red Hat Customer Portal
-
第10章 systemd によるサービス管理 Red Hat Enterprise Linux 7 | Red Hat Customer Portal