本番で落ちないサービス運用のために、最小限の systemd ユニットを用意しつつ、Restart と StartLimit* を組み合わせた安全な再起動戦略を一気に整えます。この記事を読めば、雛形に必要なキーとフラッピング回避の設計まで最短でセットできます。
詳細な流れを横断的に確認したい場合は Linuxトラブルシューティング総合ハブ から全体像をご覧いただけます。
まずはこの雛形:Restart=前提の安全設計テンプレ
最短で迷わず使える最小ユニット雛形です。再起動戦略は結論として「Restart=on-failure+RestartSecで間隔を置き、StartLimitでフラッピング抑制」を標準にします。
# /etc/systemd/system/myapp.service
[Unit]
Description=My App
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/srv/myapp
ExecStart=/srv/myapp/bin/start
ExecStop=/srv/myapp/bin/stop
Restart=on-failure
RestartSec=5s
SuccessExitStatus=0 143
RestartPreventExitStatus=23
TimeoutStopSec=30s
KillMode=control-group
[Install]
WantedBy=multi-user.target
Restart=on-failureとRestartSec=でのリトライ間隔
Restart=on-failureは異常終了・シグナル終了時のみ自動再起動します。常時ループの危険が減り、意図的な停止(systemctl stopや正常終了コード)では再起動しません。RestartSec=5sは再起動のクールダウンです。短すぎるとCPUやログを浪費するため、まずは5〜10秒を基準にし、起動コストが高いサービスはやや長め(10〜30秒)に伸ばします。
StartLimitInterval=/StartLimitBurst=でフラッピング抑制
StartLimitIntervalSec=300とStartLimitBurst=5は、5分で5回以上の再起動が続いたときにユニットを抑止(Start request repeated too quickly.)します。
事故的なクラッシュループを仕組みで強制停止でき、夜間の暴走を防げます。抑止後は原因を直してからsystemctl reset-failed myapp && systemctl start myappで復帰します。
落とし穴と対策:依存関係・停止挙動・退出コードの扱い
再起動戦略が良くても、依存関係や停止の作法、終了コードの解釈を誤るとsystemdユニットは不安定になります。起動順・ネットワーク待機・丁寧な停止・終了コードの明示をそろえて、再発しない設計に固めます。
After=/Requires=の付け方とネットワーク待機(network-online.target)
After=は順序、Requires=は存在必須の依存です。ネットワーク必須なら次のようにします。
- 最低限:
After=network-online.target+Wants=network-online.target - 本気で待つ:
systemd-networkd-wait-online.serviceやNetworkManager-wait-online.serviceを有効化
DNSや外部API前提のアプリは、実通信が可能になるまで待つ設計にしないとクラッシュ→再起動ループを誘発します。不要なRequires=多用は起動失敗の連鎖になるため、必要最小限に留めます。
SuccessExitStatus=/RestartPreventExitStatus=で「正常終了扱い」を明示
アプリ都合の終了コードをsystemdにどう見せるかを調整します。
SuccessExitStatus=0 143:例)SIGTERM(143)での穏当な終了を成功扱いにするRestartPreventExitStatus=23:例)設定ミス時にexit 23で再起動を抑止し、無限ループを避ける
これにより、Restart=on-failureの判定が意図通りになります。終了コード設計はアプリ側とセットで決めます。
KillMode=/TimeoutStopSec=で停止を丁寧に
停止時はまず穏やかに、必要なら強制が原則です。
KillMode=control-group:同一cgroup内の子プロセスまで一括停止。孤児プロセスを残さないTimeoutStopSec=30s:ExecStop=やアプリのシャットダウンに十分な猶予を与える- 併用ヒント:
ExecStop=で自前の停止スクリプトを呼び、接続のドレインや一時ファイルのフラッシュを済ませてから終了TimeoutStopSecが短すぎるとSIGKILL連発でデータ破損や再同期コスト増につながります。反対に長すぎるとリリース時の足止めになるため、実測で調整します。
本番運用チェックリスト:変更→デーモン再読込→温和なリスタート
ユニット変更時の安全な反映手順を定型化します。最小の停止時間で確実に反映し、初期不安定期はログで挙動を観察します。
daemon-reloadのタイミングとsystemctl reload/restart使い分け
ユニットファイル(.service)やドロップイン(/etc/systemd/system/myapp.service.d/*.conf)を編集したら、まずdaemon-reloadで定義を再読込します。
- 反映の基本:
sudo systemctl daemon-reload- 設定検証:
systemd-analyze verify /etc/systemd/system/myapp.service - 温和な反映:
systemctl reload myapp(アプリがSIGHUP等で設定再読込に対応している場合) - 非対応なら短時間停止で:
systemctl restart myappreloadは接続を切らずに反映できるのが利点です。restartは確実ですが瞬断が発生します。どちらを採用するかはアプリの実装で決めます。
ログ監視(journalctl -u <unit>)と初期不安定期の観察ポイント
デプロイ直後や設定変更直後は数分間の観察を欠かさないでください。
- 直近ログ:
journalctl -u myapp -b -n 200 -f(起動後の追尾) - 再起動ループ検知:
systemctl status myappでActiveの遷移回数と「Start request repeated too quickly」を確認 - 退出コードの傾向:
journalctl内のcode=exited, status=…やsignal=をチェック - ネットワーク待機の失敗:
network-online.target関連やwait-onlineのタイムアウト - 資源枯渇:同時に
dmesg -Tやsudo systemd-cgtopでOOM/KILLやcgroup圧迫を確認
初期の小さなエラーでも、同一パターンがStartLimitにぶつかる前に手当てすることで、夜間の無用なアラートやサービス停止を防げます。
まとめ
systemdの基本を押さえて雛形と再起動戦略を整えれば、サービスは安定して稼働し続けます。Restart=on-failureとRestartSecで再起動の間隔を設け、StartLimitでフラッピングを防止し、依存関係や停止挙動まで定義しておくことが安全運用の第一歩です。
本番運用では、daemon-reloadやjournalctlでの確認を習慣化し、ユニットが予期せず落ちても被害が広がらないようにします。さらに、デプロイ直後の確認手順を組み合わせれば、障害の芽を早期に摘むことができます。
systemdでの自動再起動設計を固めたら、依存関係管理や監視・通知まで含めてハブ記事を活用し、運用設計を一気に仕上げましょう。
