めもめも

このブログに記載の内容は個人の見解であり、必ずしも所属組織の立場、戦略、意見を代表するものではありません。

Systemd入門(3) - cgroupsと動的生成Unitに関する小ネタ

この連載では、Fedora 17での実装をベースとして、systemdの考え方や仕組み、利用方法を説明します。今後出てくる予定のRHEL7での実装とは異なる部分があるかも知れませんが、その点はご了承ください。

今回は、表題の小ネタを2つお届けします。

cgroups

systemdの管理下では、すべてのプロセスについて、cgroupsによる分類が行われます。cgroupsでは、グループに階層構造を持たせることができますが、systemdは「systemグループ」と「userグループ」を用意した上で、その下にサブグループを作成していきます。

グループ 説明
system   systemdから起動するserviceについて、この下に該当service用のサブグループを作成します。
user    この下にユーザアカウントごとのサブグループを作成します。その下には、さらに、ログイン端末ごとのサブグループを作成します。

各プロセスのグループは次のコマンドで確認できます。実行コマンド名の前の数値は、該当プロセスのPIDです。

# systemd-cgls
├ user
│ ├ enakai
│ │ ├ 10
│ │ │ ├ 1317 sshd: enakai [priv]
│ │ │ ├ 1321 sshd: enakai@pts/2
│ │ │ └ 1322 -bash
│ │ └ 9
│ │   ├ 1291 sshd: enakai [priv]
│ │   ├ 1295 sshd: enakai@pts/1
│ │   └ 1296 -bash
│ └ root
│   ├ 11
│   │ ├  435 login -- root
│   │ └ 1347 -bash
│   └ 1
│     ├  549 sshd: root@pts/0
│     ├  553 -bash
│     ├ 1363 systemd-cgls
│     └ 1364 cat
└ system
  ├ 1 /usr/lib/systemd/systemd
  ├ chronyd.service
  │ └ 713 /usr/sbin/chronyd -u chrony
  ├ sm-client.service
  │ └ 542 sendmail: Queue runner@01:00:00 for /var/spool/clientmqueue
  ├ sendmail.service
  │ └ 522 sendmail: accepting connections
  ├ sshd.service
  │ └ 725 /usr/sbin/sshd -D
  ├ crond.service
  │ └ 437 /usr/sbin/crond -n
  ├ dbus.service
  │ ├ 431 /bin/dbus-daemon --system --address=systemd: --nofork --systemd-...
  │ ├ 452 /usr/libexec/polkit-1/polkitd --no-debug
  │ └ 469 /usr/sbin/modem-manager
  ├ systemd-logind.service
  │ └ 412 /usr/lib/systemd/systemd-logind
  ├ NetworkManager.service
  │ ├ 410 /usr/sbin/NetworkManager --no-daemon
  │ └ 485 /sbin/dhclient -d -4 -sf /usr/libexec/nm-dhcp-client.action -pf ...
  ├ rsyslog.service
  │ └ 409 /sbin/rsyslogd -n -c 5
  ├ auditd.service
  │ └ 407 /sbin/auditd -n
  ├ udev.service
  │ ├ 288 /usr/lib/udev/udevd
  │ ├ 348 /usr/lib/udev/udevd
  │ └ 349 /usr/lib/udev/udevd
  └ systemd-journald.service
    └ 279 /usr/lib/systemd/systemd-journald

これにより、systemdは、serviceごとにcgroupsによるリソースの割り当てを細かに制御することができるようになります。システム管理者は、cgroupsの設定を直接に行うのではなく、serviceの設定ファイルにリソースの割り当て条件を記載することで、systemdが該当serviceのグループに対して必要な設定を行う形になります。現在、systemdとのインテグレーションに合わせて、cgroupsの大幅な改変が予定されていますので、具体的な設定方法はこれから整備されていくと思われます。

参考資料
[HEADSUP] cgroup changes:2013/06/21にLennartがcgoupsの改変について投稿したメール

一方、serviceごとにプロセスをグループ化することには、cgroupsの設定以外にも恩恵があります。KILLシグナルでserviceを強制停止する場合、同じグループに属するプロセスすべてを強制停止することで、該当のserviceを完全に停止することができます。デーモンプロセスでは、「double fork」という手法でプロセスの親子関係を分断することがあるため、プロセスの親子関係だけで関連するプロセスを網羅できない点に注意してください。上記のコマンド出力からわかるように、systemdは、それぞれのグループ内のプロセスのPIDをすべて把握しています。これまでは、PIDファイルで停止するプロセスを特定する必要がありましたが、この必要もなくなります。

具体的には、systemctlコマンドのkillオプションを使用すると、指定のserviceに属するすべてのプロセスにまとめてシグナルが送信されます。シグナル名(シグナル番号)は-sオプションで指定します。

# systemctl kill -s9 sshd.service

service内で最初に起動したmainプロセスだけにシグナルを送りたい場合は、「--kill-who=main」オプションを指定します。

# systemctl kill -sSIGHUP --kill-who=main sshd.service

参考資料
systemd for Administrators, Part IV - Killing Services

また、systemctlコマンド(stopオプション)でserviceを停止する場合にもこの仕組みが利用されます。具体的には、次の順序で停止処理が行われます。

・「ExecStop=」オプションで指定したコマンドを実行
・グループ内の全てのプロセスにSIGTERMを送信(*)
・グループ内の全てのプロセスにSIGKILLを送信(*)

(*)「KillMode=process」を指定した場合は、最初に起動したプロセスのみに送信

動的生成Unit

参考資料
systemd-specialのmanページ

