Linux管理・運用の基本
システム管理者のための実践ガイド
システム管理者のための実践ガイド
前回はsystemdの基本であるユニットファイルの編集とカスタムサービスの作成方法について解説しました。今回はさらに一歩踏み込み、systemdの強力な機能であるタイマーユニットとソケットユニットについて詳しく見ていきます。
これらのユニットを使いこなすことで、定期的なタスクの自動化や、必要な時だけサービスを起動するといった効率的なシステム運用が可能になります。この記事では、タイマーユニットとソケットユニットの概要から、それぞれの設定方法、そして具体的な活用例まで、丁寧に解説します。
タイマーユニット(.timer)は、指定した時間や間隔でサービスユニット(.service)を自動的に実行するためのsystemdの機能です。従来のcronに代わる新しい仕組みとして、より柔軟で安定したタスクスケジューリングを提供します。systemdの他のユニットと連携するため、ログの管理や依存関係の制御といった統合的な管理が容易になります。
タイマーユニットは主に[Timer]セクションと、サービスユニットとの連携を定義する[Unit]セクションで構成されます。
| オプション | 意味 | 補足 |
|---|---|---|
OnCalendar= |
カレンダー形式で実行日時を指定します。 | OnCalendar=dailyやOnCalendar=Mon *-*-* 03:00のように柔軟な指定が可能。 |
OnActiveSec= |
ユニットがアクティブになってからの秒数で実行を遅延させます。 | |
OnBootSec= |
システム起動からの秒数で実行を遅延させます。 | OnBootSec=10minのように指定。 |
AccuracySec= |
スケジュールの実行精度を設定します。 | デフォルトは1分。タスクの開始をどれくらい厳密にするかを制御します。 |
RandomizedDelaySec= |
実行開始時間を指定した秒数分ランダムに遅延させます。 | 同時に多くのタイマーが動くことによる負荷集中を避けるために有用です。 |
Persistent= |
システムの再起動を跨いで、実行予定時刻を保持するかを指定します。 | trueに設定すると、システム停止中に実行されるべきだったタスクが起動後にすぐに実行されます。 |
OnCalendarは非常に強力で、cronよりも直感的な表記が可能です。例えば、「毎月1日の午前5時30分」ならOnCalendar=monthly 5:30、「毎週月曜日の午後10時」ならOnCalendar=Mon 22:00と記述できます。OnCalendarは複数行にわたって記述できますが、複数の条件はORとして扱われるため、「毎日かつ午前2時」のようなAND条件はOnCalendar=*-*-* 02:00:00のように1行で簡潔に表現するのが一般的です。
OnCalendarの最後に@タイムゾーンを追加することで、特定のタイムゾーンで実行時間を指定することも可能です(例: OnCalendar=Mon 10:00:00 America/New_York)。有効なタイムゾーンのリストはtimedatectl list-timezonesコマンドで確認できます。
RandomizedDelaySecの役割と注意点RandomizedDelaySecオプションは、OnCalendarなどで設定された起動時刻に、指定された時間内のランダムな遅延を加えることで、タイマーの起動時間を分散させるために使用されます。
これにより、dailyやweeklyといった同じタイミングで起動するように設定された複数のタイマーユニットが、同時に起動するのを防ぐことができます。複数のタイマーが同時に起動すると、以下のような問題が発生する可能性があります。
Persistent=trueの注意点Persistent=trueは、システムが再起動しても、タイマーが最後に実行された時間を覚えておく便利な機能ですが、不用意に設定すると想定外の負荷につながる可能性があります。
Persistent=trueを設定すると、ディスクへの書き込みが頻繁に発生し、I/O負荷が増加します。Persistentタイマーが「次に実行されるはずだった時間」を計算し、ほぼ同時に実行される可能性があります。これは、RandomizedDelaySecが設定されていない場合に特に顕著です。Persistent=trueを使用する場合は、RandomizedDelaySecを併用して、再起動後のタイマー実行時間を分散させることが強く推奨されます。
ここでは、毎日深夜2時に実行されるバックアップサービスを作成する例を見てみましょう。
サービスユニットファイルを作成
backup.serviceとして/etc/systemd/system/に保存します。
[Unit]
Description=Daily Backup Service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup-script.sh
タイマーユニットファイルを作成
backup.timerとして/etc/systemd/system/に保存します。
[Unit]
Description=Run daily backup at 2 AM
[Timer]
OnCalendar=*-*-* 02:00:00
AccuracySec=1h
Persistent=true
RandomizedDelaySec=600
[Install]
WantedBy=timers.target
ユニットを有効化し、起動
# systemdに新しいユニットを読み込ませる
$ sudo systemctl daemon-reload
# タイマーユニットを有効化する
$ sudo systemctl enable backup.timer
# タイマーユニットを起動する
$ sudo systemctl start backup.timer
# タイマーユニットの状態を確認する
$ sudo systemctl status backup.timer
| 機能 | cron | systemd.timer |
|---|---|---|
| ログ管理 | syslog依存 | journalctlで一元管理 |
| ユニット依存関係 | 不可 | 可能 |
| タイムゾーン | 基本固定 | 柔軟に指定可能 |
| システム停止中のタスク | 実行されない | Persistent=trueで起動後に実行可能 |
| 実行精度 | 分単位 | 秒、マイクロ秒単位で指定可能 |
ソケットユニット(.socket)は、特定のネットワークソケットやIPC(プロセス間通信)ソケットへの接続を監視し、接続要求があった場合にのみ、関連するサービスユニット(.service)を起動するための仕組みです。従来のinetdやxinetdの機能を取り込み、より統合的な管理を実現しています。
この方式の最大のメリットは、常にサービスを起動しておく必要がないため、システムリソース(メモリ、CPU)を節約できる点です。
sshd.socketユニットは、SSH接続要求があった時に初めてsshd.serviceを起動します。この機能はセキュリティポリシーに合わせて適切に利用しましょう。ソケットユニットは主に[Socket]セクションと、サービスユニットとの連携を定義する[Unit]セクションで構成されます。
| オプション | 意味 | 補足 |
|---|---|---|
ListenStream= |
TCPストリームソケットを監視します。 | ListenStream=8080のようにポート番号を指定します。 |
ListenDatagram= |
UDPデータグラムソケットを監視します。 | ListenDatagram=9000のように指定します。 |
Accept= |
ソケットからの接続を個別のサービスプロセスに渡すかどうかを指定します。 | yesに設定すると、接続ごとに新しいサービスプロセスが起動します。noに設定すると、単一のプロセスで全ての接続を処理します。 |
FreeBind= |
起動時にポートが使用されていても起動するかどうかを指定します。 |
Accept=yesの注意点Accept=yesを不用意に使用すると、プロセスが乱立する可能性があります。これは、inetdのように接続ごとに新しいプロセスを起動する挙動です。
クライアントからの接続が短時間に多数集中すると、Accept=yesが有効なソケットユニットは、その接続ごとに新しいサービスプロセスを次々と起動します。これにより、システムのCPUやメモリに過度な負荷がかかり、リソースが枯渇する可能性があります。ほとんどの場合、デフォルトのAccept=noで十分です。
ここでは、HTTPリクエストがあった時だけ起動する簡易Webサーバーを作成する例を見てみましょう。この例では、より一般的なAccept=noを使用します。
サービスユニットファイルを作成
web.serviceとして/etc/systemd/system/に保存します。ソケットユニット経由で起動するサービスは、セキュリティの観点から専用の制限ユーザーで実行するのが望ましいです。以下の例ではUser=nobodyとしています。
[Unit]
Description=Simple Web Server
Requires=web.socket
[Service]
User=nobody
ExecStart=-/bin/sh -c 'while read -r line; do case "$line" in GET\ *) echo "HTTP/1.0 200 OK"; echo "Content-Type: text/plain"; echo; echo "Hello, world!"; break; esac; done'
StandardInput=socket
StandardInput=socketは、ソケットユニットからの入力をこのサービスプロセスの標準入力にリダイレクトする重要な設定です。これにより、サービスはソケットからの接続データを直接読み込むことができます。
ソケットユニットファイルを作成
web.socketとして/etc/systemd/system/に保存します。
[Unit]
Description=Socket for simple web server
[Socket]
ListenStream=8080
[Install]
WantedBy=sockets.target
ユニットを有効化し、起動
ソケットユニットを有効化・起動するだけで、サービスは必要になるまで起動しません。
$ sudo systemctl daemon-reload
$ sudo systemctl enable web.socket
$ sudo systemctl start web.socket
動作確認
別のターミナルからcurlコマンドでリクエストを送ると、サービスが起動してレスポンスが返されます。
$ curl http://localhost:8080
Hello, world!
| 機能 | inetd/xinetd | systemd.socket |
|---|---|---|
| 設定ファイル | /etc/inetd.confなど個別の設定ファイル |
systemdユニットファイルに統合 |
| プロセス管理 | 独立したデーモンが管理 | systemdが統合管理 |
| サービス連携 | 外部のスクリプトと連携 | systemdサービスユニットと密接に連携 |
| 依存関係 | 不可 | 他のユニットとの依存関係を定義可能 |
| 機能 | 基本的なソケット監視 | タイマー、パスなどと連携してより高度な機能を実現 |
今回は、systemdの高度な機能であるタイマーユニットとソケットユニットについて解説しました。
OnCalendarなどのオプションで、高度なスケジュール管理が可能です。これらのユニットを組み合わせることで、システムの負荷を最適化しながら、堅牢な自動化・運用体制を構築できます。
この記事が、Linux管理・運用の知識を深める一助となれば幸いです。ご覧いただきありがとうございました。次回は、ファイルの更新をトリガーにジョブを走らせるパスユニットと、外部ストレージのマウント管理に役立つマウントユニットについて解説します。