2026年11月13日

2026年11月13日

Linuxのsystemdタイマーでバックアップを自動化する方法

はじめに

Linux で定期実行といえば伝統的に cron ですが、近年は systemd.timer を使う選択肢が増えています。理由は明快で、systemd.timer は実行ログが journalctl に集約され、依存関係(ネットワーク起動後など)を宣言的に定義でき、失敗時のリトライや前回失敗時のキャッチアップも標準サポートされているためです。

特にバックアップのような「成功/失敗を後から追跡したい」「ノートPC のように電源が入っていない時間がある環境でも実行したい」用途には、OnCalendar と Persistent=true の組み合わせが理想的です。

本記事では、restic を使ったバックアップを systemd.timer で完全自動化する例を、ユニット定義から監視まで通しで解説します。

症状・背景

systemd timer 化したくなる場面:

  • cron の実行結果がメール送信に依存していて見落としが多い
  • 平日業務時間外のみ走らせたいが cron 表記が複雑になりすぎる
  • 前回実行が止まっていた時に次回起動時にキャッチアップして欲しい
  • バックアップの所要時間や成否を Prometheus でメトリクス化したい

手順・設定方法

ステップ1: サービスユニットを作成

cat <<'EOF' | sudo tee /etc/systemd/system/backup.service
[Unit]
Description=Daily restic backup
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
EnvironmentFile=/etc/backup/restic.env
ExecStart=/usr/local/bin/restic backup /var/www /etc /home --tag daily
ExecStartPost=/usr/local/bin/restic forget --keep-daily 7 --keep-weekly 4 --prune
Nice=10
IOSchedulingClass=best-effort
IOSchedulingPriority=7
EOF

ステップ2: タイマーユニットを作成

cat <<'EOF' | sudo tee /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 03:00

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=15min
Persistent=true
Unit=backup.service

[Install]
WantedBy=timers.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer

ステップ3: 状態確認とログ閲覧

# 次回実行予定時刻と直近実行の確認
systemctl list-timers backup.timer

# 直近のサービス実行履歴
systemctl status backup.service --no-pager

# ログ全文(journald)
sudo journalctl -u backup.service --since '24 hours ago' --no-pager

# 失敗時のみ確認
sudo journalctl -u backup.service -p err --no-pager

ステップ4: 失敗時の通知連携(OnFailure)

# 失敗時に通知サービスを起動するドロップイン
sudo mkdir -p /etc/systemd/system/backup.service.d
cat <<'EOF' | sudo tee /etc/systemd/system/backup.service.d/onfailure.conf
[Unit]
OnFailure=backup-notify@%n.service
EOF

# 通知用テンプレートサービス
cat <<'EOF' | sudo tee /etc/systemd/system/backup-notify@.service
[Unit]
Description=Notify backup failure for %i

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'curl -X POST -H "Content-type: application/json" \
  --data "{\"text\":\"[FAIL] %i on $(hostname)\"}" \
  https://hooks.slack.com/services/T000/B000/XXX'
EOF
sudo systemctl daemon-reload

注意事項

  • Persistent=true はノートPC等で起動時間が予測不能な環境向け。常時稼働サーバーでは不要なこともある
  • RandomizedDelaySec は複数ホストで同時実行を避けるためのジッタ。バックアップ集中による I/O 競合を防げる
  • 環境変数を扱う場合は EnvironmentFile= で別ファイル化し、chmod 600 で保護
  • Type=oneshot を必ず付けないと、コマンド終了で「失敗」と扱われる場合がある

まとめ

1. service ユニット: 実行内容と環境を宣言的に記述

2. timer ユニット: OnCalendar で柔軟なスケジュール

3. Persistent: 起動時のキャッチアップで「実行漏れ」防止

4. journald: 全実行が journalctl で検索可能

5. OnFailure: 失敗通知を別ユニットで切り分け可能

関連記事:

お気軽にご相談ください

お見積りへ お問い合わせへ
▲