Help us understand the problem. What is going on with this article?

Systemd メモ書き

More than 1 year has passed since last update.

SysVinitおぢさんなので。

コレのメモ書き http://www.slideshare.net/enakai/linux-27872553

  1. SysVinit / UpStart
  2. systemd の起動処理/操作方法
  3. journald のログ管理
  4. Unit設定の書き方
  5. Tips

SysVinit / Upstart

BIOS が Grub を読み込んで実行 → Grub が Kernel と初期ラムをメモリに展開して Kernel 実行 → Kernel が init Script を実行

  • SysVinit/Upstart は /etc/inittabを元に処理を実行。

    • rc.sysinit (システム初期化
    • rc (サービス起動)
    • /etc/init.d/(servise) start
    • migetty/prefdm ログイン受付
  • UpStart

    • RHEL6 にあった
    • 実際にジョブとして実行される内容はRHEL5と同じ
  • /etc/init.d/(service) のスクリプトはただのシェルスクリプト

  • Systemd が目指したもの

    • システム起動時間の短縮: 並列実行ではなかったので、遅かった
    • システム構成の動的変更: システム構成の変更に応じて、動的に必要なサービスの起動・停止をしたい
    • プロセス停止処理を標準機能化: 今まではシェルスクリプトで各自実装だったのを、systemd 自身が面倒を見る形
    • デーモン実行環境の制御: サービスごとに関連するプロセスの実行環境(Cgroups によるリソース割当とかアクセス可能なディレクトリなど)を設定するようにしたい。あとログ管理も。

Systemd

  1. Unit
    1. SysVinit のスクリプトに含まれていた個々の処理を抜き出し、それらを「Unit」として定義
    2. 例: rsyslog.service, systemd-remount-fs.service, tmp.mount, proc-sys-fs-binfmt_misc.mount, ..
  2. Unit のタイプ
    1. .service: サービス。対応するデーモンが起動
    2. .target: 何もしない。依存関係や順序関係を定義する時に、複数のUnitをグループ化するのに使用する
    3. .mount: 有効化するとデバイスなどのマウントをする
    4. .swap : Swap領域の有効化
    5. .device: デバイス。udevがデバイスを認識すると有効化
    6. .socket: systemd が特定のソケットをListenし、接続があると、指定のデーモンを起動してソケットを受け渡す。(xinetd みたいな機能)
  3. Unitには明示的に設定するのと、自動的に作成するのがある
    1. .service, .target は設定ファイルで明示的に定義する
    2. .mount, .swap は /etc/fstab から自動作成
    3. .device は udev によって自動作成

Unit 定義ファイルの場所

  • 二箇所ある。
    1. /usr/lib/systemd/system/ : システムデフォルト
    2. /etc/systemd/system/ : 管理者がカスタマイズする場所
  • 同じ名前の設定ファイルがある場合、 /etc/systemd/system/ が優先
    • システムデフォルトの設定を変更する場合、 /usr/lib/systemd/system/ から /etc/systemd/system に設定ファイルをコピーして編集
  • Unit名がそのまま設定ファイル名になる
    • シンボリックリンクでUnitの別名を設定することができる
    • ディレクトリ「(Unit名).wants」は依存関係の定義に使用

Unit の依存と順序

  1. 依存関係: 「A Unit を有効化するなら、B Unit も有効化するべき」
  2. 順序関係: 「A Unit を有効化する前に、B Unit を有効化するべき」
  • systemd が起動すると「default.target」が有効化され、それに依存するUnitがまとめて有効化
    • default.target の実態は「multi-user.target」「graphical.target」などへのシンボリックリンク。リンク先をカエルことが「デフォルト runlevelの変更」に相当

~~ 図解 ~~

要は、 default.target のリンクがrescue.targetに向いてる時はrunlevel1相当になり、multi-user.targetの時はrunlevel3graphical.targetの時はrunlevel5になる。
それぞれ、最低でも local-fs.target,swap.target,sysinit.target, basic.target が動く。

依存

  1. syetemd が起動すると、Unitの「依存関係」を元に、有効化されるUnit群を決める
    • ただし、起動する「順序関係」は別に定義
    • systemd は順序関係を持たないUnitに関しては、出来る限り並列実行を実施する。
  2. 依存関係の設定。いずれかの方法でやる
    • Unit設定ファイルの[Unit]セクションで「Wants=」オプション、もしくは「Requires=」オプションで一緒に有効化するUnitを指定
    • ディレクトリ「(Unit).wants」「(Unit).requires」内に一緒に有効化するUnitの設定ファイルへのシンボリックリンクをはる
    • Requiresは前提Unitが起動にこけると、このUnitの起動をやめる。Wantsは前提Unitが起動にこけても、このUnitの起動処理を行う
    • 他にConflict=オプションで、同時に有効化してはいけないUnitの指定ができる

順序

  1. 順序の設定は次の方法
    • Unit 設定ファイルの[Unit]セクションにおいて、After=オプションとBefore=オプションで指定する
    • After=A B C: 自分自身は、Unit「A」「B」「C」の後に起動する
    • Before=A B C: 自分自身は、Unit「A」「B」「C」の前に起動する
  2. Unit起動の「待ち合わせ」ポイントとして、target タイプのUnitを利用する

例えば

ネットワーク環境を準備するUnitには「Before=network.target」
ネットワーク環境を使用するUnitには「After=network.target」

  • ネットワークを準備する例

    /usr/lib/systemd/system/firewalld.service
    [Unit]
    Description=firewalld - dynamic firewall daemon
    Before=network.target
    Before=libvirtd.target
    Before=NetworkManager.service
    
  • ネットワークを利用する例

    /usr/lib/systemd/system/httpd.service
    [Unit]
    Description=The Apache HTTP Service
    After=network.target remote-fs.target nss-lookup.target
    

このように、network.targetにかます事で、ネットワーク準備と使用のUnit依存をまとめる

  • 現在有功なUnit依存、順序はコマンドで確認できる
  • # systemctl list-dependencies <Unit>
    • 指定Unitが必要とするUnitを表示。省略時は「default.target」
    • 依存UnitがTargetタイプの時は、さらに、それが必要なUnitを再帰表示
    • --all オプションをつけると全てのUnitを再帰表示
  • # systemctl list-dependencies <Unit> --after
    • 指定Unitより先に起動するUnitを表示
    • --all オプション有り
  • # systemctl list-dependencies <Unit> --before
    • 指定Unitより後に起動するUnitを表示
    • --all オプション有り

動的生成Unit

/usr/lib/systemd/system-generators/ 以下は、システム環境に応じて、動的なUnit生成や、既存Unitの設定変更をする

例:

  • systemd-cryptsetup-generator
  • systemd-fstab-generator:
    • /etc/fstab を参照して、 mountとswapのUnitを生成
    • mount はマウントポンとのパスで、「/」を「-」に置換したものがUnit名になる
  • systemd-rc-local-generator

    • /etc/rc.d/rc.local が実行可能ファイルの場合、rc-local.service の自動機能を有効化
  • 動的に生成されたUnitの設定ファイルは /run/systemd/generator/ 以下に配置される

一覧表示

  • # systemctl list-unit-files: 従来のchkconfig --list相当

    • enable: WantedBy=指定あり。自動起動が有功
    • disable: WantedBy=指定あり。自動起動が無効
    • static: WantedBy=指定なし
  • # systemctl list-utils

    • 現在有功なUnit一覧とその状態を表示
    • --type オプションで特定タイプのUnitのみを表示
    • --type=service で service タイプのみなど。

基本操作

  • # systemctl enable/disable (unit)
    • Unit の自動起動を有効化/無効化する
    • 実際にはWantedBy=で指定されたUnitへの依存関係を設定/削除する
  • # systemctl start/stop/restart (unit)
    • Unit をその場で 起動/停止/再起動する
    • reload は、Unit設定ファイルでreloadの動作が定義されている場合のみ使用できる
  • # systemctl status (unit)

    • Unit の実行状態を表示
    • PID や Status や CGroup や関連するデーモンプロセスや直近ログの表示とか
  • # systemctl daemon-reload

    • Unit設定ファイルを変更した時に、変更内容をsystemdに認識させる
  • chkconfig/service のコマンドは、対応するsystemctlコマンドに変換されます

  • サービス起動スクリプトで標準外オプションを使用していたのは、systemdでは使用できなくなる

    • 例: # service postgresql initdb# postgresql-setup initdb

CGroup の確認

(そもそもCgroupって何の略だろ…。Categoryかしら)

  • systemd は Cgroup を利用してUnitごとに関連するプロセスを分類

    • # systemd-cgls: Cgroupによる分類を表示
    • # systemd-cgtop: リソース利用状況を表示。topコマンドみたいなもの
  • Cgroup が同じプロセスに、まとめてシグナルを送信することができる

    • # systemctl kill -s9 sshd.service
    • sshd.service のグループに属するプロセスにKILLシグナルを送る
    • これにより、サービスに関連するプロセス全てを停止させることができる
    • --kill-who=mainオプションをつけると、グループで最初に起動したプロセスのみにシグナルを送る
  • systemctl stop で停止する時にも利用される

    1. 定義ファイルのExecStop=で指定されたコマンドを実行
    2. 該当Unitのグループにプロセスが残ってる場合は、まとめて SIGTERMを。
    3. それでも残ってる場合は SIGKILL

Journald

  • rsyslogd へ出力する内容を、systemd-journald.service:通称「journald」に送る
    • Journald はメタ情報を追加して、 /var/log/journal/以下に記録
    • journaldのログはバイナリなので、journalctlコマンドを利用して、検索・表示する
  • systemd では rsyslogd の設定変更が必要

    • 従来: Process → /dev/log → rsyslogd
    • systemd: Process → /dev/log → systemd → /run/systemd/journal/syslog → rsyslog
  • rsyslogd には、journaldから直接ログ情報を取得するモジュール imjournal があり、UnixSocket /run/systemd/journal/syslogの代わりに、これを利用するのも可

Journald の検索

  • journalctl
    • -u (Unit): 指定ユニットに関係するログのみ表示
    • -b: 直前のサーバ起動以降のログを表示
    • -f: tail -f のように、順次表示する
    • --no-pager: less コマンドを使用しない
    • -a : 長いメッセージを省略しない
    • --since='YYYY-MM-DD hh:mm:ss': 指定日以降のログ表示
    • --until='YYYY-MM-DD hh:mm:ss': 指定日までのログ表示

Unit 設定ファイル文法

  • セクションわけがされている

    • [Unit]: 依存関係・順次関係など、Unitのタイプに依存しない設定を記載
    • [Install]: 「systemctl enable/disable」コマンドに関連する設定
    • [Service]: Service タイプに固有の設定項目を記載
  • オプションに複数項目を記載するときは、スペース区切りか、同じオプションを複数回に分けて記載

  • Unit セクションの主なオプション

    • Description: 説明
    • Documentation: ドキュメントのURI
    • Requires/Wants: 同時に有効化が必要な前提Unit
    • After: これより先に起動するべきUnit
    • Before: 後に起動するべきUnit
  • Install オプション

    • WantedBy: enable時にこのUnitの.wantsディレクトリにシンボリックリンクをはる
    • RequiredBy: enable時にこのUnitの.requiredディレクトリにシンボリックリンクをはる
    • Also: enable/disable時に、同時に enable/disableするUnit
    • 例: syslog/network/auditdの環境が揃ってから起動する。multi-user.target の前提として有効化する。
/usr/lib/systemd/system/sshd.service
[Unit]
Description=OpenSSH server daemon
After=syslog.target network.target auditd.service

[Service]
EnvironmentFile=/etc/sysconfig/sshd
ExecStartPre=/usr/sbin/sshd-keygen
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s

[Install]
WantedBy=multi-user.target
  • Service タイプのオプション

    • ExecStart: サービス起動コマンド
    • ExecReload: サービス再起動コマンド?
    • ExecStop: サービス停止コマンド
    • ExecStartPre/ExecStartPost: サービス起動前後の追加コマンド/サービス起動判定には関連させたくないコマンドを記載
    • ExecStopPost: サービス停止後に実行するコマンド。サービスが以上停止した際にも実行される
    • EnvironmentFile: 環境変数を読み込むファイル
    • KillMode: ExecStopで停止せずに残ったプロセスの処理方法
    • Type: サービスプロセスの起動完了の判定方法
    • PIDFile: fork型サービスのメインプロセスのPIDファイル
    • BusName: D-Bus型サービスのbus接続名
    • Restart: サービスプロセス停止時の再起動条件(Default: no)
    • User/Group : プロセスを起動するユーザ/group
    • PrivateTmp: このサービス専用の/tmpと/var/tmpを用意する
    • ReadOnlyDirectories: 指定のディレクトリ以下をReadOnlyモードにする
    • InaccessibleDirectories: 指定ディレクトリ以下をアクセス不可にする
    • RootDirectory: 指定ディレクトリにchrootする
    • これらの機能は、ファイルシステムのネームスペースを分離することで実現している。そのため、サービスを提供するプロセスがこのネームスペース内で実施したバインドマウントは、他のプロセスからは見えなくなるという制限がある。(chroot した時に /dev/urandom ねーぞとか。)
  • Typeはサービスの起動完了を判定するタイミングを指定

    • Type=simple: 指定コマンドがフォアグラウンドで実行を継続する場合。コマンドを実行したらすぐに起動完了と判定
    • Type=forking: 子プロセスをバックグラウンドで起動して、最初のコマンドをは終了する場合。最初のコマンドが終了したタイミングを起動完了と判断
    • Type=oneshot: 一度だけコマンドを実行するタイプのサービスの場合。コマンドが終了したら起動完了と判定して、サービスも終了したものと認識。(RemainAfterExit=yesを指定すると、コマンド終了後もサービスは起動したままと認識。)
    • Type=notify: systemdのライブラリ関数「sd_notify()」を使用する場合。プロセスのプログラム内部で、sd_notify()関数で起動完了を通知するように作られている必要が有ります。
    • Type=dbus: D-Bus(プロセス間通信用メッセージバス)を利用するサービスの場合。BusNameで指定した接続名がD-BUsに登録されると、サービス起動完了と判定

プロセスが異常終了したときの動作設定

  • restartオプションでサービスの再起動を行うか指定
    • Restart=no: サービスの再起動は行いません
    • Restart=always: サービスの再起動を行う
  • デフォルトでは10秒の間に5回以上再起動すると、次の10秒間は再起動を試みない。一般では「StartLimitIntervalの間にStartLimitBurst回以上再起動すると、次のStartLimitIntervalの間は再起動を試みない」

  • systemdは起動したサービスに関連する全てのプロセスをCgroupの個別のグループに入れて管理している

  • ExecStopコマンドで停止した時、グループ内にプロセスが残っている場合、KillModeの設定に応じて残プロセス処理を行う

    • KillMode=none 残プロセスは放置
    • KillMode=process メインプロセスが残っている場合、SIGTERM/SIGKILLで停止する。その他の残プロセスは放置
    • KillMode=control-group グループ内の全ての残プロセスを SIGTERM/SIGKILL で停止する
    • KillMode=mixed メインプロセスを SIGTERM/SIGKILL で停止し、続けてグループ内の全ての残プロセスを SIGKILL で停止する。

Type=forking?

Type=forking はメインプロセスの追跡にPIDファイルが必要になることから、systemdのサービス設定ではType=ForkingよりType=simple,Type=notifyの利用が推奨される。
- Apache httpd では mod_systemdモジュールで systemd に対応している

Tips

Unitの無効化

  • # systemctl mask/unmask (Unit)
    • 指定のUnit を無効化/有効化する。maskを使用した場合、disableと異なりsystemctl startで手動起動もできなくなります。
    • mask による無効化は、 /etc/systemd/system以下に /dev/null へのシンボリックリンクをはることで行われる。/etc/systemd/system以下に設定ファイルを作成している場合は、maskによる無効化はできない

テンプレートタイプの設定ファイル

  • hoge@.service は 「hoge@<任意の文字列>.service」という複数サービスの設定ファイルとして機能する
    • # systemctl start hoge@huga.service: 「hoge@huga.service」にしたがってサービス「hoge@huga.service」が起動する。この際、設定ファイルの「%I」が「<任意の文字列>」(この場合huga)に置換される(「%i」は「%I」内の記号文字を独自ルールでエスケープしたものになる)
    • # systemctl enable hoge@huga.service: .wantsディレクトリ内に、「hoge@huga.service」から「hoge@.service」へシンボリックリンクがはられます。これにより、「hoge@huga.service」を自動起動しようとしますが、実際には「hoge@.service」の設定が使用される
Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away