LoginSignup
4
4

More than 3 years have passed since last update.

systemdのお勉強

Posted at

はじめに

Linuxのサービスやデーモンを管理する仕組みであるsystemdについて勉強したので、そのまとめです。

systemdはRHEL7から採用されていて、RHEL8でもそこは同じです。
それ以前はSysVinit(init)/Upstartと呼ばれる仕組みが使われていましたが、そこは本記事では触れません。

基本的にRedHat公式ドキュメント「第3章 SYSTEMD によるサービス管理」に沿っています。

環境

Shimer-System: vagrantでrhel8を試してみるを参考に、vagrant&virtualboxでrhel8を起動しました。

起動処理

Linuxの起動はざっくりと以下の4段階によって行われます。

電源投入によりBIOSが起動する。
BIOSからブートローダーが呼び出される。
ブートローダーがLinuxカーネルを起動する。
Linuxカーネルがinitプロセス(PID 1)を起動する。

出典:Developers.IO by Classmethod: systemd超入門

上記のinitプロセスが従来、/sbin/initだったのが、systemdでは/usr/bin/systemdとなる。

[vagrant@rhel8 ~]$ ps u -p 1
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.2  0.7 179556 13924 ?        Ss   07:23   0:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 18

Unit

systemdでは、「Unit」という単位で処理を管理します。これまで、rc.sysinitやサービス起動スクリプトが実施していた処理の内容は、すべて、Unitとして定義されます。

出典:Systemd入門(1) - Unitの概念を理解する

RedHatのページに書いてありますが、ユニット設定ファイルは以下のディレクトリにあります。下に行くほど設定内容は優先されます。

ディレクトリ 説明
/usr/lib/systemd/system/ インストール済みのRPMパッケージで配布された設定ファイル
/run/systemd/system/ ランタイム時に自動作成されたsystemd ユニットファイル
/etc/systemd/system/ systemctl enableで作成された systemd ユニットファイル、およびサービス拡張向けに追加されたユニットファイル

ユニットにはタイプ(種類)があり、主なものは以下になります。

タイプ 説明 備考
service システムサービス 主にデーモンの起動・管理
target ユニットをグループ化するためのもの
mount ファイルシステムのマウントポイント /etc/fstabから自動作成される
automount ファイルシステムの自動マウントポイント
device デバイスファイル udevがデバイスを認識すると 自動作成される
socket プロセス間の通信ソケット systemdがsocketをListenして、接続があると指定のデーモンを起動してプロセスに受け渡す
path ファイルシステム内のファイルまたはディレクトリー 指定のファイルが作成されると、指定されたサービスを起動する

デフォルト設定

systemdのデフォルト設定は/etc/systemd/system.confで確認で居ます。
このデフォルト設定はコンパイル中に定義されたものであり、このファイルを編集することでデフォルト値を上書きできます。
このファイルの中にも以下のように書かれています。

Entries in this file show the compile time defaults.
You can change settings by editing this file.
Defaults can be restored by simply deleting this file.

サービスの管理

SysVinit/Upstartでは、/etc/rc.d/init.d/ディレクトリーにあるinitスクリプト(Bashのスクリプト)がサービスの起動・管理で利用されていましたが、systemdではサービスユニットの設定ファイル(xxx.service)に置き換わります。

起動・停止系

サービスの起動停止再起動実行中のみ再起動設定再読み込み状態確認は、それぞれ以下の通りsystemctlコマンドで実行します。サービスに限っては、ユニットファイルの.serviceは省略できます。

systemctl start|stop|restart|try-restart|reload|status(is-active) xxx.service(サービスユニットファイル)

全てのサービスの状態確認は以下のコマンドで確認できます。

systemctl list-units --type service --all

systemctl statusの表示内容

example
[vagrant@rhel8 ~]$ systemctl status chronyd.service
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled) ←ユニット設定ファイルが読み込まれているか、そのファイルパス、有効かどうか
   Active: active (running) since Sun 2021-01-31 07:24:00 UTC; 2h 7min ago ←起動状態、タイムスタンプ
     Docs: man:chronyd(8)
           man:chrony.conf(5)
 Main PID: 839 (chronyd) ←サービスのPIDとその名前
    Tasks: 1 (limit: 11394)
   Memory: 2.4M
   CGroup: /system.slice/chronyd.service ←コントロールグループ (cgroup) の情報
           └─839 /usr/sbin/chronyd

有効化・無効化系(自動起動設定)

サービスの有効化(自動起動設定)無効化設定確認は、それぞれ以下のコマンドで実行します。

systemctl enable|disable|status(is-enabled) xxx.service(サービスユニットファイル)

全てのサービス設定確認サービスの開始タイミングの依存関係(他ユニットの前/後)の確認は以下のコマンドで確認できます。

systemctl list-unit-files --type service
systemctl list-dependencies --after
systemctl list-dependencies --before

