長年稼働してきたcronジョブをsystemdタイマーへ移行する話は、「いつかやらなければ」と思いつつ後回しにされがちです。しかし2026年現在、主要ディストリビューションの多くがsystemd一本に統一されており、cronを並走させるよりタイマーへ移行するメリットが明確になってきました。本記事では、既存のcronジョブを止めずに段階移行する手順と、移行後の失敗検知・ジャーナル確認の方法を一通り説明します。
なぜ今、systemdタイマーへ移行するのか
cronは長らくLinux定期実行の標準的な仕組みとして機能してきました。しかし運用規模が大きくなると、いくつかの限界が見えてきます。まず、実行ログが標準ではジャーナルに統合されず、メール通知かファイルへの独自書き出しに頼らざるを得ない点があります。次に、ジョブが終わる前に次の実行が重なっても、デフォルトでは止まりません。cronはプロセス多重起動を防ぐ仕組みを持たないためです。
systemdタイマーはこれらの課題に対応しています。実行ログはjournalctlで一元管理されるため、他のサービスと同じ手順で調査できます。OnBootSecやOnUnitActiveSecといったオプションで起動タイミングを柔軟に制御でき、ConditionPathExistsなど条件付き実行も設定ファイルで完結します。また、サービスユニットにKillModeやTimeoutStopSecを指定することで、暴走プロセスの強制終了も組み込めます。
一方で移行にはコストもあります。crontabの1行で済んでいたものが、ユニットファイル2枚の管理に変わります。段階移行を選ぶ最大の理由は、cronとタイマーを一時的に並走させて動作を比較確認できる点です。
ユニットファイルの構成を理解する
systemdタイマーは「.timer」と「.service」の2ファイルで1セットです。タイマーが「いつ起動するか」を定義し、サービスが「何を実行するか」を定義します。
例として、毎日午前3時にバックアップスクリプトを実行していたcronジョブを想定します。
# 元のcrontabエントリ
0 3 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
これをsystemdで書き直すと、まずサービスユニットを作ります。ファイル名は/etc/systemd/system/backup.serviceとします。
[Unit]
Description=Daily backup script
After=network.target
[Service]
Type=oneshot
ExecStart=/opt/scripts/backup.sh
StandardOutput=journal
StandardError=journal
User=backup-user
続いてタイマーユニットを/etc/systemd/system/backup.timerとして作成します。
[Unit]
Description=Daily backup timer
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.target
Persistent=trueは重要な設定です。サーバーが午前3時に停止していた場合、次回起動時に前回の実行が漏れていれば即座に補完実行します。cronにはない挙動で、バックアップやレポート生成など「確実に1回は実行したい」ジョブに向いています。
段階移行の実施手順
移行は「cronを止めずにタイマーを並走させる→動作確認→cronを無効化」という3段階で進めます。
1. タイマーを有効化して並走させる
ユニットファイルを配置したら、デーモンをリロードしてタイマーを起動します。この時点ではまだcrontabはそのままです。
systemctl daemon-reload
systemctl enable --now backup.timer
タイマーが正しく登録されたか確認します。
systemctl list-timers --all | grep backup
出力にNEXTとLASTの列が表示されます。NEXTが翌朝3時になっていれば登録は成功です。LASTはまだ実行されていなければ「n/a」と表示されます。
2. 動作確認のために手動実行する
翌日の本番実行を待たずに動作を確かめるには、サービスユニットを直接起動します。
systemctl start backup.service
実行後すぐにステータスを確認します。
systemctl status backup.service
Active: inactive (dead)と表示され、その直前にSucceededまたはFailedのステータスが出ます。Type=oneshotの場合、正常終了後はinactiveに戻るのが正常です。これをエラーと混同しないよう注意してください。
3. 並走期間を設けてcronを無効化する
本番実行を1〜2週間確認できたら、crontabの該当行をコメントアウトします。削除ではなくコメントアウトにしておくと、切り戻し時に手間が減ります。
# 0 3 * * * /opt/scripts/backup.sh >> /var/log/backup.log 2>&1
並走期間中は二重実行が起きることがあります。スクリプトがべき等でない場合(二重バックアップでストレージを圧迫するなど)は、並走期間を短くするか、cronを先に止めてからタイマーの初回実行を手動で起動して確認する手順を取ります。
ジャーナルで実行ログを確認する
移行後のログ確認はすべてjournalctlで行います。cronのメール通知やファイルへの独自書き出しは不要になります。
特定のサービスのログを時系列で確認するには次のコマンドを使います。
journalctl -u backup.service
最新の実行だけを確認したい場合は-nオプションで行数を絞ります。
journalctl -u backup.service -n 50
日時指定で絞り込むこともできます。昨日の実行ログだけを見たい場合は以下のようにします。
journalctl -u backup.service --since yesterday --until today
ジャーナルにはスクリプトの標準出力と標準エラーがそのまま記録されます。スクリプト側でファイルにリダイレクトしていた部分は、ユニットファイルにStandardOutput=journalとStandardError=journalを指定することで同等に扱えます。ただし、スクリプト内部でさらにリダイレクトしている場合はその出力は引き続きファイルに書かれるため、両方を確認する習慣をつけておくと安全です。
失敗検知の仕組みを組み込む
systemdタイマーが優れている点のひとつは、失敗時のフックが標準で用意されていることです。OnFailureディレクティブを使うと、サービスが異常終了したときに別のサービスを呼び出せます。
通知用のサービスユニットを別途作成します。ここではbackup-failure-notify.serviceとします。
[Unit]
Description=Notify backup failure
[Service]
Type=oneshot
ExecStart=/usr/bin/systemd-cat -t backup-failure echo "backup.service failed"
実際の運用ではメール送信やSlack通知のスクリプトをExecStartに指定します。そしてbackup.serviceの[Unit]セクションに以下を追加します。
OnFailure=backup-failure-notify.service
これだけで、バックアップスクリプトが非ゼロ終了した際に自動で通知サービスが起動します。cronのメール通知はMTA設定が必要でしたが、こちらはsystemd内で完結します。
失敗が起きたかどうかを後から一覧で確認するには、systemctl --failedが便利です。
systemctl --failed
失敗状態のままになっているユニットが一覧で表示されます。調査後にリセットするにはsystemctl reset-failed backup.serviceを実行します。
切り戻し手順と移行後の注意点
何らかの問題が起きてcronへ戻す必要が生じた場合は、タイマーを止めてcrontabのコメントを外す手順で切り戻せます。
systemctl stop backup.timer
systemctl disable backup.timer
crontabを元に戻せば即座にcronの制御下に戻ります。ユニットファイル自体は削除しなくてもよく、切り戻し後に再検討する余地が生まれます。
移行後に現場でよく出る問題をいくつか挙げます。まず環境変数の扱いです。cronは/etc/environmentや各ユーザーの.bashrcの一部を読み込みますが、systemdサービスはそれらを読まないことが多く、スクリプトが依存している環境変数が未定義になる場合があります。ユニットファイルにEnvironmentFile=を指定するか、Environment=で明示的に設定する必要があります。
次に作業ディレクトリです。cronはデフォルトでホームディレクトリを起点にすることが多いですが、systemdサービスはWorkingDirectory=を指定しないと/が起点になります。スクリプト内で相対パスを使っている場合は要注意です。
最後にタイムゾーンの扱いです。OnCalendarの解釈はシステムのローカルタイムゾーンに従います。サーバーのタイムゾーンがUTCに設定されている環境では、cronのcrontabと時刻がずれることがあります。timedatectlでタイムゾーンを確認してから時刻設定を行うことを推奨します。
systemdタイマーへの移行は一度にすべてのcronジョブを切り替える必要はありません。影響範囲の小さいジョブから始めて、ジャーナル確認と失敗検知の運用に慣れたうえで順次移行していく方が現場のリスクを抑えられます。段階移行という選択肢があることが、systemdタイマーの導入を現実的にしている大きな要素のひとつです。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
PR・広告
[試して理解]Linuxのしくみ 増補改訂版(Amazon)
プロセス・権限・ファイルシステムなどLinux内部を図解で理解できる一冊。運用判断の勘所に。
※ Amazonのアソシエイトとして、当サイトは適格販売により収入を得ています。
