systemdエッセンシャル
RHEL8 で systemd の出力やログを読んで理解できないときに、どこを調べたらいいか見当がつくようになることを目標として、systemdの基本的な考え方や、調べるときに中心になりそうなトピックを紹介する資料。RHEL 8を想定しています。
systemd エッセンシャル
レッドハット株式会社 ソリューションアーキテクト
森若和雄
2020-03-22
1この資料の位置づけ
2対象 : systemd をとりあえず使えているけど中で何をやってい
るかブラックボックスで気持ち悪い or 納得感がない人
目的 : RHEL8 で systemd の出力やログを読んで理解できない
ときに、どこを調べたらいいか見当がつくようになること
前提 : fork, exec システムコール、シグナル、ソケットくらい
の言葉がなんとなくわかる程度の UNIX 系 OS についての知識この資料で扱わないこと
RHEL8 より前の systemd から何が変わったかの差分unit 作成方法や コマンドの how to usedracut を含む起動処理の詳細Optional な機能の一部3ディレクティブの網羅的な一覧や解説 (systemd.directives から systemd の man page を探す
のがおすすめです )–systemd-networkd, systemd-resolved, systemd-timesyncd–systemd-nspawn, machinectl–systemd-boot, Portable Service–デスクトップ環境とのインテグレーション全般個別のトラブルシュート (Red Hat の Knowledge base を検索するのがおすすめです )
agenda
systemd は何をやるもの ?systemd の unit
target unit: 同期ポイントを提供–service unit: サービス管理––4––socket, path, timer unit: イベントに
よる Activation
device, mount unit: ファイルシステ
ムの mount
slice, service, scope unit: cgroup 管理ユーザセッション用 systemd
アドホックなコマンド実行の管理
systemd-runjournald によるロギングsysvinit からの移行systemd の動作を眺める周辺ツールなど参考資料概要図unit 作成unit unit unit unit 管理socket
socket
socket 待受けsystemdデバイス管理5サービスやユーザセッション
cgroup
などの環境
cgroup
などの環境
cgroup
などの環境path
path
timer
timer
timerunit
path
file環境セットアッププロセスログ出力udevjournalddevice
device
devicejournal
プロセス
child
processystemd は何をやるもの ?6systemd って何?
7システムとサービスの管理をおこなうたくさんのサービス、ユー
ティリティ、ライブラリ群。 PID 1 の init 実装を含む。
「 sysvinit の置き換え」とよく言われますが単純な置き換えでは
なく linux の機能を活用する基盤として作り込まれています
目標は?
–起動の高速化–ディストリビューション独自実装の統廃合–ベストプラクティスの統合
systemd の普及
2010 年 systemd の最初のリリース2011 年 Fedora に systemd を統合2013 年 Debian に統合 ( 複数ある init 実装の一つとして )2014 年 RHEL, SLES が systemd を統合2015 年 Debian のデフォルト init 実装に選出世にでてから約 10 年、一般的なディストリビューションで
標準的に利用されるようになってから約 5 年
8systemd はどのあたりをカバーする ?
9起動・終了・再起動に必要な処理全般
–デバイスの検出・命名・初期化–fs の mount, autmount, 暗号化 block device 対応–サービス起動・管理–ロギング–起動失敗時のレスキュー処理–パスワード確認–システムの locale, TimeZone, キーボード , 仮想コンソール–電源管理 ( サスペンド・ハイバネート・レジューム )サービス管理で典型的に必要な属性全般の管理
–control groups, namespace, ulimit, 通知 , /tmp の掃除–ユーザセッション管理
それぞれをカバーする systemd 関連プログラム
10起動・終了・再起動に必要な処理全般
–デバイスの検出・命名・初期化← udev–fs の mount, autmount, 暗号化 block device 対応 ← systemd-fstab-generator–サービス起動・管理–ロギング–起動失敗時のレスキュー処理–パスワード確認 ← systemd-ask-password-*–システムの locale, TimeZone, キーボード , 仮想コンソール ← localectl, timedatectl–電源管理 ( サスペンド・ハイバネート・レジューム )← systemd 本体← journald
← rescue.service← systemd-sleep, udev, systemd-inhibitサービス管理で典型的に必要な属性全般の管理
–control groups, namespace, ulimit, 環境変数 , /tmp の掃除 ← systemd 本体 , systemd-tmpfiles*–ユーザセッション管理 ← systemd-logind
宣言的なサービスの定義
sysvinit では shell を順次実行することで起動処理を行う
–
–編集すると rpm パッケージ等の更新時にトラブルが発生しがち
ulimit 等リソース割り当てや設定方法が標準化されていないため Ansible 等での自動的なカ
スタマイズが困難systemd では宣言的にサービスを定義し、実行は shell ではなく systemd 自体が行う
[Unit]
Description=Vsftpd ftp daemon
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf11[Install]
WantedBy=multi-user.target従来からの互換性の維持
中身は大きく変わっていますが、操作の互換性を維持する工夫を実施sysvinit, LSB の init scripts から unit ファイルを自動生成インタフェースの互換性維持
–
–
–
互換コマンドの提供
–
–12「ランレベル」への対応 : runlevelX.target, カーネルオプション等の維持
ソケット : /dev/initctl, /dev/log 互換ソケット
dbus: ConsoleKit 等の dbus インタフェースを維持
halt, init, poweroff, reboot, runlevel, shutdown, telinit など
service コマンドを実行すると systemctl を呼びだす# service cups start
Redirecting to /bin/systemctl startcups.servicesystemd はプロセス実行環境を用意する
systemd の主要な機能のひとつは実行環境の用意
–13UID, GID, 環境変数 , cwd, chroot, ulimit, capability, nice,
cgroup, namespace, seccomp, taskset などを設定した上でプロ
セスを実行systemd は linux kernel が提供する多様な機能を統一的なイン
タフェースで提供systemd がプロセス実行環境を用意する方法
1. systemd は fork() して、子プロセスを cgroup に入れる
systemd
cgroup, 環境変数 , uid etc.
systemd →
プロセス2. 子プロセスの systemd が
環境を設定してから exec()
でプロセス実行
プロセス
child
proces143. プロセスがデーモン化や子プロセスの
生成などを行っても cgroup で追跡する
使い捨て unit の作成 systemd-run
systemd が用意する環境を試すには、使い捨ての unit を作る systemd-run コマンドが便利systemd-run [ オプション ] < コマンド >
––例 1: # systemd-run -t env
サービス用に用意された環境変数を表示-t をつけないと端末ではなくログへ出力される例 2: # systemd-run -t --uid=apache id
–例 3: # systemd-run -S -p ProtectHome=yes
15uid が変わっている
service 用環境で shell を起動する。この例では /home 以下にアクセスできない ( 何もなくなっ
ているように見える )
systemd で制限をかけた環境でプログラムをテストするときに便利。
unit
systemd の管理するモノ16unit とは ?
システム管理に登場するいろいろなモノを抽象化し
た、 systemd で使われる概念
例 : 以下の「」内にあるものは全て unit
「ブロックデバイス sda2 」を「 /var に mount 」して
「パス /var/cache/cups/org.cups.cupsd が存在」すれば
「サービス cupsd 」を起動して「ソケット /run/cups/
cups.sock 」で待ちうける
unit17systemd は unit 群を管理する
systemd はおおむね以下のような動作を無限に繰り返します :
システムの起動、ハードウェアの挿抜、ユーザコマンド、
タイムアウト、 unit 状態変化などのイベントを取得する
イベントに対応する unit があれば、あらかじめ定義された制限に従って有
効化 (Activation) や無効化などの job を行う。 unit の内容や依存関係から
複数の job になることもある。
systemd は job queue を持っていて複数の job を適切な順序で実施する
event18systemdactivationunitunit がとる状態
基本的な 2 状態 : Active, Inactive中間的な状態 : Activating, Deactivating, Reloading例外 : Failed, Maintenance
ActivatingFailed
InactiveMaintenance
19ActiveDeactivating
Reloadingunit 間の依存関係
unit は他の unit と依存関係をもてる
20Wants: B を active にするなら A も active にした
いが A が無い場合や失敗しても OKARequires: B を active にするなら A も active にし
する。 A が成功しないと B は失敗AAfter: B を activating にするのは A を activating
にしたあとAConflicts: A と B は同時に Active になれない
AWantsRequiresAfterConflictsBBBBsystemd の unit 初期化イメージ
chronyd
After chrony-wait Before time-sync
.service Require .service Wants .targetsystemd は
多数の unit 間の After
依存関係を見て
何を active に
network
するか、順序を
.target
どうするか決めるWants
Wants
multi-user
.targetBefore
Wantsnetwork-pre
.target
21Aftercrond
.serviceNetworkManager
After
.serviceWants
起動設定 :
これを active に
するぞsystemd の unit 初期化イメージ ( 続 )
networkpreNetworkManagernetwork依存関係を満たしつつ
起動処理を並行して行うchronyd 起動
chrony-wait22timesynccrond 起動
multiuser実際の起動処理の様子
$ systemd-analyze plotSVG 形式で起動時の各 unit
の初期化開始・終了のタイ
ミングを図示する。23systemd --test
24/lib/systemd/systemd --test --system とすると実際に起動用
の unit や設定を読んで実行するべき job を計算した様子を出
力する。 ( 実際の起動処理はおこないません )主要な Activation のきっかけ
25Activation on boot: 起動処理。通常は default.target unit を有効化する。
Socket-based Activation: systemd が xinetd のようにソケット待ちうけを行
い着信を契機に対応する service の unit を有効化してソケットを引きつぐ。
socket unit と service unit の組み合わせで定義する。
Timer-based Activation: systemd が時刻やタイムアウトなどを契機に service
unit などを有効化する。 timer unit と service unit の組み合わせで定義する。
Device-based Activation: linux kernel が検出したハードウェアの挿抜や変更
を契機として device unit を作成し、そこからの依存関係で mount unit や
service unit などを有効化する。 fstab での mount 処理などは device-based
activation で実施される。
ユーザからの操作 : systemctl
systemctl は systemd への主要な操作インタフェース
–よく使うコマンド : 見る (show) 、状態 (status) 、有効化 (enable) 、
無効化 (disable) 、開始 (start) 、終了 (stop) 、リロード (reload)例 : cron デーモンに対応する unit crond.service の状態表示
$ systemctl status crond.service
crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2020-02-03 14:42:02 JST; 2 days ago
Main PID: 1245 (crond)
Tasks: 1 (limit: 28413)
Memory: 10.0M
CPU: 30.309s
CGroup: /system.slice/crond.service
└─1245 /usr/sbin/crond -n26Feb 06 11:10:01 snake.usersys.redhat.com CROND[147722]: (root) CMD (/usr/bin/redhat-interna>unit の start/stop 操作
systemd が unit を
active にする (start) / inactive にする (stop)
–systemctl start crond.service–systemctl stop crond.service状態を変える必要がある場合だけ動作を行う
–27unit が既に active である場合、 start しようとしても何も実施しな
い。 unit が inactive な場合の stop も同様。依存関係があれば指定以外の unit も操作を行う場合がある
実際のシステムで依存関係を見る
systemctl list-dependencies
–28デフォルトでは起動処理に対応する
default.target の依存関係を表示default.target に使われる unit
–multi-user.target (runlevel 3 相当 )–graphical.target (runlevel 5 相当 )unit の種類
unit にはいくつかの種類がある。よく使うものを例示する。
–target: 何もしない。依存関係や前後関係を定義する。–service: 何かのプロセスを実行してサービスを提供する–socket: TCP, UDP, IPv4, IPv6, socket, dbus, fifo などで待ちうける––29path: ファイルやディレクトリが存在することや操作されたこと
を待ちうける
timer: サービス開始時から x 秒経過、前回の timer 起動時から x
秒経過、カレンダー上の日時などの時刻を待ちうける
関連する man page
30systemd(1) Concepts 節 : systemd の主なコンセプト、 unit
の種類、 kernel コマンドラインオプション
daemon(7) Activation 節 : Activation の説明
systemd.special(7): systemd であらかじめ定義されている特殊
な unit の紹介。 default.target など予約語のように扱われるも
のも多い。やってみよう31systemctl list-units で unit の一覧を見るsystemctl status で unit の状態を見るsystemctl show でもっと細かい unit の状態を見るunit file
unit の設定ファイル32unit の定義ファイル unit file
systemd の unit 群のほとんどはファイルで定義されるunit と unit file は明確に区別されるが慣れるまでは混乱しがち–systemctl list-units (unit の一覧 )–systemctl list-unit-files (unit file の一覧 )–systemctl cat crond.service ( ある service に関連する unit file を出力 )ロードunitsystemd は unit file をロードしてメモリ上の unit を作成する
–
–33unit filesystemctl daemon-reload ( 全 unit 定義ファイルを読み直す )
不要な unit は自動的にアンロードされる ( 一覧を見るだけでもロードしなおさ
れるので利用時にはあまり意識しない )※unit file を書き変えただけでは動作に影響を及ぼさない場合があるので注意
unit file の例
/lib/systemd/system/httpd.service
[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
KillSignal=SIGWINCH
KillMode=mixed
PrivateTmp=true34[Install]
WantedBy=multi-user.targetunit の例
$ systemctl show httpd35Type=notify
Restart=no
NotifyAccess=main
RestartUSec=100ms
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
TimeoutAbortUSec=1min 30s
RuntimeMaxUSec=infinity
WatchdogUSec=0
WatchdogTimestampMonotonic=0
RootDirectoryStartOnly=no
RemainAfterExit=no
GuessMainPID=yes
MainPID=0
ControlPID=0
FileDescriptorStoreMax=0
NFileDescriptorStore=0StatusErrno=0
Result=success
ReloadResult=success
CleanResult=success
UID=[not set]
GID=[not set]
NRestarts=0
OOMPolicy=stop
ExecMainStartTimestampMonotonic=0
ExecMainExitTimestampMonotonic=0
ExecMainPID=0
ExecMainCode=0
ExecMainStatus=0
ExecStart={ path=/usr/sbin/httpd ; arg
ExecStartEx={ path=/usr/sbin/httpd ; a
( 以下略 )unit file の文法
いわゆる INI ファイル形式
Key=Value 形式の行が並ぶ。 Key や
条件により同じ Key を複数回書ける
場合もある。Key はディレクティブと呼ばれる# または ; のあと改行まではコメント改行は \ でエスケープできる36[Section] でセクションを指定時間は” 3min 10sec” のように単位を
つけて書ける[Section A]
KeyOne=value 1
KeyTwo=value 2
# a comment
; another comment
[Section B]
Setting="something" "some thing" "..."
KeyTwo=value 2 \
value 2 continued
TimeoutSec=”1hour 5min”unit と unit file
unit には unit file にある情報の他に以下が含まれる
–デフォルト値–他 unit からの依存関係の逆向きの依存関係
–37他から After= で参照されていると Before= が作られるなど実行時に決まる情報 ( 時刻、実行結果、 PID など )unit file の enable/disable 操作
unit file に対して enable か、 disable かを指定する
––38enable すると Install 処理が行われる ( 典型的には multiuser.target などからの依存関係を定義する )
disable すると Uninstall 処理を
行い Install での処理を元に戻すchrony-wait Before time-sync
chronyd
.service Require .service Wants .target
Aftercrond
.serviceAfterdisable していても unit file はロード .target
Before
Wants
され unit が作成される。他から依存 network-pre After NetworkManager
.service
.target
されていれば active になる場合もある
networkWants
cups
.pathWants multi-user
.targetWantsunit file の mask/unmask 操作
どういう依存関係を経由しても unit file から unit を作りたくないと
きは mask を行う
–mask すると systemd はその unit file を無視してロードしない–unmask すると元にもどすmask した unit file で定義される
unit へ、他の unit が依存していると
依存関係を満たせず失敗する場合もあるchrony-wait Before time-sync
chronyd
.service Require .service Wants .target
After
After
network
.targetWants
cups
.path
Before
Wantsnetwork-pre
.target39crond
.serviceAfterNetworkManager
.serviceWants multi-user
.targetWantsunit file の参照パス
40systemd が unit file を探すディレクトリは複数ある
RHEL の場合 systemd 関連の設定ディレクトリは以下。
同名のファイルがあれば上が優先
/etc/systemd ( 管理者による設定 )
→ /run/systemd ( 実行時の自動設定など )
→ /lib/systemd (rpm パッケージで提供 )
設定変更がパッケージ更新で壊される事故が防げる
unit file のカスタマイズ
unit file の典型的なカスタマイズはファイル内容の編集ではなく、別
ファイルの配置やシンボリックリンクの作成でおこなう。foo.service という unit file に対して以下のディレクトリが使える
––41foo.service.d (drop-in ディレクトリ。 *.conf のファイル名で設定を
書くと foo.service の同じディレクティブを上書きしたものとして解
釈される )
foo.service.wants, foo.service.requires ( このディレクトリ内に他
の unit file へのシンボリックリンクを置くことで Wants= および
Requires= に追記したものとして解釈される )
drop-in の利用例
/lib/systemd/system/httpd.service
[Unit]
Description=The Apache HTTP Server
Wants=httpd-init.service
After=network.target remote-fs.target nsslookup.target httpd-init.service
Documentation=man:httpd.service(8)
[Service]
Type=notify
Environment=LANG=C/etc/systemd/system/httpd.service.d/limit.conf
[Service]
LimitNOFILE=10240
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
# Send SIGWINCH for graceful stop
KillSignal=SIGWINCH
KillMode=mixed
PrivateTmp=true
42[Install]
WantedBy=multi-user.targetdrop-in には追加または変更したい部
分だけ書く
systemctl cat httpd.service
のようにすると指定した unit に関係
する設定ファイルを出力する
(*.wants, *.requires は systemctl cat
の出力に含まれない )
systemd-delta コマンドは unit カ
スタマイズの概要を表示する関連する man page
systemd.syntax(7): unit file の文法systemd.time(7): systemd 内で使う日時で使える構文43systemd.unit(5): unit file 、 unit file のロードやアンロードの
条件、依存関係や全 unit 共通の設定、設定ファイルを配置す
る path などsystemd.directives(7): ディレクティブから man ページへの索
引 ( 既存の unit file を読むときに便利 )
やってみよう
44systemctl list-units と systemctl list-unit-files を比較
systemctl cat sys-subsystem-net-devices-eno1.device のようにして対応す
る unit file が存在しないことを確認する
systemctl cat default.target と systemctl show default.target を比較
パッケージに含まれる /lib/systemd/system/ 以下の unit file と、自動または
手動で作られる /etc/systemd/systemd/ 以下のリンクやファイルを見比べて
systemctl show の出力と比較する
systemctl enable/disable crond.service で unit を install/uninstall する。こ
の操作による設定が /etc/systemd/system/ 以下に反映されていることを確認
する
target unit
同期ポイントを提供45target unit
target unit 自体は何もしないで状態が変わるだけの unit
–システム起動、シャットダウン、異常時のレスキューなどで典
型的に必要な target はあらかじめ定義されている。自由に追加
することもできる。
–46前後関係や依存関係をまとめるために利用されるsystemd.special(7) を参照multi-user.target の例
multi-user.target は主なサービス群を動作させたい従来のラン
レベル 3 に相当する。
定義ファイルを見ると説明と依存関係のみ
/lib/systemd/system/multi-user.target47(略)
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
multi-user.target の依存関係
systemctl show multi-user.target で unit を見ると多数のサービスにWants と After で依存。 active にすることで多数のサービスが起動する。
$ systemctl show multi-user.target
(略)
Requires=basic.target
Wants=dbus.service plymouth-quit.service chronyd.service sshd.service tuned.servicersyslog.service sssd.service pmlogger.service plymouth-quit-wait.service rhsmcertd.service
systemd-ask-password-wall.path pmcd.service systemd-user-sessions.service atd.service systemdlogind.service firewalld.service NetworkManager.service remote-fs.target getty.target dnfmakecache.timer crond.service auditd.service systemd-update-utmp-runlevel.serviceRequiredBy=graphical.target
Conflicts=shutdown.target rescue.service rescue.target
Before=shutdown.target systemd-update-utmp-runlevel.service graphical.target
After=atd.service sshd.service sssd.service rescue.target chronyd.service tuned.serviceNetworkManager.service pmlogger.service systemd-logind.service plymouth-quit-wait.service
plymouth-quit.service rsyslog.service firewalld.service crond.service pmcd.service systemd-usersessions.service dnf-makecache.timer dbus.service basic.target rhsmcertd.service getty.target
rescue.service48(略)Install 処理での依存関係の追加
multi-user.target の unit file に存在しない Wants は以下のディレクトリにあるリンク群
に由来する
tuned
multi-user
/lib/systemd/system/multi-user.target.wants/
.service
Wants
.target
/etc/systemd/system/multi-user.target.wants/
–/etc/systemd/system/*.wants および *.requires ディレクトリは unit file を拡張する
–49unit file の enable 時に [Install] 節の定義によりリンクを作成する
例 : シンボリックリンク multi-user.target.wants/tuned.service は
Wants=tuned.service の追記に相当。
さらに依存関係解決により、 tuned.service 内の Requires= で参照している
dbus.service, polkit.service も multi-user.target の Wants= へ追加される
ネットワーク初期化での .target 例
RHEL 8 ではネットワーク初期化に NetworkManager(NM) を使うが、各種
サービスは直接 NetworkManager に依存せず network.target や networkonline.target へ依存している。
network-pre.target
–NM networkネットワーク初期化をはじめる準備ができた (NM.service の After= に指定 )network.target
–ネットワーク初期化をはじめた (NM.service の Before= に指定 )network-online.target
–ネットワークで外部と通信できるようになった (NM-wait-online.service の
Before= に指定 )ネットワーク初期化に NM 以外を利用する場合も、 target は同じなので
サービスは target との依存関係だけを持てばよい。
50networkpreNM-wait-online networkonline関連する記事
Running Services After the Network is up
https://www.freedesktop.org/wiki/Software/systemd/NetworkTar
get/関連する man page51systemd.target(5): target unit の説明systemd.special(7): systemd がデフォルトで提供する *.target の説明bootup(7) : systemd がデフォルトで提供する *.target の依存関係を表現した図やってみよう
systemctl list-units -t target -a でどんな target があるか一覧を見る
–※LOAD 欄が not-found となっている unit は他から参照されているが unit file
は存在しない
52例 :syslog.target は systemd 202 よりあとには存在しないsystemctl show shutdown.target の ConflictedBy= 行を見る。
shutdown.target を active にしようとするとここに記載された unit 群は競
合するため inactive にされる。/etc/systemd/system/multi-user.target.wants/ 以下にあるリンクか
ら中身を見て、 [Install] 節を確認する。
service unit
サービス管理53systemd の service って何するの ?54サービスが動作する環境を用意サービスを起動 ( 通常何らかのプロセスを開始 )起動したサービスを監視
–stop やシャットダウン時などの操作–異常終了の検出、再起動などの対応サービスのイメージ図
1. systemd は fork() して、子プロセスを cgroup に入れる
systemd
cgroup, 環境変数 , uid etc.
systemd →
プロセス2. 環境を設定してから
exec() でプロセス実行
プロセス
child
proces553. プロセスがデーモン化や子プロセスの
生成などを行っても cgroup で追跡する
サービスが動作する「環境」って ?56環境変数ulimitUID, GIDnice 値numa ポリシーCPU アフィニティCapabilitySELinux contextcgroups でのリソース制御
–CPU, メモリ , ストレージ I/O, 直
接アクセスできるデバイスseccomp でのシステムコール制限
namespace を使ってファイルシス
テムの一部を bind mount して変更
サービス毎の firewall 設定
などサービスを起動
基本的にはプロセスを fork(), exec() するプログラムによりいろいろな動作があるのでいくつかの type を提供している
–
–57デーモン化するもの、デーモン化しないもの
プロセスが生き続けてサービスを提供しつづけるもの、最初と最後に設定変更をす
るだけで動作しつづけるプロセスがないもの–(systemd がうまく扱える ) socket や dbus で待ちうけするもの–systemd に対応して通知してくれるもの、 systemd への対応はないものservice は type により「どうなったら active とみなすか」の詳細がことなるdaemon 利用時のイメージ
systemd
cgroup, ulimit, namespace, 環境変数 etc.
service process1. exec() して環境の中でサービス
実行開始 . daemon 化して exit()
main processpidfile2. PID ファイルなどで
main process を
systemd が推定child process
58おさらい : daemon 化による端末との切り離し
rccd /
stdin, stdout, stderr を /dev/null へ接続
fork()
setsid()termservice process termdaemon 化をする目的は端末から
切り離して(SIGPIPE, SIGSTOP, SIGTERM
などの ) シグナルを受けない画面にゴミを出さない59端末から影響されないmain process
pidfile
child processsystemd の環境と daemon 化
60systemd は service に割りあてる stdin, stdout, stderr をどう構成するか明示
的に設定できる
–/dev/null, 端末 , socket, ファイル , journal など–systemd.exec(5) の Logging and Standard Input/Output可能 ( プログラムに“ foreground mode” などのオプションがある ) であれば
Type=simple を使う。この場合 stdout や stderr へメッセージを出すなら
journal に接続して記録できる。
daemon 化を避けられない場合は Type=forking にして PIDFile で監視するべ
きプロセスを伝える。 stdout や stderr はセットアップされるが、 daemon
化で /dev/null へ接続されなおすのでその後は使われない。
Type=notify 利用時のイメージ
systemd
socket1. fork, exec しただけでは unit は active ではなく activating
2. libsystemd の sd_notify() 関数で準備完了のメッセージを
受けとると active にするREADY=1main processchild process61よく使われる type と使い分け
よく使う service の type は以下 3 種類simple
–service実行されたプロセスがさらに子プロセスを作
りデーモン化するタイプ。古典的な daemon
はこの type 。 stdout,stderr 経由の log が使え
ないため選べるなら simple のほうがよい。simple
childserviceforking
main
childoneshot
–62forkforking
–実行されたプロセスが直接サービスを提供す
るタイプのプログラム。systemd–何かの初期化など一時的に実行するだけです
ぐに終了するもの。
長期間 ( 数分〜 ) 動作するものには向かない。serviceoneshot
childservice が active になる条件
Activating
InactiveActiveexec: fork(), exec() が成功すると activeforking: プロセスを起動して main process の PID を確認すると active63simple, idle: fork() が成功すると activeoneshot: fork() が成功して activating 、 exit() すると inactive 。 active
にならない。
oneshot(RemainAfterExit つき ): fork() したプロセスの exit() が成功だと
activedbus: dbus 上で指定した名前の待ちうけが行われると activenotify: sd_notify で通知が行われると active
startservice の起動フロー
fail前処理 : ExecStartPre
↓
fail
本体 : ExecStart
↓
確認等 : ExecStartPost fail上から順に実行して、成功の場合は次へ進む
–ExecStartPost の実行開始タイミングはいつかが異
なる
どこまで起動が進んでいるかにより ExecStop,
ExecStopPost を実行する
–stop本体終了 : ExecStop
↓
後処理 : ExecStopPost
64running
の場合service の type によりいつ active になるか、終了処理で失敗すると unit は failed 状態になる起動・終了それぞれにデフォルトで 1 分 30 秒の
タイムアウトが設定されている。どの Exec* も
失敗する可能性があるreload設定リロード : ExecReload
active な service の終了検出
systemd は service の終了を検出できる
––65プロセスが exit() した場合、 systemd は PID 1 なので SIGCHLD
を受信し、 signal や exit code がわかる。
systemd の notify に対応している場合
定期的な watchdog 送信sd_notify でのサービス状態の通知ExecStopPost= での終了処理を行う。その後 Restart= により
再度 service を active にするよう指定もできる。
service への start 以外の操作 ( 一部 )
stop
–service が active であれば ExecStop, ExecStopPost を実行する–service が signal などで殺された場合 ExecStopPost を実行する–service が inactive であれば何もしない (sysvinit と異なる振舞いなので注意 )kill
–cgroup を利用して指定した service に関係するプロセス全てへシグナルを送る
例 ) libvirtd が dnsmasq を起動して stop しても dnsmasq はそのまま残る。関連プロセス
を全て落とすには kill を使う。66reload
–設定ファイルを読み直す–ExecReload= を指定している場合のみ実行可
起動終了処理のカスタマイズ
条件確認
––ExecCondition= ( 何かを実行して実行結果で条件確認 )–StartLimit*= (start の頻度に制限をかける )実行の成功失敗判断
––67Condition*= ( 各種条件を確認し、条件を満たす場合に実行する。
ConditionPathExists=, ConditionVirtualization= など )Exec*= に指定する実行ファイル名の直前に” -” をつけると exit code を無視し
て成功とみなす。
SuccessExitStatus= exit code のうち成功とみなすものと、受信シグナルのうち
成功とみなすものを追加する
サービスの起動順序が意図と違う ?
“ 意図通りの実行順にならない” ケースの多くは以下 2 つ
依存関係 (Wants, Requires) で指定したものが先に実行されると思った
–
–これらで指定したものが起動しているか、サービス開始しているかは関係な
くサービスを起動しはじめる前後関係 (After, Before) がサービス開始の前後関係であると思った
–
–68指定されたものの activation は job queue に入る ( だけ ) 。プロセス起動の前後関係は守られる
サービス開始したかはわからない (Type=dbus か notify でなければプロセス
が起動したことしか見ていないから )
余談 : 前後関係でループができたら?
設定ミスによりループができるケースがある
このような場合 systemd は (Wants= だけで
参照されているような ) 必須ではない unit を
無視・停止してループを消そうとする。69B.serviceAfter
AfterA.serviceプロセスの起動順序ではなく
サービスの起動順序を守らせるには ?
短時間 ( 〜 1 分 ) で初期化が終わる場合は ExecStartPost で対応
きっちりやる派 ( 確認プロセスの終了ステータスで伝える ):
Type=forking または simple にして
ExecStartPost= でサービス検出を確認したあと exit(0) する。
–70service unit のタイムアウトによる失敗処理があるので確認プロセスは無限に
待つ素朴なプログラムでよいだいたい動けば OK 派 ( ちょっと待つ ):
ExecStartPost=/usr/bin/sleep 30sプロセスの起動順序ではなく
サービスの起動順序を守らせるには ?( 続 )
プロセスの起動からサービス開始まで長時間 (1 分〜 ) かかる場合はプロセス
起動のタイムアウト処理とサービス開始の検出を分離する。
プログラムを systemd に対応させる派 (notify)
–サービスの動作確認をするだけの別サービスを用意する
NetworkManager.service→NetworkManager-wait-online.service
–71Type=notify として、サーバプロセスから準備 OK の通知をもらう ( 起動され
るプログラム内での対応が必要 )Type=oneshot で TimeoutStartSec=infinity, RemainAfterExit=true として
ExecStart= でサービスの動作を確認するプロセスを起動する
プロセスの実行環境 ( 再掲 )
1. systemd は fork() して、子プロセスを cgroup に入れる
systemd
cgroup, 環境変数 , uid etc.
systemd →
プロセス2. 環境を設定してから
exec() でプロセス実行
プロセス
child
proces723. プロセスがデーモン化や子プロセスの
生成などを行っても cgroup で追跡する
systemd-run でサービスの実行環境を調べる
例「 PrivateTmp=yes とされている環境ではどうなるか調べたい場合」systemd-run -S -p PrivateTmp=yes
–echo $$ で自分の PID を確認する–lsns -t mnt で shell が独自の mnt namespace に入っていることを確認する–/tmp, /var/tmp に何もないことを確認する
73/var/tmp は /var/tmp/systemd--/tmp を bind mount
される。 /tmp は外から見えない関連する man page
74systemd.service(5): service についての unit file でデフォルトで含ま
れる依存関係、各 type の動作、 Exec* で使える特殊な記法、 service
特有のディレクティブ、コマンドライン風のパイプおよびリダイレク
ト処理
systemd.exec(5): (cgroup 以外の ) プログラムの実行環境を準備する
ためのディレクティブ
sd_notify(3): systemd へ通信をする C 言語での関数
systemd-notify(1): sd_notify() を呼ぶコマンド。シェル等で利用す
る。
やってみよう
75/lib/systemd/system/ で simple, oneshot, forking, notify の例を探す。
※ Type= がない service はデフォルトの simple
Type=oneshot の例をコピー・改変して /bin/echo foobar するだけの unit file
foobar.service を作成する
–/etc/systemd/system に配置、 systemctl daemon-reload で読み込み–systemctl start foobar.service してログに foobar が記録されていることを確認する–systemctl status foobar.service して状態を確認–RemainAfterExit= の設定を反対にして同じことを繰り返して動作の違いをみる複雑な service unit の例として nfs-server.service か libvirtd.service を見てみる
socket, path, timer unit
イベントによる service 起床76何かのイベントを契機に service を起動する
systemd では「イベントを契機にして service を起動する」仕組
みを提供し、 unit の組み合わせとして管理する
socket, path, timer
イベントを検出するとデフォルトでは
同じ名前の .service を active にする
–77Service= で任意の service unit を指定できるfoo
.socketAfterfoo
.servicesocket unit
systemdsystemd が socket を listen する。
–socket
プロセス–socket–socket
.target*.socket78foo 起動
bar 起動
baz 起動起動のごく初期に listen を開始するので一
般のプロセスによるランダムなポート
open との競合を回避する
socket の listen と service の立ち上げを分
離すると、 socket だけ先に作っておけば
互いに socket で通信する service 群の起動
を並列化できる。
socket の利用を開始すれば自動的に相手
を待つ。対応する service unit の起動時に socket
をひきつぐ。
–foobar.socket には foobar.service が対応別名の service への対応づけも指定可
–「 socket の引き継ぎ」ってどうやるの ?
systemd が socket unit で待ちうけていた socket を service unit
へ渡す方法は…… ?
79inetd 方式 : service unit で StandardInput=socket として標準
入出力を socket とのやりとりに使う
libsystemd 方式 : systemd が service 実行時に fd 群を設定す
る。サービスを実行するプロセスは sd_listen_fds() 関数で fd の
数や属性を取得する。socket activation
起動時は socket unit だけ active にしておき service は起動しないsystemd が socket への着信を検出すると service を起動する
–801 回目の通信には遅延が発生するservice の [Install] 節に通常の service と同様 WantedBy= 等を挿入するよ
う定義することで、ユーザーが unit の動作を選べるようにもできる
–enable してシステム起動時の起動対象にする–disable して socket activation の対象にするservice で Also= として socket をインストールすることで service の
enable/disable とセットで socket の確保を指定できる
path unit
systemd が path の存在・変更等を inotify() で監視する
socket activation と同様に指定されたイベントがあれば対応する service
を起動する
service は特にイベントを受信したり共有したりはしない
systemd
inotifyプロセスfile,dir
file,dir
file,dir
81timer unit
timer はいくつかのイベントから xx マイクロ秒経過のような表現で定義
socket activation と同様に指定されたイベントがあれば対応する service
を起動する
timer unit は複数のタイマーイベントを定義できるsystemdtimer
82プロセス余談 : timer の扱うイベント
timer はさまざまなイベントからの相対時間を指定できる
83OnBootSec= システムが起動してからの相対時間
OnStartupSec= systemd が起動してからの時間。 system 全体を管理する
systemd では OnBootSec とほぼ同じ。ユーザセッションではログイン直後のタ
イミングからの相対時間になる。OnActiveSec= timer unit 自身が active にされてからの相対時間OnUnitActiveSec= timer に対応する service unit が active になってからの時間OnUnitInactiveSec= timer に対応する service unit が inactive になってからの時間OnCalendar= カレンダー上の時刻、 cron 的な指定ができる
timer の繰り返し (1)
繰り返し実行させたい場合には、 OnBootSec= と
OnUnitInactiveSec= を組みあわせて実現システム
起動84OnUnitInactiveSecOnUnitInactiveSecOnBootSecservice 実行service
実行service は Type=simple
実行終了して
inactive になった
servictimer の繰り返し (2)
繰り返し実行させたい場合には、 OnBootSec= と OnUnitActiveSec= を組
みあわせて実現。実行時間が OnUnitActiveSec より短いことが必須。OnBootSec
システム
起動OnUnitActiveSecservice 実行OnUnitActiveSecservice
実行service が active になった
85OnUnitActiveSecservice 実行servictimer をわざとずらす
86AcculacySec= timer で指定された時刻をどれだけの精度で実
現するか。デフォルトでは 1 分。すこしずつ異なるタイマーイ
ベント群にもとづくアクションの実施タイミングを揃えること
で消費電力削減に役立つ。
RandomizedDelaySec= timer で指定された時刻をランダムに
最大どれだけ遅延させるか。デフォルトは 0 。クラスタ環境で
同じプログラムが同時に実行されることにより、負荷が過度に
集中することを避けるために利用する。
path, socket, service 連携例 cupsd (1)
cups.service
[Unit]
Description=CUPS Scheduler
After=sssd.service network.target ypbind.service
[Service]
ExecStart=/usr/sbin/cupsd -l
Type=notify
Restart=on-failure
[Install]
Also=cups.socket cups.path
WantedBy=printer.target
87ExecStart= 起動時に実行するコマンド。 ExecStop 等の指定がないので終了時はここで作成さ
れたプロセスへ「 SIGTERM 送信→タイムアウト待ち→ SIGKILL 送信」による終了処理を行う
Also= この unit を有効にする時に指定した unit も有効化する
WantedBy= enable すると依存関係を挿入する。 printer.terget を有効化すると cups.service
も有効化の対象になる
path, socket, service 連携例 cupsd (2)
Socket Activation
cups.socket
[Unit]
Description=CUPS Scheduler
PartOf=cups.service
[Socket]
ListenStream=/var/run/cups/cups.sock
[Install]
WantedBy=sockets.targetListenStream= 指定したソケットを systemd が待ちうける
systemd がソケットの listen を行い、はじめて接続がおこなわれた時点で対応する
サービスを起動する (Socket Activation)
–88この例では cups.socket を待ちうけて着信があれば cups.service を起動
path, socket, service 連携例 cupsd (3)
Path based Activation
cups.path
[Unit]
Description=CUPS Scheduler
PartOf=cups.service
[Path]
PathExists=/var/cache/cups/org.cups.cupsd
[Install]
WantedBy=multi-user.target
89ファイルやディレクトリの存在や変更を検知して対応するサービスを起動す
る (Path based activation)
この例では /var/cache/cups/org.cups.cupsd が存在すれば cups.service を
起動する
timer と service の連携例 systemd-tmpfiles-clean.timer
systemd-tmpfiles-clean.timer
[Unit]
Description=Daily Cleanup of Temporary Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
[Timer]
OnBootSec=15min
OnUnitActiveSec=1d
90時間の経過を契機として service を起動する
この例ではシステム起動後 15 分、その後 1 日おきに systemd-tmpfilesclean.service を起動する関連する man page
systemd.socket(5), systemd.path(5), systemd.timer(5): 各種
類の unit の説明、利用できるディレクティブなどsystemd.time(7): 時刻、時間の表記法systemd for Developers I
–91http://0pointer.de/blog/projects/socket-activation.htmlやってみよう
lsof -p 1 で systemd が多くの socket を待ちうけていることを確認
–92systemctl -t socket で socket unit を確認して照らしあわせるsystemctl list-timers で今予定されている timer の起床一覧を見る
fstrim.timer は 1 週間に 1 回 service を起動する設定になってい
る。 drop-in を使って 1 日に 1 回に書き換えてみる。
/lib/systemd/system/*.timer を見ていろいろなタイマーの使い方のパ
ターンを見るdevice unit と mount unit
ファイルシステムの mount93デバイス検出から mount まで94主な登場人物 : linux kernel, udev daemon, systemd, fstab関係する unit
–.device–.mount–local-fs.target, remote-fs.targetデバイス検出から .device unit 作成まで
*.rulesudevuevent/sys/devsystemd/run/udevカーネル
ハードウェア
951)ハードウェアの追加や変
更を kernel が検出
2)uevent を udev が受信
3)udev の *.rules により /dev
以下にファイルを作成し
たり、 systemd 用の情報
を付加したりする
4)systemd は udev によ
り” systemd” と TAG が付
与されたデバイス
の .device unit を作成するfstab から mount unit を生成
systemd-fstab-generator
–/etc/fstab を解析して、対応する mount unit 定義を生成する例 : fstab の ” /dev/mapper/snake-home /home xfs
生成された /run/systemd/generator/home.mountdefaults 0 0” という行から# Automatically generated by systemd-fstab-generator
[Unit]
SourcePath=/etc/fstab
Documentation=man:fstab(5) man:systemd-fstab-generator(8)
Before=local-fs.target96[Mount]
Where=/home
What=/dev/mapper/snake-home
Type=xfs余談 : systemd-fstab-generator 実行タイミング
systemd の起動直後と、 systemd daemon-reload 実行時に
systemd-fstab-generator は実行される。つまり……
–
–97initramfs 内での起動直後、 initramfs 内の fstab から unit 生成
root directory を変更して systemd を読み直した直後、
/etc/fstab から unit 生成fstab を編集して手動で mount を行う操作はひきつづき有効なの
で利用していても特に今までと違いはない余談 : systemd-mount, systemd-umount
systemd の mount unit はちょっと賢い
–親ディレクトリの mount や、ネットワーク接続を待つ–automount–98その他任意の unit の依存関係が書けるので mount が成功するのを待ってサービ
スを起動する等賢いのはいいが使うのに都度 fstab に書いて generator を実行して systemctl
start foobar.mount するのは面倒なので……
→ 専用コマンド systemd-mount が用意されているlocal-fs.target, remote-fs.target
local-fs.target: ネットワーク不要で mount できるファイルシス
テム
–remote-fs.target: ネットワーク初期化後に mount できるファイ
ルシステム
–99fstab に書かれている local fs はこの target から依存されるfstab で _netdev オプションが書かれているとこの target から依存
される関連する man page
100systemd.mount(5): fstab に書くオプションについてここに記
載されている
systemd.device(5): udev rules で定義する変数について記載が
ある
udev(7), udevadm(8): udev database を見たりイベントをモニ
タしたいときは udevadm コマンドで見るやってみよう
root fs のデバイスを ROOT として。
–udevadm info ROOT の出力をみる
101TAGS= に systemd があることを確認する/lib/udev/rules.d/99-systemd.rules を眺める
–対応しそうな device unit を systemctl show して照らしあわせる (DEVPATH と
Description 等 )printer サブシステムのデバイスがあると SYSTEMD_WANTS 経由で printer.target
を要求USB メモリを挿入したり loopback device を作成して対応する device unit がで
きていることを確認する
slice, service, scope unit
cgroup 管理102cgroup って何 ?
linux が持つプロセスをグループ化する仕組み control group の略
–
–103主にリソース管理を行うために利用する
全てのプロセスはいずれかのグループに所属し、子プロセスは明示的な
移動がなければ親プロセスと同じグループに所属しつづけるcgroup の利用シーン例
104特定サービス , VM, コンテナだけで特定 CPU を占有、他のサービスや
ユーザセッションでは利用できる CPU を制限
主にサービスを実施するマシンで
–ユーザの対話セッションで利用できるリソースを制限–Ansible や Puppet が使うリソースを制限サービスに最低限必要なメモリ量を設定 (cgroup v2 が必要 )コンテナ毎に利用できる IOPS を設定 (cgroup v2 が必要 )cgroup によるリソース管理の特徴
cgroup はツリー状にグループを分類して、グループに対してリソースを割り当てる各グループ毎にリソース制御の設定が可能–CPU 使用率の比–IO スループット–メモリ +Swap の割り当て量の上限、下限–アクセスできるデバイス–ネットワークのクラス付け などcgroup v1 と、 cgroup v2 が存在する。 2020 年時点では cgroup v2 への過渡期。
–105systemd は cgroup v1 および v2 の両方に対応しているが、 cgroup のバージョンにより使
えるディレクティブが異なる。
systemd と cgroup の関係
各 unit には対応する cgroup がありリソース管理以外でも活用される
–
–リソース管理を行わない場合にも、各 unit から実行されるプログラムは対
応する cgroup 内で実行される。そのためあるプロセスがどの unit に所属
しているかが linux kernel により自動的に追跡される。systemd は cgroup を管理してリソース管理をおこなう
––
106systemd は各 unit を初期化する時にグループの作成・設定をおこなうcgroup のパスは slice, scope, service, socket, mount, swap のいずれかの
unit に対応づけられ、各 unit の設定としてリソース制御の指定をおこなう
systemd が直接管理する他に、部分的に管理を移譲する API がある
cgroup と関連してよく使う 3 種類の unit
slice: cgroup のグループ分け用の unit
–service: systemd が管理するプロセスおよびその子プロセス群
–各 service は自動的に対応する名前の cgroup の中に入れられるscope: systemd 以外のプロセスが fork&exec& 管理をおこなう
ものを API で登録する
–107slice を単体で宣言する他 service の Slice= で指定して作成systemd-run, gdm, gnome-launchd などは作成したプロセスを
scope で作成した cgroup の中に入れる
デフォルトの 3 種類の slice
User slice
–ユーザセッションに対応するプロセスや service を格納する–各ユーザ用の systemd ( 後述 ) を起動–各ユーザの service を起動System slice
–Machine slice
–108システムサービスを格納する仮想マシン、コンテナ等を格納する
user slice, system slice, machine slice109前述の 3 つの slice の下にユーザ毎、サービス毎、 VM 毎などツリー状に分類される
systemd-cgls
cgroup の階層構造と所属プロセスを一覧表示する110-.slice
├─user.slice
│ └─user-11956.slice
│
├─session-3.scope
│
│ ├─1909 gdm-session-worker [pam/gdm-password]
│
│ ├─4727 /usr/bin/gnome-keyring-daemon --daemonize --login
│
│ ├─7654 /usr/libexec/gdm-x-session --run-script /usr/bin/gnome-session
│
│ ├─7663 /usr/libexec/Xorg vt2 -displayfd 3 -auth /run/user/11956/gdm/Xauth>
│
│ ├─8020 /usr/libexec/gnome-session-binary
│
│ └─8225 /usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "/usr/bin/gnome>
│
└─user@11956.service
│
├─gsd-xsettings.service
│
│ └─8764 /usr/libexec/gsd-xsettings
│
├─gvfs-goa-volume-monitor.service
│
│ └─8657 /usr/libexec/gvfs-goa-volume-monitor
│
├─gsd-power.service
│
│ └─8723 /usr/libexec/gsd-powersystemd-cgtop
cgroup 毎に CPU, メモリ ,I/O 使用量を表示する。ここで表示
するには accounting(cgroup での資源利用追跡 ) が有効になっ
ている必要がある。111Control Group
/
/system.slice
/system.slice/NetworkManager.service
/system.slice/atd.service
/system.slice/auditd.service
/system.slice/boot.mount
/system.slice/chronyd.service
/system.slice/cockpit.socket
/system.slice/crond.service
/system.slice/dbus.service
/system.slice/dev-hugepages.mount
/system.slic…-mapper-rhel\x2dswap.swapTasks
213
57
3
1
4
1
1
2
-%CPU
-Memory
2.9G
2.7G
7.5M
644.0K
9.2M
92.0K
3.1M
2.2M
2.2G
28.8M
632.0K
456.0KInput/s Output/s
-ユーザのリソース制限
各ユーザは user-.slice により定義されるので、この unit に対して定義を
おこなうことでユーザのリソースを制限できる
–
–/etc/systemd/system/user-.slice.d/resources.conf
全ユーザに対して同じ設定を指定したい場合は、 user-.slice がテンプレートなので
そこへ定義を記述することで全ユーザへ影響するログイン時に pam_systemd により cgroup の作成・切り替えが行われる
–su や sudo では cgroup は切り変わらないのでリソース管理上は同じユーザのまま–cgroup を変えたい場合は systemd-run を使うか ssh などでログインしなおす設定例 : /etc/systemd/system/user-1000.slice.d/resources.conf
112[Slice]
CPUQuota=120%関連する man page
systemd.resource-control (5): unit に対する cgroup でのリ
ソース制御。 cgroup v1 、 v2 の違いは Unified and legacy
control group hierarchies 節にまとまっている。
RHEL7 ドキュメント「リソース管理ガイド」https://access.redhat.com/documentation/ja-jp/red_hat_enterpri
se_linux/7/html-single/resource_management_guide/index
113linux kernel ドキュメント「 Control Group v2 」
https://www.kernel.org/doc/Documentation/cgroup-v2.txt
やってみよう
systemd-run -p CPUQuota=10% -t yes > /dev/null として (--user では制限されないので注
意)
–top で CPU 消費量を見てリソース制限されていることを確認する–/proc//cgroup を見て cgroup 名を確認–/system.slice/run-u492.service のような名前なので、 /sys/fs/cgroup/cpu,cpuacct/ 以下から
対応するディレクトリをみつけ、 cpu.cfs_period_us, cpu.cfs_quota_us を比較する/etc/systemd/system/user-.slice.d/resources.conf に以下を記述する
[Slice]
CPUQuota=123%114ログインしなおしてから systemd-cgtop で消費の様子をみるsu, sudo 前後で /proc/self/cgroup を見て追跡されている様子を確認する
ユーザセッション用 systemd115ユーザセッション管理
systemd-logind がユーザセッションを追跡する。
–116どのユーザが、いつから、どの seat( 通常ひと組のディスプレイ、キー
ボード、 USB ポート等 ) からアクセスしているか、関係するプロセスは
どれかの追跡–周辺装置の権限管理–idle 検出、サスペンド・レジューム、電源断–セッションのロック、強制終了、有効化、終了時の関連プロセス kill などloginctl コマンドで操作する
systemd の仕組みをユーザ用に使う
各ユーザで systemd を利用できると便利
ユーザごとの service 管理
–
–117tmux 、 emacs server 、デスクトップ環境での各種サービス等
ハードウェア利用 ( スマートカード、 Bluetooth アダプタ等 ) の
ためのサービス起動–システムのサービスと同じ仕組みで管理–今まで混在していたり失われていたログを journald へ蓄積
ユーザ用 systemd
各ユーザの systemd インスタンス (service manager) は
systemd --user として起動される。
––
118/lib/systemd/user , ~/.local/share/systemd/user, /etc/systemd/
user, ~/.config/systemd/user から unit file をロードする
起動時は default.target を active にするよう動作するsystemd のインスタンスと配下の service 群は「セッション
毎」には対応せず「ユーザ毎」に対応する。そのためログアウ
トのタイミングで終了するとは限らない。
ユーザ用 systemd からのリソース管理
デフォルトではユーザ用 systemd から cgroup によるリソース管
理は memory, pid しか利用できない。他のリソースを管理するに
はシステムの systemd から管理を移譲する設定が必要。
–例 : /etc/systemd/system/user@.service.d/override.conf
[Service]
Delegate=yes–119cat /sys/fs/cgroup/user.slice/user-11956.slice/cgroup.controllers
のようにして cgroup の設定を確認ログイン時の動作
ログイン認証時にから pam_systemd を
動作させる。
pam_systemd はログインにあたりいくつ
かの作業をおこなう
–ユーザ用の /run/user// を作成–対話セッションに対応する番号を作成–120セッション毎の scope を作成、まだ存在
していなければユーザ毎の systemd イン
スタンスを起動する
ユーザプロセスの自動 kill
ユーザ用 systemd で管理される service および scope 内のプロセスは以下の条件で kill
される
セッション終了した場合の動作は logind.conf 内の KillUserProcess= 設定による :
–
–No( デフォルト ): 特に何もしない
Yes: ユーザがログアウトした時にそのセッションに対応する scope 以下のプロセスを
kill する。さらに特定ユーザのみ kill 対象、特定ユーザのみ kill 対象外の設定も可。
121kiosk 端末などで便利だが tmux, nohup 等のログアウト後に実行を継続されてほし
いソフトウェアにとっては想定と異なる動作になるユーザ用 systemd が SIGTERM, SIGINT をうけると shutdown.target が有効化され
(Conflict しているサービスが終了す ) る。
loginctl enable-linger とは ?
英語の linger は「居残る、長引く、なかなか消えない」というような意味
ユーザは自分の全セッションが終了しても scope, service を自動で kill しないよう指
定することができ、 loginctl enable-linger がその指示を行うコマンド。
運用管理者は PolicyKit の設定で linger の指定を禁止することもできる。そのため実
用上は以下の 3 種類から動作を選べる
–
––122enable-linger を禁止してセッション終了時に全プロセスを kill する (kiosk 端末など )
enable-linger したユーザのプロセスは kill しない、していないユーザのプロセスは kill
する
セッション終了をきっかけとして kill はしない ( デフォルト )関連する man page
123systemd-logind(8), logind.conf(5), loginctl(1): セッション管
理を行うサービス、設定ファイル、管理コマンド
pam_systemd(8): ユーザログイン時の動作を行うための PAM
モジュール
systemd-user.conf(5): ユーザ用 systemd の設定は /etc/
systemd/user.conf に分けて定義される。記述内容はシステム
用のものと同じ。
やってみよう
loginctl で現在のセッションを見たあと
––124loginctl show-session < セッション ID> で systemd-logind が追
跡しているものを見る
loginctl seat-status でシートに対応づけられているデ
バイスを見る。これらのデバイスは対応するセッションのユーザ
からアクセスできるよう設定される。systemctl --user list-unit-files などを行いユーザセッション用
の unit file を眺める
アドホックなコマンド実行の管理125systemd-run
アドホックにプログラムを実行する際にも systemd の仕組みを使いたい
––
126ulimit, cgroup, ロギングなどの環境準備を自作しなくても systemd に任せられ
る
シャットダウン時に”正しいお作法で”終了してくれるsystemd-run で実行すると使い捨ての service または scope を作成する
–service を activate する path,timer,socket も特定オプション作成–systemd-run --uid=apache /usr/bin/foobarsystemd-run 利用例
systemd-run ls
–systemd-run --uid=apache -t ls
–uid を apache にし、標準入出力を端末へ接続して ls する。systemd-run --scope ls
––127一時的な service を作成して systemd が実行。環境変数や標準出力が journal
に記録されること、 CWD が / になることなども service と同様。一時的な scope を作成して systemd-run がその中に入って ls を実行。 cgroup
でリソース管理される以外は直接実行するのとほとんど変わらない。
scope の場合は systemd から実行されない点が大きく異なる
systemd-run の service と scope の違い
service
親プロセスsystemdsystemd-run を実行したプ
ロセス ( 多くの場合 sh)標準入出力journal 。 -t オプションな
どで変更できる。親プロセスをひきつぐ環境変数systemd の service 用設定
に従う親プロセスをひきつぐcgroup, 環境変数、
uid,gid などなどcgroup だけsystemd-run -Ssystemd-run --scope bashsystemd が制御する環境
実験用 shell 起動
128scopesystemd-run を nohup のかわりに使う
systemd-runnohupコマンド例loginctl enable-linger
systemd-run foobarnohup foobar 2>&1 &ログ出力先journal
オプションで任意ファイルnohup.logsystemd に unit 終了のログnohup.log を open しているプロ
セスを fuser で探す終了確認SIGSTOP, SIGTERM
SIGSTOP, SIGTERM
シャットダウン時 -p ExecStop= 指定で任意コマン
ド実行
129taskset, ulimit 等のかわりに systemd-run を使う
systemd-run の -p オプションでリソース制御ができる。 -t オプションで端末との接続
を維持する。
systemd-run -t -p BlockIOWeight=10
count=10000 oflag=direct
–core 出力サイズを抑制して実行するsystemd-run -t -p CPUAffinity=0-1 ./mytest
–130cgroup v1 で IO のスロットリングをしつつ実行する。 cgroup v2 では BlockIOWeight
ではなく IOWeight を使うsystemd-run -t -p LimitCORE=0 ./mytest
–dd if=infile of=outfile実行可能 CPU を 0 と 1 だけに制約して実行する
関連する man page
systemd-run(1): systemd-run の利用例などsystemd.resource-control(5): cgroup に指定できる項目131systemd.exec(5): プロセス実行で指定できる項目。 scope で
は指定できない。やってみよう
132systemd-run env と systemd-run --user env で環境変数が異なる
( 後者はデスクトップ環境や X の設定なども含む ) ことを確認する
systemd-run -S で service のコンテキストで shell を実行す
る。 echo $PPID が 1 であること、 systemd-cgls で shell から実
行されているプロセスも含めて service 内にあることを確認する
systemd-run -S -p PrivateTmp=yes -p ProtectHome=yes のよう
なセキュリティ設定をおこなって /tmp や /home がどのように見
えるか確認する
systemd-journald によるロギング133従来の syslog にあった課題
時刻が秒単位で粗いため複数ホストのログを集約すると前後関係がよくわか
らない。時刻が localtime で夏時間がある地域では 1 時間隙間が進んだり戻ったりする接続元、指定された優先度などのメタデータが失われる134syslogd が起動する前の boot 直後のログを統合できない構造化されていないため DB などに投入しにくい。 NUL などを含むデータを
ログに入れられないなど制限が厳しい。
保存されたログへのアクセス制御が粗いsystemd とログを統合したい
135systemd はシステム起動のごく初期から起動される
→同じ基盤でログの仕組みを作れば起動直後から記録できる
unit 用に用意する環境の標準出力 (stdout, stderr) を /dev/null へ捨てる
のではなくログへ保存して簡単にサービスを作りたい
systemd が管理している環境についての ID 各種 (machine ID, boot ID,
cgroup 名、 unit 名など ) の情報をログに付与して、イメージを複製し
た複数 VM や再起動の前後、どの unit からのログかを識別したいsystemd-journald によるロギング
詳細なメタデータ付加
–136マイクロ秒 64bit でのタイムスタンプ , 起動からの時間 , ログの優先度 , systemd の
unit, cgroup, SELinux コンテキスト , boot ID, machine ID 等独自バイナリフォーマット
–圧縮・インデクシング・改竄検出対応–テキスト log が必要な場合 rsyslog と併用する (RHEL 7, 8 でのデフォルト )自動的かつ透過的な rotatejournalctl コマンドによるクエリデフォルトでは journald のログは揮発性だが /var/log/journal を作ると永続化
systemd-journald イメージ図バイナリログ
uid 毎に分離
ACL で本人には
読み込み許可/dev/kmsg
syslog 対応
ソフト/dev/loguser-1000.journalsystemdjournaldsystem.journalunit 内 stdout, stderr
journald 対応
ソフトアーカイブrsyslog/var/log/*
137journalctlテキストログ保存
従来との一貫性、互換性system@ 〜 .journalクエリにより
journal file 群から
ログを検索・整形・表示journald で付加されるメタデータ例138カーソル位置
時刻 (usec)
起動からの経過時間
BOOT ID
ログ優先度
UID
GID
マシン ID
ホスト名
syslog の ID と
ファシリティ
ソースコード
内の行番号
内の関数名
メッセージの ID
接続方法
PID
コマンド名
実行ファイル
CAPABILITY
CGROUP
コマンドライン
SELinux コンテキスト
systemd の unit 名
メッセージ本文
出力時の時刻 (usec)__CURSOR=s=70bed981e31a46e2a70c56776402e0eb;i=342;b=982826bc22454f079fd46ec94e2b
__REALTIME_TIMESTAMP=1407830743019247
__MONOTONIC_TIMESTAMP=1792842
_BOOT_ID=982826bc22454f079fd46ec94e2b67fc
PRIORITY=6
_UID=0
_GID=0
_MACHINE_ID=025b7ff2c8af43f78513996f06584c4c
_HOSTNAME=localhost.localdomain
SYSLOG_IDENTIFIER=systemd
SYSLOG_FACILITY=3
CODE_FILE=src/core/unit.c
CODE_LINE=1115
CODE_FUNCTION=unit_status_log_starting_stopping_reloading
MESSAGE_ID=7d4958e842da4a758f6c1cdc7b36dcc5
_TRANSPORT=journal
_PID=1
_COMM=systemd
_EXE=/usr/lib/systemd/systemd
_CAP_EFFECTIVE=1fffffffff
_SYSTEMD_CGROUP=/
_CMDLINE=/usr/lib/systemd/systemd --switched-root --system --deserialize 20
_SELINUX_CONTEXT=system_u:system_r:init_t:s0
UNIT=rsyslog.service
MESSAGE=Starting System Logging Service...
_SOURCE_REALTIME_TIMESTAMP=1407830743019153journalctl によるクエリ例
journalctl コマンドのオプションで条件を指定。絞り込んで必要なログだけを抽出
139ログレベルの制限
journalctl -p 4 ← warning(4) 以上の priority であること
ユニットの制限
journalctl -u NetworkManager.service ← 指定した unit からの出力であること
起動ごとの制限
journalctl -b -1← 直近の boot より 1 つ前の起動以降のログ
時間の制限
journalctl --since “2020-02-01” --until “2020-02-05” ← 時間ウィンドウの指定
任意のフィールド
journalctl _COMM=dhclient ← < フィールド名 >=< 値 > で任意の値で絞り込み
journald のディレクトリ構造
/run/log/journal ( 揮発 ) または /var/log/journal ( 永続 ) 以下に収集する
–システムのログ .//system.journal–各ユーザのログ .//user-.journal
ログを uid で分離せずにまとめる設定も可能だが journalctl は透過的にまとめて検索する
ため ( ユーザが自分のログを見られなくなる以外に ) 特に使い勝手などの変化はない。–ローテートされたログ .//system@suffix.journal–ローテートされたログ .//user-@suffix.journal–140ACL で各ユーザ本人へのアクセス許可を付与しているログの破損を発見すると、 ログは *.journal~ という拡張子に変更され、新しいログへ書き出
しを行う
journald の設定
/etc/systemd/journald.conf で設定する
圧縮有無、 Seal 処理 ( ハッシュを利用したログ改竄検出 ) 、ストレージへの同期間
隔、ログ出力レート制限
コンソールや syslog などへの forward の有無、ストレージへの保存や出力先毎の
loglevel 指定
ログローテート
–141サイズ毎、時間毎の rorate 処理アーカイブ削除
–journal 全体のサイズ上限、ストレージの残容量下限による削除、指定時間以上経過で削除–削除はローテートされたアーカイブファイル単位で行われる
ログ保存とローテートの設定
journald のデフォルトではサイズベースでのローテートが指定
される
–ファイルシステムの 10% か 4GB の内小さい容量をログに使用
–
142ログファイルはその 1/8 のサイズ (4GB の場合 512MB)ファイルシステムの 15% か 4GB の内小さい空き容量を残すMaxFileSec= を指定してで毎日 / 毎月などのタイミングでも
ローテートを指定できる
rsyslog への forward
rsyslogd の imjournal plugin が journald の
ログを監視して保存します
–143逆に rsyslogd の出力先を journald にする
omjournal plugin も提供されているuser-1000.journal
system.journalRHEL のデフォルトでは journald は揮発性、
rsyslogd で永続化
記録される情報としては journald が多いが、
既存の syslog 対応ツールや外部との連携は
rsyslog が便利なケースが多い
imjournal
rsysloglogger コマンドからのログ書き出し例144$ logger --journald < → graphviz で指定 unit 群の依存関係を図示する。
systemd-analyze verify → lint 的に unit file をチェックする。ディレ
クトリや Exec* の対象存在有無など。
systemd-analyze condition → 各 condition のチェックと全
体としての成否を表示する。
その他時刻や時間の表現がどう認識されるかテストする機能もあります。
systemd の log level を変える
systemd がどこと通信して何をしているか見たいときは debug レベルのログを見ます
起動時の問題であれば grub で kernel のオプションに systemd.log_level=debug
のように指定する ( 起動時はログがとても多いので注意 )
/etc/systemd/system.conf に LogLevel=debug と記述して systemctl daemonreload します。他の設定ファイルも全て読み直します。
実行中に loglevel だけを変更するには以下のように systemd-analyze コマンドで指
定する
–現在の log level 確認 ( デフォルトは info):
systemd-analyze log-level–log level を debug にする :systemd-analyze log-level debug
158unit の状態でシェルスクリプトの動作を変える
unit の状態でシェルスクリプトなどの動作を変えたい場合は、
systemctl のサブコマンド is-active, is-enabled, is-failed, issystem-running を使う
–159systemctl status や systemctl show だと sysvinit のスクリプト
の状態が最新でない場合がある出力はテキストと exit code 。 --quiet オプションをつけると
テキスト出力は抑制される。余談 : systemd-sysv-install
160sysvinit 形式のスクリプトがある場合の is-enabled の確認は
/lib/systemd/systemd-sysv-install で行われる。
/lib/systemd/systemd-sysv-install は RHEL/Fedora では
chkconfig の別名で enable/disable を sysvinit のディレクトリ
の状態から返す
systemctl status や systemctl show では unit の状態を返すが
systemd-sysv-install によるチェックを行わないので最新でな
い場合がある
関連する man page
161systemd-analyze(1): systemd-analyze の各サブコマンドの実
行例、出力例あり
systemctl(1): is-enabled などの節には出力と対応する exit
code の表ありやってみよう
graphviz を入れて unit 間の依存関係画像を見てみる
$ systemd-analyze dot 'cockpit.*' | dot -Tsvg >cockpit.svg
$ eog cockpit.svg162systemd-analyze calendar daily として、 timer unit などで
’ daily’ と指定があると実際に何時何分を指しているのかを確認する
systemd の log level を debug に変更し、 systemctl などのコマン
ドを実行した時にどのようなログが出るのか見る周辺ツールなど163systemd-tmpfiles
一般に永続的でないディレクトリが多数ある /dev, /run, /tmp など
–systemd-tmpfiles は起動時、または定期的なセットアップと掃除をこれらの
ディレクトリに対して行う
–ファイルやディレクトリ、リンク、パイプ、デバイスファイルなどを作成–特定ファイルを特定のコンテンツで初期化––164live CD のような環境では /var 以下も永続的であるとは限らない特定のディレクトリ以下のファイルを削除したり、ファイルそのものは残して
truncate したり、 uid,gid, 権限 , ACL などを変更する
最終アクセスから指定時間以上経過していたら削除 など
systemd-tmpfiles
systemd-tmpfiles --cat-config で全設定を出力
–
––パッケージに含まれる設定を変更したい場合は /etc/tmpfiles.d 以下に
/usr/lib/tmpfiles.d と同じ名前のファイルを作るとファイル単位で上書きされる
作成 ( または削除 ) されるディレクトリやファイルに親子関係があれば適切な順序
で実行する実行は systemd-tmpfiles-*.service, systemd-tmpfiles-*.timer から行われる。
–165設定は宣言的に行う。設定内容の読み方については tmpfiles.d(5) を参照デフォルトでは起動時に /dev/ とそれ以外に分けて setup を呼びだし、
起動から 15 分後に 1 回目の clean 、その後 1 日 1 回 clean を繰り返す
hostnamectl
ホスト名の設定
–hostnamectl set-hostname host.domain.example.orgホスト名の確認
$ hostnamectl$ hostnamectl
Static hostname: rhel8.example.com
Icon name: computer-vm
Chassis: vm
Machine ID: 21975e50f73142d5b4a92eb05209e9fa
Boot ID: 83c339091094442b8645fec5699c7e11
Virtualization: kvm
Operating System: Red Hat Enterprise Linux 8.1 (Ootpa)
CPE OS Name: cpe:/o:redhat:enterprise_linux:8.1:GA
Kernel: Linux 4.18.0-147.0.3.el8_1.x86_64
Architecture: x86-64166machine id と boot id
各ホストや起動・再起動での一意性を確保したいので UUID のよう
な ID があると便利
––167Machine ID: /etc/machine-id にある id 。ホスト毎に生成されランダ
ム。 /etc/machine-id を削除して再起動すると自動で新しい乱数が生成
される。
Boot ID: /proc/sys/kernel/random/boot_id にある id 。起動毎に生成
されランダム。利用例 : journald によるログには machine id, boot id が含まれてい
る。
関連する man page
168systemd-tmpfiles(8), tmpfiles.d(5): systemd-tmpfiles と設定
ディレクトリ、設定ファイルについて
hostnamectl(1): ホスト名の設定、確認について
random(4): linux kernel の random モジュールについて。
boot_id もこのモジュールが生成している。参考資料169man page
今まで参照した man page 群でわかるとおり systemd は多数の充
実した man page が提供される
170systemd.index(7) - systemd の man page 一覧
systemd.directives(7) - unit file の directive がどの man page
に書かれているかの一覧。既存 unit file 読解時に便利ホームページ、 blog
https://systemd.io/ systemd project ホームページ
https://www.freedesktop.org/wiki/Software/systemd/ 旧
systemd ホームページ
–171特に運用管理者には The systemd for Administrators Blog
Series を推奨しますスライド資料
Demystifying systemd
–2018 年版 : RHEL7 ベース。これから使いはじめる人むけ
https://www.redhat.com/files/summit/session-assets/201
7/S103870-Demystifying-systemd.pdf–1722019 年版 : RHEL8 ベース。新機能に興味がある人むけ
https://www.redhat.com/files/summit/session-assets/201
9/T4D2A2.pdf