有効化すると何が起きるか

enableを行うと、選択したサービスユニット設定ファイルのの[Install]セクションを読み取り、/etc/systemd/system/配下(もしくはそのサブディレクトリ)に/usr/lib/systemd/system/name.serviceファイルへのシンボリックリンクを作成します。
実際、enable、disableを行うと以下の通りメッセージが出力される。

example
[vagrant@rhel8 ~]$ sudo systemctl disable rsyslog.service
Removed /etc/systemd/system/syslog.service.
Removed /etc/systemd/system/multi-user.target.wants/rsyslog.service.
[vagrant@rhel8 ~]$
[vagrant@rhel8 ~]$ sudo systemctl enable rsyslog.service
Created symlink /etc/systemd/system/multi-user.target.wants/rsyslog.service → /usr/lib/systemd/system/rsyslog.service.
[vagrant@rhel8 ~]$
[vagrant@rhel8 ~]$ ls -l /etc/systemd/system/multi-user.target.wants/ | grep syslog
lrwxrwxrwx. 1 root root 39 Jan 31 09:46 rsyslog.service -> /usr/lib/systemd/system/rsyslog.service

エイリアス

ユニットにはエイリアス名も設定することができ、特定のユニットのエイリアスは以下のコマンドで確認できます。

systemctl show nfs-server.service -p Names

systemdのターゲット

ターゲットユニットファイル(xxx.target)は依存関係の連鎖で他のsystemdユニットをグループ化するために使われます。
Linuxを起動する際はモードというものが数種類あり、systemd以前はその仕組みをランレベルと呼んでいました。systemdでは従来のランレベルをターゲットユニットで定義しており、互換性の観点から、以下の通りマッピングされています(これもRedHatのページに載っています)

ランレベル ターゲットユニット 説明
0 runlevel0.target, poweroff.target システムをシャットダウンし、電源を切ります。
1 runlevel1.target, rescue.target レスキューシェルを設定します。
2 runlevel2.target, multi-user.target 非グラフィカルなマルチユーザーシステムを設定します。
3 runlevel3.target, multi-user.target 非グラフィカルなマルチユーザーシステムを設定します。
4 runlevel4.target, multi-user.target 非グラフィカルなマルチユーザーシステムを設定します。
5 runlevel5.target, graphical.target グラフィカルなマルチユーザーシステムを設定します。
6 runlevel6.target, reboot.target システムをシャットダウンして再起動します。

デフォルトターゲット

/etc/systemd/system/default.targetのファイル、もしくはsystemctl get-defaultコマンドで確認できます。
↓の例では、multi-user.targetがデフォルトになっています。

example
[vagrant@rhel8 ~]$ systemctl get-default
multi-user.target
[vagrant@rhel8 ~]$ ls -l /etc/systemd/system/default.target
lrwxrwxrwx. 1 root root 41 Jan 20 22:51 /etc/systemd/system/default.target -> /usr/lib/systemd/system/multi-user.target

デフォルトターゲットはsystemctl set-default xxxx.targetコマンドで変更できます。
これによりdefault.targetのシンボリックリンクが置き換わります。

レスキューモード

レスキューモードはシステムの修復などで利用するシングルユーザー環境を提供するモードで、ネットワーク機能や他のユーザのログインは不可のまま、ローカルファイルシステムのマウントと、一部のシステムサービスのみを開始します。
現行のセッションでレスキューモードに入るには以下の通り実行します。現在ログインしているユーザにメッセージが送信されます。

# systemctl rescue

Broadcast message from root@localhost on pts/0 (Fri 2013-10-25 18:23:15 CEST):

The system is going down to rescue mode NOW!

systemdでの電源管理

systemdではsystemctlコマンドでシステムのシャットダウン・再起動・サスペンドなども行えます。
詳細はRedHatのページを参照ください。
こちら↓も参考になりました。
haltを実行してもSystem haltedで止まり電源が落ちない(halt, shutdown, poweroffの違いまとめ)

systemdユニットファイルの設定

例として、chronyd(ntpの後継)のユニット設定ファイル(デフォルト)が以下になります。
(参考)Systemd入門(4) - serviceタイプUnitの設定ファイル

[vagrant@rhel8 ~]$ sudo cat /usr/lib/systemd/system/chronyd.service
[Unit] ←typeに依存しない一般的な設定
Description=NTP client/server ←ユニットの説明。`systemctl status`で出力される
Documentation=man:chronyd(8) man:chrony.conf(5) ←ドキュメントを参照するURI
After=ntpdate.service sntp.service ntpd.service ←起動順序。指定したユニットの後に開始する
Conflicts=ntpd.service systemd-timesyncd.service ←同時に有効化してはいけないユニット
ConditionCapability=CAP_SYS_TIME ←
##他には
##Requires: 同時に有効化するユニット。この中のいずれかが開始しないと、アクティブにならない
##Wants: 同時に有効化するユニット。Requireよりも弱い依存性で、前提Unitが失敗しても起動処理を行う

