サーバー運用では、バックアップやログローテーション、監視スクリプトなど「定期的に自動実行したいジョブ」が数多くあります。AlmaLinux 9 では、従来の cron に加えて systemd timer による定期実行も標準で利用できます。本記事では、crontab の書式から systemd timer の作成、cron から timer への移行判断、排他制御やデバッグまで、企業のサーバー運用チームで求められる知識を手順つきで整理しています。
コマンド早見表
| やりたいこと | コマンド |
|---|---|
| ユーザー cron 一覧表示 | crontab -l |
| ユーザー cron 編集 | crontab -e |
| ユーザー cron 削除 | crontab -r |
| 他ユーザーの cron 確認 | crontab -u <user> -l |
| システム cron 確認 | cat /etc/crontab |
| cron.d 配下の確認 | ls /etc/cron.d/ |
| run-parts 対象確認 | run-parts –test /etc/cron.daily |
| anacrontab 確認 | cat /etc/anacrontab |
| timer 一覧表示 | systemctl list-timers –all |
| timer 有効化・起動 | systemctl enable –now xxx.timer |
| timer 手動テスト | systemctl start xxx.service |
| timer ログ確認 | journalctl -u xxx.service |
| OnCalendar 書式検証 | systemd-analyze calendar “書式” |
| crond サービス状態 | systemctl status crond |
前提条件
| 項目 | 値 |
|---|---|
| OS | AlmaLinux 9.6(Sage Margay) |
| cronie | 1.5.7-13.el9(cronie-anacron 含む) |
| systemd | 252 |
| 実行ユーザー | 一般ユーザー(crontab)/ root(システム cron、systemctl) |
1. cron の基本
cron は UNIX 系 OS で長年使われている定期実行の仕組みです。crond デーモンが常駐し、登録されたジョブを指定時刻に実行します。
crond の稼働確認
ジョブを登録する前に、crond が動作していることを確認します。
実行コマンド:
# systemctl status crond
実行結果:
● crond.service - Command Scheduler
Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; preset: enabled)
Active: active (running)
active (running) かつ enabled になっていれば、crond は稼働中で OS 起動時にも自動起動します。
crontab の書式
crontab の各行は「いつ」「何を」実行するかを 6 つのフィールドで定義します。
┌───────────── 分 (0 - 59)
│ ┌───────────── 時 (0 - 23)
│ │ ┌───────────── 日 (1 - 31)
│ │ │ ┌───────────── 月 (1 - 12)
│ │ │ │ ┌───────────── 曜日 (0 - 7, 0と7は日曜日)
│ │ │ │ │
* * * * * コマンド
各フィールドで使える特殊文字は以下の通りです。
| 特殊文字 | 意味 | 例 |
|---|---|---|
| * | すべての値 | * = 毎分 / 毎時 / 毎日 |
| */n | n ごと(ステップ) | */5 = 5 分ごと |
| a-b | a から b の範囲 | 1-5 = 月曜〜金曜 |
| a,b,c | リスト指定 | 1,3,5 = 月・水・金 |
曜日フィールドの数値は 0 = 日曜日 で始まり、7 も日曜日として扱われます。
特殊文字列(ショートカット)
crontab では数値指定の代わりに、以下の特殊文字列を使って直感的にスケジュールを記述できます。
| 特殊文字列 | 等価な書式 | 意味 |
|---|---|---|
| @reboot | (起動時に 1 回) | OS 起動時に実行 |
| @hourly | 0 * * * * | 毎時 0 分に実行 |
| @daily | 0 0 * * * | 毎日 0:00 に実行 |
| @weekly | 0 0 * * 0 | 毎週日曜 0:00 に実行 |
| @monthly | 0 0 1 * * | 毎月 1 日 0:00 に実行 |
ユーザー crontab の操作
各ユーザーは自分の crontab を持つことができます。ユーザー crontab の実体は /var/spool/cron/<ユーザー名> に格納されますが、直接編集せず crontab コマンドで操作します。
現在のユーザー crontab を一覧表示するコマンドです。
実行コマンド:
$ crontab -l
実行結果:
no crontab for developer
ジョブが未登録の場合はこのように表示されます。crontab を編集するには crontab -e を実行します。EDITOR 環境変数に設定されたエディタ(デフォルトは vi)が開きます。
root 権限で他ユーザーの crontab を確認する場合は -u オプションを使います。
実行コマンド:
# crontab -u developer -l
crontab -r の誤実行に注意
crontab -r は確認なしでユーザーの crontab をすべて削除します。-e(編集)と -r(削除)はキーボード上で隣接しているため、誤って実行してしまう事故が起きやすいコマンドです。対策として、crontab を編集する前に crontab -l > ~/crontab_backup_$(date +%Y%m%d).txt でバックアップを取得しておくことを推奨します。
2. システム cron
ユーザー crontab とは別に、システム全体で管理する cron 設定があります。root が管理する定期ジョブはこちらに配置します。
/etc/crontab
システム crontab は /etc/crontab に配置されています。ユーザー crontab との違いは、コマンドの前に「実行ユーザー名」フィールドがある点です。
実行コマンド:
# cat /etc/crontab
実行結果:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
AlmaLinux 9 のデフォルトでは、/etc/crontab にはジョブの定義がなく、環境変数のみが記載されています。実際のシステムジョブは /etc/cron.d/ ディレクトリに配置されています。
/etc/cron.d/ ディレクトリ
/etc/cron.d/ には、パッケージやシステム管理者が配置するジョブ定義ファイルが格納されます。書式は /etc/crontab と同じ(ユーザー名フィールドあり)です。
実行コマンド:
# cat /etc/cron.d/0hourly
実行結果:
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
この設定により、毎時 1 分に root ユーザーで /etc/cron.hourly/ 内のスクリプトが run-parts コマンドで一括実行されます。
/etc/cron.d/ のファイル名にドットを含めない
/etc/cron.d/ に配置するファイル名にドット(.)を含めると、crond はそのファイルを無視します。たとえば backup.sh や cleanup.cron のような名前では読み込まれません。backup-daily や cleanup のように、英数字・ハイフン・アンダースコアのみで命名してください。
/etc/cron.{hourly,daily,weekly,monthly}/
これらのディレクトリにスクリプトを配置すると、対応する周期で自動実行されます。cron.hourly は /etc/cron.d/0hourly の設定で毎時実行され、cron.daily・cron.weekly・cron.monthly は anacron 経由で実行されます。
run-parts がどのファイルを実行対象として認識するかは --test オプションで事前に確認できます。
実行コマンド:
# run-parts --test /etc/cron.daily
run-parts は、ファイル名に拡張子(ドット以降)が含まれるファイルを実行対象から除外します。たとえば backup.sh は無視され、backup であれば対象になります。また、実行権限(chmod +x)が付与されていないファイルも除外されます。
3. cron の実務設定
環境変数の設定
cron ジョブが動かない最も多い原因は PATH の問題です。cron が使用するデフォルトの PATH は /usr/bin:/bin のみで、通常のログインシェルとは異なります。
cron の PATH はログインシェルと異なる
ログインシェルでは /usr/local/bin や /usr/sbin が PATH に含まれますが、cron のデフォルト PATH には含まれません。スクリプト内でコマンドをフルパスで指定するか、crontab の先頭で PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin を定義してください。
crontab で設定可能な主な環境変数は以下の通りです。
| 変数 | デフォルト値 | 用途 |
|---|---|---|
| PATH | /usr/bin:/bin | コマンド検索パス |
| SHELL | /bin/sh | ジョブ実行に使用するシェル |
| MAILTO | crontab の所有者 | ジョブの標準出力・標準エラーの送信先メールアドレス |
crontab の先頭に環境変数を定義する例です。
実行コマンド:
$ crontab -e
以下の内容を記述します。
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
SHELL=/bin/bash
MAILTO=admin@example.corp
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
出力のリダイレクト
cron ジョブの標準出力と標準エラー出力は、デフォルトでは MAILTO で指定したアドレスにメール送信されます。メールサーバーが設定されていない環境では出力が消失するため、ログファイルにリダイレクトすることを推奨します。
0 2 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
>> で追記、2>&1 で標準エラーも同じファイルに出力します。>(上書き)ではなく >>(追記)を使う理由は、過去のログを保持するためです。
cron のアクセス制御
cron の利用を許可・拒否するユーザーは /etc/cron.allow と /etc/cron.deny で制御します。
| ファイル | 動作 |
|---|---|
| cron.allow が存在する | cron.allow に記載されたユーザーのみ利用可能 |
| cron.allow がなく cron.deny が存在する | cron.deny に記載されたユーザー以外が利用可能 |
| 両方とも存在しない | root のみ利用可能 |
AlmaLinux 9 のデフォルトでは /etc/cron.allow は存在せず、/etc/cron.deny が空の状態で存在します。この状態ではすべてのユーザーが cron を利用できます。
特定のユーザーのみに cron の利用を制限する場合は、/etc/cron.allow を作成して許可するユーザーを記載します。
実行コマンド:
# echo "developer" > /etc/cron.allow
切り戻す場合は /etc/cron.allow を削除すれば、元の動作(cron.deny による制御)に戻ります。
実行コマンド:
# rm /etc/cron.allow
4. anacron
anacron は、サーバーが停止していた間にスキップされたジョブを、次回起動時に補完実行する仕組みです。24 時間稼働ではない開発サーバーや、メンテナンスで定期的に停止するサーバーで役立ちます。
パッケージの確認
AlmaLinux 9 では cronie-anacron がデフォルトでインストールされています。
実行コマンド:
$ rpm -q cronie cronie-anacron
実行結果:
cronie-1.5.7-13.el9.x86_64
cronie-anacron-1.5.7-13.el9.x86_64
/etc/anacrontab の書式
/etc/anacrontab は anacron の設定ファイルです。各行は「期間日数」「遅延分」「ジョブ名」「コマンド」の 4 フィールドで構成されます。
実行コマンド:
# cat /etc/anacrontab
実行結果:
RANDOM_DELAY=45
START_HOURS_RANGE=3-22
1 5 cron.daily nice run-parts /etc/cron.daily
7 25 cron.weekly nice run-parts /etc/cron.weekly
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly
各フィールドの意味は以下の通りです。
| フィールド | 例(cron.daily の場合) | 意味 |
|---|---|---|
| 期間日数 | 1 | 1 日ごとに実行 |
| 遅延分 | 5 | anacron 起動後 5 分待ってから実行 |
| ジョブ名 | cron.daily | タイムスタンプファイルの識別名 |
| コマンド | nice run-parts /etc/cron.daily | nice 付きで cron.daily 内のスクリプトを実行 |
環境変数 RANDOM_DELAY=45 は 0〜45 分のランダムな遅延を追加します。複数サーバーで同時にジョブが走ることによる負荷集中を避ける目的です。START_HOURS_RANGE=3-22 は、anacron がジョブを実行してよい時間帯(3:00〜22:00)を指定しています。
5. systemd timer の基本
systemd timer は、systemd が提供するタイマー機能です。.timer ユニットと .service ユニットのペアで動作します。timer が指定した時刻になると、対応する service を起動してジョブを実行します。
既存の timer を確認する
AlmaLinux 9 にはデフォルトでいくつかの timer が登録されています。
実行コマンド:
# systemctl list-timers --all
実行結果:
NEXT LEFT LAST PASSED UNIT ACTIVATES
Wed 2026-03-25 01:50:52 JST 1h 17min left Wed 2026-03-25 00:25:46 JST 7min ago dnf-makecache.timer dnf-makecache.service
Wed 2026-03-25 14:44:36 JST 14h left Tue 2026-03-24 14:44:36 JST 9h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Thu 2026-03-26 00:00:00 JST 23h left Wed 2026-03-25 00:00:46 JST 32min ago logrotate.timer logrotate.service
各列の意味は次の通りです。
- NEXT:次回の実行予定時刻
- LEFT:次回実行までの残り時間
- LAST:前回の実行時刻
- PASSED:前回実行からの経過時間
- UNIT:timer ユニット名
- ACTIVATES:timer が起動する service ユニット名
timer ユニットの主要なオプション
timer ユニットの [Timer] セクションで使用する主なオプションです。
| オプション | 説明 | 例 |
|---|---|---|
| OnCalendar | カレンダー形式で実行時刻を指定 | OnCalendar=daily |
| OnBootSec | OS 起動からの経過時間で指定 | OnBootSec=10min |
| OnUnitActiveSec | service の前回起動からの経過時間で指定 | OnUnitActiveSec=1h |
| AccuracySec | 実行時刻の精度(デフォルト 1min) | AccuracySec=1h |
| RandomizedDelaySec | ランダムな遅延の最大値 | RandomizedDelaySec=60m |
| Persistent | 前回実行されなかった分を起動時に補完 | Persistent=true |
既存の timer の設定を確認してみます。
実行コマンド:
# systemctl cat logrotate.timer
実行結果([Timer] セクション):
[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true
OnCalendar=daily は毎日 0:00 に実行する設定です。AccuracySec=1h により最大 1 時間の幅で実行タイミングが調整されます。これはシステム負荷を分散する目的です。Persistent=true により、サーバー停止中にスキップされたジョブは次回起動時に実行されます。
OnCalendar の書式検証
systemd-analyze calendar コマンドで、OnCalendar に指定する書式が意図通りのスケジュールになるか事前に検証できます。
実行コマンド:
$ systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
実行結果:
Normalized form: Mon..Fri *-*-* 09:00:00
Next elapse: Wed 2026-03-25 09:00:00 JST
From now: 8h left
Normalized form で正規化された書式を確認でき、Next elapse で次回実行時刻を確認できます。本番に投入する前に必ずこのコマンドで検証してください。
自作の timer / service を作成する
毎日 3:00 にバックアップスクリプトを実行する timer を作成する例です。まず service ユニットを作成します。service が「何を実行するか」を定義し、timer が「いつ実行するか」を定義します。
実行コマンド:
# cat /etc/systemd/system/backup-daily.service
以下の内容で作成します。
[Unit]
Description=Daily backup script
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
StandardOutput=journal
StandardError=journal
Type=oneshot は、スクリプトが完了するまで待ち、完了後にユニットの状態を inactive に戻す設定です。定期実行のジョブでは oneshot を使います。StandardOutput=journal により出力が journald に記録されます。
次に timer ユニットを作成します。
実行コマンド:
# cat /etc/systemd/system/backup-daily.timer
以下の内容で作成します。
[Unit]
Description=Run daily backup at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
AccuracySec=5min
Persistent=true
[Install]
WantedBy=timers.target
AccuracySec=5min で実行精度を 5 分以内に設定しています。デフォルトの 1 分よりも緩くすることで、他のジョブとの同時実行を避けつつ、過度に厳密なタイミング制御によるシステム負荷を抑えます。[Install] セクションの WantedBy=timers.target は systemctl enable 時に timers.target に組み込むための設定です。
ユニットファイルを作成したら、daemon-reload で systemd に認識させ、timer を有効化・起動します。
実行コマンド:
# systemctl daemon-reload
実行コマンド:
# systemctl enable --now backup-daily.timer
enable --now は enable(自動起動の有効化)と start(即時起動)を同時に行います。timer が登録されたことを確認します。
実行コマンド:
# systemctl list-timers backup-daily.timer
timer と service のファイル名を揃える
timer ユニットは、同名の service ユニット(backup-daily.timer → backup-daily.service)を自動的に紐づけます。ファイル名を揃えておけば、timer の [Timer] セクションに Unit= を明示する必要はありません。
6. systemd timer の実務設定
排他制御(多重起動の防止)
ジョブの実行時間が予想以上に長引いた場合、次回のスケジュール時刻に前回のジョブがまだ実行中という事態が起こり得ます。同じジョブが同時に複数走ると、データの不整合やリソース競合の原因になります。
systemd timer の場合、service に Type=oneshot を指定していれば、前回の service が完了するまで次回の起動は待機されます。これにより多重起動が防止されます。
cron での排他制御(flock)
cron には systemd のような排他制御の仕組みがないため、flock コマンドでロックファイルを使った排他制御を行います。
0 */1 * * * /usr/bin/flock -n /tmp/backup.lock /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
-n オプションはロックが取得できない場合(前回のジョブが実行中の場合)に即座に終了します。-w 60 に変更すると、最大 60 秒間ロックの取得を待ちます。運用要件に応じて選択してください。
エラー通知(OnFailure)
systemd timer で実行した service が失敗した場合に、別のユニットを起動して通知する仕組みが OnFailure= です。
まず通知用の service を作成します。
実行コマンド:
# cat /etc/systemd/system/notify-failure@.service
以下の内容で作成します。
[Unit]
Description=Send failure notification for %i
[Service]
Type=oneshot
ExecStart=/opt/scripts/notify-failure.sh %i
@ 付きのユニット名はテンプレートユニットです。%i にはインスタンス名(呼び出し元のユニット名)が入ります。
バックアップ service の [Unit] セクションに OnFailure= を追加します。
[Unit]
Description=Daily backup script
OnFailure=notify-failure@%n.service
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
StandardOutput=journal
StandardError=journal
%n は現在のユニット名(backup-daily.service)に展開されます。バックアップが失敗すると notify-failure@backup-daily.service が起動し、通知スクリプトが実行されます。
ログ確認と手動テスト
timer で実行された service のログは journalctl で確認します。
実行コマンド:
# journalctl -u backup-daily.service
timer のスケジュールを待たずに service を手動で実行してテストするには、service を直接起動します。
実行コマンド:
# systemctl start backup-daily.service
実行後、ステータスを確認します。
実行コマンド:
# systemctl status backup-daily.service
Active: inactive (dead) かつ Result: success と表示されれば、oneshot の service が正常に完了したことを意味します。Result: exit-code の場合はスクリプトがエラー終了しているため、journalctl でログを確認してください。
7. cron から systemd timer への移行
systemd timer は cron の上位互換ではなく、それぞれに適した用途があります。移行を検討する際は、以下の比較を参考にしてください。
機能比較
| 機能 | cron | systemd timer |
|---|---|---|
| ログ出力 | 自前でリダイレクトが必要 | journald に自動記録 |
| 依存関係 | なし | After= / Requires= で他ユニットとの依存を定義可能 |
| リソース制御 | なし | CPUQuota= / MemoryMax= でリソース制限可能 |
| 状態確認 | ログを確認するしかない | systemctl status で即座に確認可能 |
| 排他制御 | flock を使って自前で実装 | Type=oneshot で標準対応 |
| 失敗時通知 | MAILTO(メール依存) | OnFailure= で任意の処理を起動 |
| 停止中の補完 | anacron が必要 | Persistent=true で対応 |
| 秒単位のスケジュール | 不可(最小単位は分) | OnCalendar で秒単位まで指定可能 |
移行例
以下の cron ジョブを systemd timer に移行する例です。
移行前の crontab 設定:
30 2 * * * /opt/scripts/cleanup.sh >> /var/log/cleanup.log 2>&1
移行後の service ユニット(/etc/systemd/system/cleanup-daily.service):
[Unit]
Description=Daily cleanup script
[Service]
Type=oneshot
ExecStart=/opt/scripts/cleanup.sh
StandardOutput=journal
StandardError=journal
移行後の timer ユニット(/etc/systemd/system/cleanup-daily.timer):
[Unit]
Description=Run daily cleanup at 02:30
[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
[Install]
WantedBy=timers.target
移行手順は次の通りです。
- 上記の service / timer ユニットファイルを作成する
systemctl daemon-reloadで systemd に認識させるsystemctl enable --now cleanup-daily.timerで有効化・起動するsystemctl start cleanup-daily.serviceで手動テストする- テスト成功を確認してから crontab の該当行を削除する
移行すべきでないケース
以下のケースでは cron のまま運用する方が合理的です。
- チーム全員が cron に習熟しており、systemd timer の学習コストが見合わない場合
- 既存の運用手順書や監視設定が cron 前提で構築されている場合
- 1 行の crontab で済む単純なジョブを、2 ファイル(timer + service)に分ける必然性がない場合
8. 実践シナリオ
バックアップジョブ
毎日 3:00 に /opt/data を tar.gz で /backup に保存するジョブを、cron 版と systemd timer 版の両方で示します。
cron 版
実行コマンド:
# crontab -e
以下の行を追加します。
0 3 * * * /usr/bin/flock -n /tmp/backup-data.lock /usr/bin/tar czf /backup/data-$(date +\%Y\%m\%d).tar.gz -C /opt data >> /var/log/backup-data.log 2>&1
crontab 内の % は改行として解釈されるため、\% でエスケープする必要があります。flock で多重起動を防止し、ログをファイルにリダイレクトしています。
systemd timer 版
service ユニット(/etc/systemd/system/backup-data.service):
[Unit]
Description=Backup /opt/data
OnFailure=notify-failure@%n.service
[Service]
Type=oneshot
ExecStart=/usr/bin/tar czf /backup/data-%Y%m%d.tar.gz -C /opt data
StandardOutput=journal
StandardError=journal
timer ユニット(/etc/systemd/system/backup-data.timer):
[Unit]
Description=Run data backup at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
AccuracySec=5min
Persistent=true
[Install]
WantedBy=timers.target
timer 版では、ログは journald に自動記録され、排他制御は Type=oneshot で対応し、失敗時通知は OnFailure で設定しています。cron 版で必要だった個別の対策が systemd の標準機能で実現できています。
ディスク容量監視
ディスク使用率が 80% を超えた場合に警告ログを出力するスクリプトを、5 分ごとに実行する例です。
監視スクリプト(/opt/scripts/check-disk.sh):
#!/bin/bash
THRESHOLD=80
df -h --output=pcent,target | tail -n +2 | while read usage mount; do
usage_num=${usage%\%}
if [ "$usage_num" -ge "$THRESHOLD" ]; then
logger -p local0.warning "DISK WARNING: ${mount} is ${usage} full"
fi
done
timer ユニット(/etc/systemd/system/check-disk.timer):
[Unit]
Description=Check disk usage every 5 minutes
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=30s
[Install]
WantedBy=timers.target
OnBootSec=1min で OS 起動 1 分後に初回実行し、OnUnitActiveSec=5min で以降 5 分間隔で繰り返します。監視スクリプトのような高頻度ジョブでは AccuracySec を短く(30 秒)設定して、実行タイミングのばらつきを抑えています。
9. トラブルシューティング
cron ジョブが動かない
cron ジョブが期待通りに動作しない場合、最も多い原因は PATH の問題です。ログインシェルでは動作するコマンドでも、cron の環境では PATH が異なるため見つからないことがあります。
確認方法として、cron のログを確認します。
実行コマンド:
# tail -20 /var/log/cron
対処方法は 2 つあります。
- crontab の先頭に
PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbinを追加する - スクリプト内のコマンドをすべてフルパス(例:
/usr/bin/tar)で記述する
cron ジョブの出力が確認できない
ジョブは実行されているがログが残らない場合、出力のリダイレクトが設定されていない可能性があります。
対処方法として、crontab のコマンド末尾にリダイレクトを追加します。
>> /var/log/job-name.log 2>&1
MAILTO が設定されていてメールサーバーが動作していれば、ジョブの出力はメールで送信されます。しかし、メールサーバーが未設定の環境では出力が破棄されるため、ファイルへのリダイレクトを基本としてください。
cron.daily のスクリプトが実行されない
/etc/cron.daily/ に配置したスクリプトが実行されない場合、以下の 2 点を確認してください。
ファイル名に拡張子が含まれていないか:run-parts はファイル名にドット(.)を含むファイルを無視します。backup.sh ではなく backup という名前にしてください。
実行権限が付与されているか:実行権限がないファイルも run-parts の対象外です。
実行コマンド:
# chmod +x /etc/cron.daily/backup
対象として認識されているか確認するには、以下のコマンドを実行します。
実行コマンド:
# run-parts --test /etc/cron.daily
このコマンドの出力にファイルパスが表示されれば、実行対象として認識されています。
systemd timer が発火しない
timer ユニットファイルを配置したのに発火しない場合、以下の 2 点が原因であることが多いです。
daemon-reload を実行していない:ユニットファイルを新規作成・変更した場合は、systemd に再読み込みさせる必要があります。
実行コマンド:
# systemctl daemon-reload
timer を enable していない:enable しないと OS 再起動後に timer が起動しません。
実行コマンド:
# systemctl enable --now backup-daily.timer
timer の状態は systemctl status backup-daily.timer で確認できます。Active: inactive (dead) の場合は起動されていません。
timer の実行が指定時刻からずれる
systemd timer にはデフォルトで AccuracySec=1min が設定されており、指定時刻から最大 1 分のずれが発生します。また、RandomizedDelaySec が設定されている場合はさらに遅延が加わります。
正確な時刻に実行する必要がある場合は、AccuracySec=1s のように精度を高く設定します。ただし、精度を上げるとシステム負荷が増加するため、運用要件に応じて判断してください。
[Timer]
OnCalendar=*-*-* 03:00:00
AccuracySec=1s
RandomizedDelaySec=0
切り戻す場合は AccuracySec を元の値(例:1min や 5min)に戻し、systemctl daemon-reload を実行してください。
