いまさらだけどsystemdに入門した
そろそろCentOS7系の知識を身につけないといけないと思い、いまさらだけど入門した。 基本的には、Red Hat Enterprise Linux 7がやってきた[概要編] - Red Hat Enterprise Linux 7がやってきた:ITproに沿った内容である。 また、vagrantでbento/centos-7.1を元に確認・調査をした。
systemdとは
いくつか記事を読んでみたところ、新しいLinuxの起動処理を支える技術であるという印象を持った。従来のSysVinitやUpstartの仕組みに代わるもので、起動処理の他に、様々なサービス管理機能を持ち合わせている。ユーザープロセスを並列に起動することによって、システムの起動処理にかかる時間を短縮する等、メリットがいくつかある。
引用元 systemd - Wikipedia / "Tizenで使われているsystemdのアーキテクチャ"
systemdが作られた背景
従来の起動処理では、OSが立ち上がった際に、最初にユーザプロセスの「init」がPID=1として起動し、その後に他のプロセスが順次起動される仕組みになっている。
引用元 図1●SVR4に採用された、OSが立ち上がった際に各種ユーザープロセスを起動する...
この仕組みはとてもシンプルで、長きに渡って支持され利用されてきたが、昨今のCPUやメモリの性能進化を考えるとこの順次起動という仕組みはボトルネックになってくる。
また、このinitスクリプト自体のメンテナンス性も問題視されていた。
他にも課題はあったが、systemdは、主にこれらを解決するために開発されるに至った。
余談だが、systemdの導入には賛否両論である。しかしながら2015年現在、主要なLinuxディストリビューションのほとんどはsystemdをデフォルトのinitシステムとして採用している。
引用元 systemd - Wikipedia / "採用および反響"
従来の仕組み
systemdについて深掘りする前に、従来の仕組みについておさらいしてみる。
起動処理は、CentOS5系では「SysVinit」、CentOS6系では「Upstart」という仕組みが採用されていた。どちらも、シェルスクリプトで起動処理を管理している。
SysVinitでは、Linuxカーネルの起動直後にPID=1として/sbin/init
(SysVinitの本体)が実行され、設定ファイル/etc/inittab
に従って、以下の流れで各サービスの起動処理が実行される。
/etc/rc.d/rcsysint
によって、ファイルシステムの整合性チェック・マウント処理・メモリスワップ領域の有効化等が行われる。/etc/rc.d/rc
によって、/etc/init.d/<サービス名>
が順番に実行され、chkconfigで設定されたサービス群が起動される。- コンソールログインを受け付けるmingettyが起動される。
抱えていた課題
昨今のサーバには、マルチコアCPUが搭載されマルチプロセスによる並列処理がますます得意になっていく中、前述の仕組みで用いられているシェルスクリプトでは並列処理が行えず、システム起動処理においてボトルネックになってしまう。
systemdのアプローチ
systemdは、これまでシェルスクリプトで行っていた処理を新しく作り直し、処理を分割して並列化することでシステム起動処理を高速化する。
systemdにおけるUnitという概念
systemdでは、様々な処理をそれぞれUnitとして定義して、実行時には各Unitを指定して実行する。つまり、従来、シェルスクリプトでシーケンシャルに実行されていた処理を複数のUnitに分解して並列実行する。
定義ファイルは、/etc/systemd/system
と/usr/lib/systemd/system
に配置されている。デフォルトの設定は/usr/lib/systemd/system
に、管理者が追加修正したものは/etc/systemd/system
に配置する。デフォルト値の変更時は、/usr/lib/systemd/system
のファイルをコピーして/etc/systemd/system
に保存するという具合に編集する。デフォルトに戻したい時は/etc
のほうにあるファイルを削除すればよい。同名のファイルがあった場合は、/etc
のほうが優先される。
Unitにはいくつか種類があり、拡張子によって判別される。管理者は主に、serviceタイプのUnitについて追加修正することが多い。
引用元 (3/3)Red Hat Enterprise Linux 7がやってきた[起動処理編] - 第1回 Linuxの起動プロセスとsystemd:ITpro
[vagrant@localhost ~]$ ls -1 /etc/systemd/system basic.target.wants dbus-org.freedesktop.NetworkManager.service dbus-org.freedesktop.nm-dispatcher.service default.target default.target.wants getty.target.wants multi-user.target.wants sockets.target.wants sysinit.target.wants system-update.target.wants
[vagrant@localhost ~]$ ls -1 /usr/lib/systemd/system | head -.slice NetworkManager-dispatcher.service NetworkManager-wait-online.service NetworkManager.service arp-ethers.service auditd.service auth-rpcgss-module.service autovt@.service basic.target basic.target.wants
Unitの依存関係と順序関係
systemdでは、Linuxカーネル起動後、PID=1として/usr/lib/systemd/systemd
(systemdの本体)が起動し、その後各Unitの依存関係を検索後、設定された順序関係に基づいてUnitを有効化する。
/usr/lib/systemd/systemd
(systemdの本体) が起動する。- systemdによって各種Unitの依存関係を検索し、有効化すべきUnitの一覧を作成する。
- 一覧から、Unitの順序関係に基づいてUnitを順番に有効化していく。順序関係を持たないUnitは並列に起動処理が行われる。
依存関係・順序関係はともにUnitの設定ファイルで定義されている。
依存関係は、以下のように[Unit]セクションでWants=
またはRequires=
に対して、当該Unitと一緒に有効化すべきUnitを指定する。
両者の違いについては、「Requires」は、有効化すべきUnitが起動に失敗すると、当該Unitの起動を取りやめる。一方、「Wants」は、有効化すべきUnitが起動に失敗しても、当該Unitの起動処理はそのまま実施する。
なお、ここでは順番は関係無く、「一緒に有効化すべきUnit群」を定義する。順序関係の定義は次に説明する。
[vagrant@localhost ~]$ sudo cat /usr/lib/systemd/system/sshd.service [Unit] Description=OpenSSH server daemon After=network.target sshd-keygen.service Wants=sshd-keygen.service ...省略
[vagrant@localhost ~]$ sudo cat /usr/lib/systemd/system/systemd-journald.service # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [Unit] Description=Journal Service Documentation=man:systemd-journald.service(8) man:journald.conf(5) DefaultDependencies=no Requires=systemd-journald.socket After=systemd-journald.socket syslog.socket Before=sysinit.target ...省略
順序関係は、[Unit]セクションでAfrer=
やBefore=
に対して、当該Unitを指定したUnitより後に起動するか前に起動するかを定義する。
以下の場合、実質なにもしないnetwork.target
をうまく使って順序関係を定義している。
これによって、sshd.service
がfirewalld.service
より後に起動されることが保証される。
[vagrant@localhost ~]$ sudo cat /usr/lib/systemd/system/sshd.service [Unit] Description=OpenSSH server daemon After=network.target sshd-keygen.service Wants=sshd-keygen.service ...省略
[vagrant@localhost ~]$ sudo cat /usr/lib/systemd/system/firewalld.service [Unit] Description=firewalld - dynamic firewall daemon Before=network.target Before=libvirtd.service Before=NetworkManager.service Conflicts=iptables.service ip6tables.service ebtables.service ...省略
[vagrant@localhost ~]$ sudo cat /usr/lib/systemd/system/network.target # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [Unit] Description=Network Documentation=man:systemd.special(7) Documentation=http://www.freedesktop.org/wiki/Software/systemd/NetworkTarget
以下を見てみると、network.target
をうまく使ってることがわかる。
network.target
より前に起動されるUnitは「ネットワークを準備する系Unit」、後に起動されるサービスは「ネットワークを利用する系Unit」である。
[vagrant@localhost ~]$ sudo grep "Before=network.target" /usr/lib/systemd/system/*.service | cut -d":" -f1 /usr/lib/systemd/system/NetworkManager-wait-online.service /usr/lib/systemd/system/NetworkManager.service /usr/lib/systemd/system/arp-ethers.service /usr/lib/systemd/system/firewalld.service /usr/lib/systemd/system/rdma.service /usr/lib/systemd/system/wpa_supplicant.service [vagrant@localhost ~]$ sudo grep "After=network.target" /usr/lib/systemd/system/*.service | cut -d":" -f1 /usr/lib/systemd/system/dnsmasq.service /usr/lib/systemd/system/httpd.service /usr/lib/systemd/system/kdump.service /usr/lib/systemd/system/nfs-lock.service /usr/lib/systemd/system/nfs-mountd.service /usr/lib/systemd/system/rc-local.service /usr/lib/systemd/system/rpc-statd.service /usr/lib/systemd/system/sshd.service
また、依存関係の定義方法は、Wants=
・Requires=
に定義する他に、もう一つ方法がある。
「<Unit名>.wants」または「<Unit名>.requires」という名のディレクトリを作成して、配下にUnitの設定ファイルへのシンボリックリンクを作成する方法である。
以下に例を挙げる。
[vagrant@localhost ~]$ sudo ls -l /usr/lib/systemd/system/multi-user.target.wants/ 合計 0 lrwxrwxrwx. 1 root root 16 10月 6 21:16 brandbot.path -> ../brandbot.path lrwxrwxrwx. 1 root root 15 10月 6 21:16 dbus.service -> ../dbus.service lrwxrwxrwx. 1 root root 15 10月 6 21:16 getty.target -> ../getty.target lrwxrwxrwx. 1 root root 29 10月 6 21:16 plymouth-quit-wait.service -> ../plymouth-quit-wait.service lrwxrwxrwx. 1 root root 24 10月 6 21:16 plymouth-quit.service -> ../plymouth-quit.service lrwxrwxrwx. 1 root root 33 10月 6 21:16 systemd-ask-password-wall.path -> ../systemd-ask-password-wall.path lrwxrwxrwx. 1 root root 25 10月 6 21:16 systemd-logind.service -> ../systemd-logind.service lrwxrwxrwx. 1 root root 32 10月 6 21:16 systemd-user-sessions.service -> ../systemd-user-sessions.service
所感
systemdにおける概要とUnitについて入門できた。調べてみて、うまくできているなという印象を持ったが前述の通り、賛否両論らしいので反対派の意見にも目を通そうと思っている。
systemdについて調べたのは、もともとDockerについて調べてる中でCoreOSの話が出てきて、cloud-configについての説明を読んでるうちにunitという概念が出てきたところからyak shavingしてきたのがきっかけである。でも、いいきっかけだったと思う。まだもう少し潜ろうと思う。
今回説明しきれなかったところ
- systemctlコマンドについて
- systemdのログ管理機能であるjournaldについて
- Unit設定ファイルの記述方法について
参考
- Red Hat Enterprise Linux 7がやってきた[概要編] - Red Hat Enterprise Linux 7がやってきた:ITpro
- 主に概要編と起動処理編を読んだ。
- systemd - Wikipedia