[Service] ←サービスtype固有の設定
Type=forking ←起動タイプ。forkingの場合は、ExecStartで起動するプロセスが、サービスのメインとなる子プロセスを起動する。デフォルトはsimple(ExecStartの起動プロセスがメインプロセスとなる)
PIDFile=/run/chrony/chronyd.pid ←PIDファイルのパス
EnvironmentFile=-/etc/sysconfig/chronyd ←環境設定ファイル
ExecStart=/usr/sbin/chronyd $OPTIONS ←ユニットの開始時に実行するコマンド
ExecStartPost=/usr/libexec/chrony-helper update-daemon ←サービス起動後の追加コマンド
PrivateTmp=yes ← プロセスが使う一時ディレクトリをそのプロセスにしか見えないようにする
ProtectHome=yes ←Unitのプロセスが/home, /root, /run/userに一切アクセスできなくなる
ProtectSystem=full ←trueの場合、実行するUnitのジョブから見た/usr, /bootが読み取りのみ(書き込み禁止)になる。fullだと、/etcも読み取りのみになる。

[Install] ←有効/無効化された時の設定
WantedBy=multi-user.target ←このユニットに依存するユニット
##他には
##Required: このユニットに強く依存するユニット

カスタムユニットファイルの作成

自前のカスタムデーモンを実行する場合、既存のサービスの2つ目のインスタンスを作成する場合の2パターンを試してみます。

カスタムデーモンの作成

※さくっとやりたい方は、[Systemdを使ってさくっと自作コマンドをサービス化してみる]を参照いただくと良いかもしれません。

dateコマンドの結果をファイルに書き込むだけのデーモン用scriptを作成しました。

date.sh
#!/bin/bash

while true;
do
    echo $(date) >> /opt/date.txt
    sleep 2
done

これを使って、以下のようなUnit定義ファイルを用意します。

/etc/systemd/system/date.service
[Unit]
Description = Date Log(Custom daemon)

[Service]
Type = simple
ExecStart = /opt/date.sh

[Install]
WantedBy = multi-user.target

すると、以下の通りUnit一覧に追加されています。

[root@rhel8 ~]# systemctl list-unit-files --type=service | grep date.service
date.service                               disabled

以下のコマンドで、scriptの実行権限を追加後、新しいUnitファイルの読み込み・起動が出来ます。

# chmod a+x /opt/date.sh
# ls -l /opt/date.sh
-rwxr-xr-x. 1 root root 67 Feb  1 15:12 /opt/date.sh
# systemctl daemon-reload
# systemctl start date.service
# systemctl status date.service
● date.service - Date Log(Custom daemon)
   Loaded: loaded (/etc/systemd/system/date.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2021-02-01 15:24:42 UTC; 3s ago
 Main PID: 26275 (date.sh)
    Tasks: 2 (limit: 11394)
   Memory: 864.0K
   CGroup: /system.slice/date.service
           ├─26275 /bin/bash /opt/date.sh
           └─26279 sleep 2

Feb 01 15:24:42 rhel8.localdomain systemd[1]: Started Date Log(Custom daemon).
#
# tail -f /opt/date.txt
Mon Feb 1 15:28:53 UTC 2021
Mon Feb 1 15:28:55 UTC 2021
Mon Feb 1 15:28:57 UTC 2021
...
# ps aux | grep date
root       26851  0.0  0.1  25952  3408 ?        Ss   15:33   0:00 /bin/bash /opt/date.sh

既存サービスの2つ目のインスタンス作成

こちらの「3.5.3.1. sshd サービスの 2 番目のインスタンスを使用したカスタムユニットファイルの作成」にsshdの2つ目のサービスを起動する方法が載っています。
詳細はここでは割愛しますが、主に以下の内容を行っています。
サービスに依って必要な内容は変わると思います。

  • サービスの設定ファイル、Unit定義ファイルをコピーして編集(主な変更点は↓のとおり)
  • 元々のサービスと重なってしまうサービス設定(ポート番号、PIDファイルなど)の変更
  • ↑の変更に伴うUnit定義ファイルの変更(設定ファイル名, Afterオプション(元々のインスタンスの後にする)など)
  • 2つ目のインスタンスでは実行不要なもの(鍵の生成など)はUnit定義ファイルから削除

参考

RedHatカスタマポータル: 第3章 SYSTEMD によるサービス管理
Linux女子部 systemd徹底入門
Developers.IO by Classmethod: systemd超入門
Qiita: いまだにsysvinitの手癖が抜けない人のためのsystemd
Qiita: これからSystemd入門する
めもめも: Systemd入門(1) - Unitの概念を理解する
めもめも: Systemd入門(4) - serviceタイプUnitの設定ファイル

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4