systemdが管理するUnitは、/usr/lib/systemd/system/以下、もしくは/etc/systemd/system/以下の設定ファイルで定義されますが、この他にもsystemdが動的に生成するUnitがあります。たとえば、ファイルシステムのマウント処理を行うmountタイプのUnitがありますが、systemdは、/etc/fstabのエントリーを参照して、対応するmountタイプのUnitを生成します。(設定ファイルを生成するわけではありません。対応する設定ファイルがない状態で、Unitの存在だけが認識される形になります。)Unitの名称は、「<マウントポイントのパスで「/」を「-」置換したもの>.mount」となります。

次の例では、-.mount(ルートファイルシステム)とboot.mount(/bootファイルシステム)が、/etc/fstabから動的に生成されたUnitになります。

# systemctl list-units --type=mount
UNIT                    LOAD   ACTIVE SUB     JOB DESCRIPTION
-.mount                 loaded active mounted     /
boot.mount              loaded active mounted     /boot
dev-hugepages.mount     loaded active mounted     Huge Pages File System
dev-mqueue.mount        loaded active mounted     POSIX Message Queue File System
media.mount             loaded active mounted     Media Directory
sys-kernel-config.mount loaded active mounted     Configuration File System
sys-kernel-debug.mount  loaded active mounted     Debug File System

これらのUnitは、「local-fs.target」の前提Unitとして自動設定されます。

# systemctl show local-fs.target | grep Requires
Requires=boot.mount -.mount

この他には、デバイスを表すdeviceタイプのUnitも動的に生成されます。これは、udevが新しいデバイスを認識したタイミングで、「systemd」というudevタグを付けると、それを受け取ったsystemdが対応するUnitを生成して有効化します。(Fedora 17のudevでは、デフォルトで前述のudevタグを付けるように設定されています。)Unitの名称は、「<該当デバイスの/sysファイルシステムパス(「/」を「-」に置換)>.device」になります。

次の例では、「sys-devices-」で始まるUnitがこれに該当します。(--fullオプションは長いUnit名を省略せずに表示するオプションです。)

# systemctl list-units --type=device --full
UNIT                                                                                LOAD   ACTIVE SUB     JOB DESCRIPTION
sys-devices-pci0000:00-0000:00:01.1-ata2-host1-target1:0:0-1:0:0:0-block-sr0.device loaded active plugged     QEMU_DVD-ROM
sys-devices-pci0000:00-0000:00:03.0-virtio0-net-eth0.device                         loaded active plugged     Virtio network device
sys-devices-pci0000:00-0000:00:04.0-sound-card0.device                              loaded active plugged     82801FB/FBM/FR/FW/FRW (ICH6 Family) High Definition Audio Controller
sys-devices-pci0000:00-0000:00:05.0-virtio1-virtio\x2dports-vport1p1.device         loaded active plugged     /sys/devices/pci0000:00/0000:00:05.0/virtio1/virtio-ports/vport1p1
sys-devices-pci0000:00-0000:00:06.0-virtio2-block-vda-vda1.device                   loaded active plugged     /sys/devices/pci0000:00/0000:00:06.0/virtio2/block/vda/vda1
sys-devices-pci0000:00-0000:00:06.0-virtio2-block-vda-vda2.device                   loaded active plugged     /sys/devices/pci0000:00/0000:00:06.0/virtio2/block/vda/vda2
sys-devices-pci0000:00-0000:00:06.0-virtio2-block-vda.device                        loaded active plugged     /sys/devices/pci0000:00/0000:00:06.0/virtio2/block/vda
sys-devices-platform-serial8250-tty-ttyS1.device                                    loaded active plugged     /sys/devices/platform/serial8250/tty/ttyS1
sys-devices-platform-serial8250-tty-ttyS2.device                                    loaded active plugged     /sys/devices/platform/serial8250/tty/ttyS2
sys-devices-platform-serial8250-tty-ttyS3.device                                    loaded active plugged     /sys/devices/platform/serial8250/tty/ttyS3
sys-devices-pnp0-00:04-tty-ttyS0.device                                             loaded active plugged     /sys/devices/pnp0/00:04/tty/ttyS0
sys-devices-virtual-block-dm\x2d0.device                                            loaded active plugged     /sys/devices/virtual/block/dm-0
sys-devices-virtual-block-dm\x2d1.device                                            loaded active plugged     /sys/devices/virtual/block/dm-1
sys-devices-virtual-tty-tty0.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty0
sys-devices-virtual-tty-tty1.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty1
sys-devices-virtual-tty-tty10.device                                                loaded active plugged     /sys/devices/virtual/tty/tty10
sys-devices-virtual-tty-tty11.device                                                loaded active plugged     /sys/devices/virtual/tty/tty11
sys-devices-virtual-tty-tty12.device                                                loaded active plugged     /sys/devices/virtual/tty/tty12
sys-devices-virtual-tty-tty2.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty2
sys-devices-virtual-tty-tty3.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty3
sys-devices-virtual-tty-tty4.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty4
sys-devices-virtual-tty-tty5.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty5
sys-devices-virtual-tty-tty6.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty6
sys-devices-virtual-tty-tty7.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty7
sys-devices-virtual-tty-tty8.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty8
sys-devices-virtual-tty-tty9.device                                                 loaded active plugged     /sys/devices/virtual/tty/tty9
sys-module-configfs.device                                                          loaded active plugged     /sys/module/configfs
sys-subsystem-net-devices-eth0.device                                               loaded active plugged     Virtio network device

特に、Bluetoothコントローラ、プリンタ、スマートカード、サウンドカードについては、それぞれ、bluetooth.target, printer.target, smartcard.target, sound.targetが自動的に前提Unitに指定されます。つまり、たとえば、サウンドカードが挿入されると、そのタイミングでsound.targetが有効化されます。そこで、サウンドカードを必要とするUnitをsound.targetの前提Unitとしておけば、サウンドカードが挿入されたタイミングでこれらのUnitが有効化されることになります。