はじめに
少し前ではありますが、isucon13に出ました。
初めてだったので、わからないことだらけでした。
今回は、そのうちの一つであるsystemd
についてまとめます。
環境
こちらのisucon13で、Ruby実装を使って検証しています。
systemdとは
systemd is a system and service manager for Linux operating systems. When run as first process on boot (as PID 1), it acts as init system that brings up and maintains userspace services.
Linuxにおけるシステム管理やサービス管理の仕組みです。
PIDが1のプロセスとして起動するinitシステムであり、プロセス階層の根元になります。
プロセスツリーの例(isucon13 Ruby実装)
$ pstree -p
systemd(1)─┬─acpid(369)
├─agetty(410)
├─agetty(421)
├─amazon-ssm-agen(392)─┬─{amazon-ssm-agen}(610)
│ ├─{amazon-ssm-agen}(611)
│ ├─{amazon-ssm-agen}(612)
│ ├─{amazon-ssm-agen}(613)
│ ├─{amazon-ssm-agen}(653)
│ ├─{amazon-ssm-agen}(956)
│ └─{amazon-ssm-agen}(1898)
├─bundle(2793)─┬─bundle(2794)─┬─{bundle}(2800)
│ │ ├─{bundle}(2840)
│ │ ├─{bundle}(2841)
│ │ ├─{bundle}(2842)
│ │ ├─{bundle}(2843)
│ │ └─{bundle}(2844)
│ ├─bundle(2795)─┬─{bundle}(2801)
│ │ ├─{bundle}(2810)
│ │ ├─{bundle}(2811)
│ │ ├─{bundle}(2812)
│ │ ├─{bundle}(2813)
│ │ └─{bundle}(2814)
│ ├─bundle(2796)─┬─{bundle}(2802)
│ │ ├─{bundle}(2835)
│ │ ├─{bundle}(2836)
│ │ ├─{bundle}(2837)
│ │ ├─{bundle}(2838)
│ │ └─{bundle}(2839)
│ ├─bundle(2797)─┬─{bundle}(2804)
│ │ ├─{bundle}(2825)
│ │ ├─{bundle}(2826)
│ │ ├─{bundle}(2827)
│ │ ├─{bundle}(2828)
│ │ └─{bundle}(2829)
│ ├─bundle(2798)─┬─{bundle}(2803)
│ │ ├─{bundle}(2815)
│ │ ├─{bundle}(2816)
│ │ ├─{bundle}(2817)
│ │ ├─{bundle}(2818)
│ │ └─{bundle}(2819)
│ ├─bundle(2799)─┬─{bundle}(2807)
│ │ ├─{bundle}(2830)
│ │ ├─{bundle}(2831)
│ │ ├─{bundle}(2832)
│ │ ├─{bundle}(2833)
│ │ └─{bundle}(2834)
│ ├─bundle(2805)─┬─{bundle}(2808)
│ │ ├─{bundle}(2845)
│ │ ├─{bundle}(2846)
│ │ ├─{bundle}(2847)
│ │ ├─{bundle}(2848)
│ │ └─{bundle}(2849)
│ └─bundle(2806)─┬─{bundle}(2809)
│ ├─{bundle}(2820)
│ ├─{bundle}(2821)
│ ├─{bundle}(2822)
│ ├─{bundle}(2823)
│ └─{bundle}(2824)
├─chronyd(414)───chronyd(424)
├─cron(373)
├─dbus-daemon(374)
├─multipathd(152)─┬─{multipathd}(167)
│ ├─{multipathd}(169)
│ ├─{multipathd}(170)
│ ├─{multipathd}(171)
│ ├─{multipathd}(172)
│ └─{multipathd}(173)
├─mysqld(709)─┬─{mysqld}(721)
│ ├─{mysqld}(722)
│ ├─{mysqld}(723)
│ ├─{mysqld}(724)
│ ├─{mysqld}(725)
│ ├─{mysqld}(726)
│ ├─{mysqld}(727)
│ ├─{mysqld}(728)
│ ├─{mysqld}(729)
│ ├─{mysqld}(732)
│ ├─{mysqld}(740)
│ ├─{mysqld}(741)
│ ├─{mysqld}(742)
│ ├─{mysqld}(743)
│ ├─{mysqld}(744)
│ ├─{mysqld}(745)
│ ├─{mysqld}(748)
│ ├─{mysqld}(749)
│ ├─{mysqld}(750)
│ ├─{mysqld}(751)
│ ├─{mysqld}(752)
│ ├─{mysqld}(753)
│ ├─{mysqld}(754)
│ ├─{mysqld}(755)
│ ├─{mysqld}(756)
│ ├─{mysqld}(757)
│ ├─{mysqld}(761)
│ ├─{mysqld}(762)
│ ├─{mysqld}(763)
│ ├─{mysqld}(764)
│ ├─{mysqld}(765)
│ ├─{mysqld}(766)
│ ├─{mysqld}(767)
│ ├─{mysqld}(768)
│ ├─{mysqld}(770)
│ ├─{mysqld}(771)
│ ├─{mysqld}(778)
│ ├─{mysqld}(779)
│ ├─{mysqld}(783)
│ ├─{mysqld}(790)
│ ├─{mysqld}(792)
│ ├─{mysqld}(797)
│ └─{mysqld}(798)
├─networkd-dispat(386)
├─nginx(567)───nginx(568)
├─pdns_server(773)─┬─{pdns_server}(780)
│ ├─{pdns_server}(781)
│ ├─{pdns_server}(782)
│ ├─{pdns_server}(784)
│ ├─{pdns_server}(785)
│ ├─{pdns_server}(786)
│ ├─{pdns_server}(788)
│ ├─{pdns_server}(789)
│ └─{pdns_server}(791)
├─polkitd(451)─┬─{polkitd}(473)
│ └─{polkitd}(475)
├─rsyslogd(390)─┬─{rsyslogd}(426)
│ ├─{rsyslogd}(427)
│ └─{rsyslogd}(428)
├─snapd(1064)─┬─{snapd}(1071)
│ ├─{snapd}(1072)
│ ├─{snapd}(1073)
│ ├─{snapd}(1074)
│ ├─{snapd}(1078)
│ ├─{snapd}(1079)
│ ├─{snapd}(1230)
│ ├─{snapd}(1231)
│ └─{snapd}(1235)
├─sshd(565)───sshd(826)───sshd(925)───bash(926)───sudo(937)───sudo(938)───bash(939)───pstree(2903)
├─systemd(843)───(sd-pam)(844)
├─systemd-journal(112)
├─systemd-logind(397)
├─systemd-network(323)
├─systemd-resolve(325)
├─systemd-udevd(154)
└─unattended-upgr(439)───{unattended-upgr}(484)
Linuxの起動プロセス
電源を入れてからの起動プロセスは以下のようになります。
このinit
のところがsystemd
に該当します。
unit
systemd
において、各種のリソースはunit
として管理されます。
unit
の状態を切り替えたり、unit
間の依存関係を計算したりすることによって、リソースを管理することができます。
ここでいうリソースとは、「サーバーの管理」や「ネットワーク接続要求の管理」や「ファイルマウントシステムの管理」などさまざまです。
unit
には複数のタイプが存在しており、現在では11種類あります。
起動中のLinuxにおいて、現在systemd
が扱っているunit
の一覧は以下のコマンドで確認することができます。
$ systemctl list-units
unitの状態
unit
は状態をもち、基本的にはactive
もしくはinactive
です。
中間状態としてactivating
、deactivating
, reloading
があります。
unitの状態はsystemctl status
で確認することができます。
$ systemctl status UNIT_NAME
# ex.
$ systemctl status isupipe-ruby.service
● isupipe-ruby.service - isupipe-ruby
Loaded: loaded (/etc/systemd/system/isupipe-ruby.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2024-02-27 18:29:30 UTC; 4min 45s ago
Main PID: 2793 (bundle)
Tasks: 57 (limit: 1121)
Memory: 203.5M
CPU: 2.000s
CGroup: /system.slice/isupipe-ruby.service
├─2793 "puma 6.4.0 (tcp://0.0.0.0:8080) [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2794 "puma: cluster worker 0: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2795 "puma: cluster worker 1: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2796 "puma: cluster worker 2: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2797 "puma: cluster worker 3: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2798 "puma: cluster worker 4: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2799 "puma: cluster worker 5: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
├─2805 "puma: cluster worker 6: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
└─2806 "puma: cluster worker 7: 2793 [ruby]" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" >
Job
systemd
において、状態を変更するためにunit
に対して行う操作をJob
と呼んでいます。
start
, stop
, restart
, reload
があります。
(systemctl start UNIT_NAME
, systemctl stop UNIT_NAME
...etc)
unitの依存関係
systemd
ではunit
間に依存関係を構築することができます。
アプリケーションサーバを立ち上げる際に、DBサーバが先に立ち上がっていて欲しいなどの依存関係などです。
特定のunit
が、どのような依存関係を持っているのかはsystemctl list-dependencies
で確認することができます。
$ systemctl list-dependencies isupipe-ruby.service
isupipe-ruby.service
● ├─-.mount
● ├─mysql.service
● ├─system.slice
● └─sysinit.target
● ├─apparmor.service
● ├─blk-availability.service
● ├─dev-hugepages.mount
● ├─dev-mqueue.mount
● ├─finalrd.service
# ...
unit file
unit
はunit file
という設定ファイルによって管理されます。
unit fileの見方
例として、isucon13のRuby実装のunit file
を見てみます。
/etc/systemd/system/isupipe-ruby.service
にあり、こちらでは、Rubyのアプリケーションサーバ(puma)のunit
が管理されています。
systemctl cat
を使うと、特定のunit
に対応するunit file
を表示してくれるので便利です。
$ systemctl cat isupipe-ruby.service
# /etc/systemd/system/isupipe-ruby.service
[Unit]
Description=isupipe-ruby
After=syslog.target
After=mysql.service
Requires=mysql.service
[Service]
WorkingDirectory=/home/isucon/webapp/ruby
Environment=RUBY_YJIT_ENABLE=1
EnvironmentFile=/home/isucon/env.sh
User=isucon
Group=isucon
ExecStart=/home/isucon/.x bundle exec puma --bind tcp://0.0.0.0:8080 --workers 8 --threads 0:8 --environment production
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
[Unit]
, [Service]
, [Install]
はセクションで、各ディレクティブをグルーピングして整理するためのものです。
[Unit]
Description
unit
に対してつける短いタイトル・ラベルです。
systemctl status
を実行したときなどに表示されます。
Requires
unit
の依存関係を示すためのディレクティブです。
対象のunit
を有効化する場合、Requires
に指定したunit
も同時に有効化するようになります。
似たディレクティブにWants
がありますが、これは依存度の違いです。
Wants
は、依存関係にあるunitの有効化が失敗しても対象のunitに影響はありませんが、Requires
の場合、依存関係にあるunitの有効化が失敗すると対象のunitの有効化も失敗します。
Wants
, Require
は依存関係を指定するためのもので、順序関係を保証するものではありません。
次のAfterを指定することによって、順序関係を構築することができます。
After
After
ディレクティブには、先に有効化されていて欲しいunitを指定します。
アプリケーションサーバを立ち上げる前に、dbサーバが立ち上がっていて欲しいので、この例では、mysql.service
が指定されています。
[Service]
ExecStart
serviceがスタートした時(systemctl start
の実行時)に実行されるコマンドです。
この例では、pumaのアプリケーションサーバを起動しています。
ExecStop
serviceを終了した時(systemctl stop
の実行時)に実行されるコマンドです。
Restart
serviceがexitした時、killされた時、timeoutした時などにリスタートするかどうかを指定します。
各値と、いつリスタートするかの関係は以下になります。(X
がリスタートするの意味)
┌─────────────────────────────┬────┬────────┬────────────┬────────────┬─────────────┬──────────┬─────────────┐
│Restart settings/Exit causes │ no │ always │ on-success │ on-failure │ on-abnormal │ on-abort │ on-watchdog │
├─────────────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Clean exit code or signal │ │ X │ X │ │ │ │ │
├─────────────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Unclean exit code │ │ X │ │ X │ │ │ │
├─────────────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Unclean signal │ │ X │ │ X │ X │ X │ │
├─────────────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Timeout │ │ X │ │ X │ X │ │ │
├─────────────────────────────┼────┼────────┼────────────┼────────────┼─────────────┼──────────┼─────────────┤
│Watchdog │ │ X │ │ X │ X │ │ X │
└─────────────────────────────┴────┴────────┴────────────┴────────────┴─────────────┴──────────┴─────────────┘
RestartSec
serviceをリスタートする際に、どれだけスリープを入れるかを指定します。
[Install]
WantedBy
systemctl enable
を実行したときに、指定したunit
の.wants
ディレクトリにシンボリックリンクが貼られます。
$ sudo systemctl enable isupipe-ruby.service
Created symlink /etc/systemd/system/multi-user.target.wants/isupipe-ruby.service → /etc/systemd/system/isupipe-ruby.service.
$ ls -l /etc/systemd/system/multi-user.target.wants/isupipe-ruby.service
lrwxrwxrwx 1 root root 40 Feb 27 20:01 /etc/systemd/system/multi-user.target.wants/isupipe-ruby.service -> /etc/systemd/system/isupipe-ruby.service
multi-user.target
はLinuxの起動時に実行されるunit
であるため、これに対して依存関係を持つことで、起動時にこのunit
も自動で有効化されます。
unit fileのpath
特定のpathにunit file
を配置することによってsystemd
に認識させることができます。
-
/lib/systemd/system
- パッケージマネージャによってインストールされたユニット
-
/etc/systemd/system
- 管理者の操作によって作成されるユニット
-
/run/systemd/system
- 実行時に自動的に作成されるユニット
↑ の3箇所ありますが、直接編集するユニットは/etc/systemd/system
に配置します。
参考