
cron・常駐プロセスの棚卸し手順|何が自動で動いているか把握する
引き継いだサーバーのログを眺めていて、毎晩3時ちょうどに何かが動いていることに気づく。 grepしてみると、たしかにスクリプトが走っている。でも、その一覧はどこにもない。誰が入れたのかも分からない。
こういうサーバー、けっこうありますよね。 動いているうちは誰も困らないので、一覧を作る理由がありませんでした。困るのは、引き継いだ人——つまり今のあなたです。
これは、前任者が不親切だったからではありません。cronの定義は仕組みとして何か所にも分かれて置けるので、意識して集めないかぎり一覧にならない、というだけの話です。この記事では、散らばった定義を集めて1枚にするところまでを、一緒にやっていきます。
結論:やることは3つです。①置き場所を4つ(個人・共通・タイマー・アプリ)と決めて、まず全部そのまま吐き出す、②常駐プロセスも同じ紙に並べる、③「止めていいか」の判断は今日はしない。棚卸しは、消すための作業ではなく、見える状態にするための作業です。まずは吐き出すだけで十分です。
なぜ「一覧がどこにもない」状態になるのか
定期実行は、1か所にまとまっていなくても動いてしまいます。ここが厄介なところです。
- 置ける場所が複数ある:ユーザーごとの設定、システム共通の設定ファイル、systemdのタイマー、アプリの中のスケジューラ。どれも正しいやり方で、どれか1つが正解というわけではありません。
- 追加した人がそれぞれ違う:サーバーを作った会社、前任者、外注さん、そして数年前の自分。それぞれが自分のやりやすい場所に足していけば、自然と散らばります。
- 消す機会がない:使わなくなった処理も、止めて誰かが困るのが怖いので、そのまま残ります。「たぶん要らないけど、たぶんで消せない」——この気持ちは、現場にいれば誰でも分かるはずです。
だから最初にやるのは、整理でも削除でもありません。いま何が動いているかを、そのまま書き出すことです。判断はそのあとで、いくらでもできます。
ステップ1:置き場所を4つに決めて、そのまま吐き出す

探し始めるとキリがないので、見る場所を4つに固定します。ここを見て出てこなければ、いったん「無い」として先へ進んで大丈夫です。
① 個人(ユーザーごとのcrontab)
いちばん見落とされるのが、自分以外のユーザーの設定です。crontab -l は自分の分しか出ません。
# 自分の分
crontab -l
# 全ユーザー分(root権限が必要です)
for u in $(cut -d: -f1 /etc/passwd); do
echo "===== $u"
crontab -l -u "$u" 2>/dev/null
done
www-data、apache、deploy、batch のような、ログインしないユーザーの下に入っていることがよくあります。名前に見覚えがなくても、そのまま書き出しておいてください。
② 共通(システム側の設定ファイル)
こちらはファイルとして置かれているので、中身を読めば分かります。
cat /etc/crontab
ls -l /etc/cron.d/ && cat /etc/cron.d/*
ls -l /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/
/etc/crontab と /etc/cron.d/ の行には、時刻のあとに実行ユーザー名の欄が入ります(個人のcrontabにはこの欄がありません)。誰の権限で動いているかは、ここで確認できます。
/etc/cron.daily/ などのディレクトリは、中に置かれたスクリプトが順に実行されます。ディストリビューションによっては anacron(サーバーが止まっていた分をあとから実行する仕組み)経由で動くので、実行時刻がぴったりでないこともあります。
③ タイマー(systemdのtimer)
最近の環境では、cronではなくsystemdのタイマーで動いているものが増えています。cronだけ見て「無い」と判断すると、ここを丸ごと見落とします。
# 有効・無効を含めて一覧表示
systemctl list-timers --all
# 気になるタイマーの中身を見る
systemctl cat <名前>.timer
systemctl cat <名前>.service
list-timers には、次回の実行予定と前回の実行時刻も出ます。前回が何か月も前で止まっているものが見つかることもあるので、あとで使えるように控えておいてください。
④ アプリ(アプリケーションの中のスケジューラ)
サーバー側のcronは1行だけなのに、その1行が実際には何十個もの処理を呼んでいる、というパターンです。cronの行を見ただけでは中身が分かりません。
- フレームワークのスケジューラ:cronから毎分1行だけ呼び出し、実際の振り分けはアプリ側の設定で行う作りです。Laravelなら
php artisan schedule:listのように、一覧を出すコマンドが用意されていることがあります。 - WordPressのWP-Cron:時刻ではなくページへのアクセスをきっかけに動く仕組みです。WP-CLIが入っていれば
wp cron event listで予定を確認できます。 - アプリ内のジョブキュー・ワーカー:常駐して待ち受けている側なので、次の「常駐プロセス」で拾います。
- 外から叩かれているもの:外部の監視サービスやSaaSが、決まった時刻にURLを呼びに来ている場合があります。サーバー側には何も定義がないので、アクセスログを「毎日同じ時刻・同じURL」で探すと見つかります。
ステップ2:常駐プロセスも同じ紙に並べる
定期実行と並んで「いつの間にか動いている」のが、常駐プロセスです。落ちても誰も気づかないまま、数日たって発覚することもあります。
# サービスとして動いているもの
systemctl list-units --type=service --state=running
# 起動してから長いもの順(古株ほど素性が分からないので上から見る)
ps -eo pid,user,etimes,cmd --sort=-etimes | head -40
# プロセス管理ツールを使っている場合
supervisorctl status
pm2 list
docker ps
ps の etimes は、そのプロセスが起動してからの経過秒数です。上から並べると、サーバーの起動時からずっと動いているものが先に出てきます。素性の分からない常駐は、たいていこのあたりにいます。
コマンドの行だけでは何をしているか分からないときは、実行ファイルのパスと作業ディレクトリをたどると手がかりになります。
ls -l /proc/<PID>/cwd # どのディレクトリで動いているか
ls -l /proc/<PID>/exe # 実体はどのファイルか
CPUやメモリの使われ方から追いかけたいときは、CPU使用率が高いときの原因プロセス特定手順の見方がそのまま使えます。
ステップ3:1枚の表にまとめる(そのまま使えるテンプレート)
集めた出力は、そのままでは読み返せません。1件1行の表に移します。埋まらない欄があっても、空欄のまま置いておくのがコツです。
| 名前 | 起動方法 | 実行タイミング | 実行ユーザー | 実体(パス) | ログ出力先 | 止まると困る人 | 最終実行 | 分類 |
|---|---|---|---|---|---|---|---|---|
| 売上集計 | 個人(batch) | 毎日 3:00 | batch | /opt/bin/uriage.sh | /var/log/batch/ | 経理 | 8/13 3:02 | 現役 |
| 一時ファイル削除 | 共通(cron.daily) | 毎日 | root | /etc/cron.daily/tmpclean | なし | — | 不明 | 不明 |
| ログ転送 | タイマー | 毎時 | root | logship.service | journal | 情シス | 8/14 1:00 | 現役 |
分類は、現役/不明/停止済みの3つだけにします。「要らない」という欄は作りません。判断を保留できる場所があると、無理に決めなくて済みます。
「止まると困る人」の欄が、あとでいちばん効きます。ここが埋まっているものは、監視や失敗通知をつける優先度が高い処理です。ここが空欄のまま残ったものが、次に調べる対象になります。
作った表は、サーバー構成の資料と同じ場所に置いておくと迷子になりません(サーバー構成情報を1枚にまとめる方法)。
「不明」をどう扱うか——止める判断は急がない
棚卸しをすると、必ず正体の分からないものが残ります。ここで慌てて消さないでください。止めて困るかどうかは、止めてみるまで分からない——そして、止めて困ったときの代償のほうが大きいからです。
判断材料になるのは、この3つです。
- 出力の最終更新日:出力先のファイルやテーブルが、いつ最後に更新されたか。数年前で止まっていれば、すでに実質動いていない可能性があります。
- 実行の記録:cronの実行ログ(環境により
/var/log/cronやjournalctl -u cron/journalctl -u crond)や、systemdタイマーの前回実行時刻。 - 誰かが見ているか:出力されたファイルやメールを、実際に使っている人がいるか。これは聞くのがいちばん早いです。
どうしても止めたいときは、いきなり削除せず、コメントアウトして日付と自分の名前を書き添え、しばらく様子を見るやり方が安全です。戻せる形にしておけば、判断の重さがぐっと減ります。作業の記録は変更管理台帳のつけ方の形で残しておくと、半年後の自分が助かります。
なお、この作業は本番サーバーの状態を確認するものです。参照するだけのコマンドが中心ですが、設定ファイルに手を入れる段階になったら、事前のバックアップと作業記録を忘れずに。実行結果や挙動は環境・ディストリビューション・バージョンによって変わるので、手元の環境で確認しながら進めてください。
棚卸しをすると、何が変わるか
一覧ができたからといって、その日のうちに楽になるわけではありません。効いてくるのは、少し先です。
- 障害のとき、原因の候補が絞れる:「この時間帯に動いているものは何か」を、その場で調べ直さずに答えられます。
- 失敗に気づける処理が増える:一覧があると、優先度の高いものから失敗通知をつけていけます(cronバッチの失敗に気づく仕組み)。
- サーバー移行のときに落とさない:移行の抜け漏れは、たいていこの「見えていなかった定期処理」で起きます。
- 引き継ぎで渡せるものが1つ増える:口頭で伝えていた内容が、紙1枚になります。
明日やること:まず吐き出して1ファイルに保存する
30分あれば、最初の一歩は終わります。
- サーバーに入って、上の①〜③のコマンドをそのまま実行する(読み取りだけです)。
- 出力を丸ごと1つのファイルに保存する。整形はしなくて構いません。日付をファイル名に入れておくと、次に取ったときの差分が見られます。
systemctl list-timers --allの前回実行時刻をざっと眺めて、止まっていそうなものに印をつける。- 常駐プロセスを
etimes順に並べて、上から10件だけ「これは何か」を書き添える。 - 表の形にするのは、翌日以降で大丈夫です。
全部を1日でやろうとしなくて大丈夫です。吐き出したファイルが1つあるだけで、次に何か起きたときの調べ物は確実に短くなります。
cron・常駐プロセス棚卸しチェックリスト
上から順に、確認できたものにチェックを入れてください。
- 自分以外のユーザーのcrontabも確認したか(
crontab -l -u) -
/etc/crontabと/etc/cron.d/の中身を見たか -
/etc/cron.hourlydailyweeklymonthlyの中を開いたか -
systemctl list-timers --allでタイマーを確認したか - アプリの中のスケジューラ(フレームワーク・WP-Cron等)を確認したか
- 外部サービスから定期的に叩かれていないか、アクセスログを見たか
- 常駐プロセスを起動時間の長い順に確認したか
- 1件ずつ「実行ユーザー」と「ログの出力先」を書き留めたか
- 「止まると困る人」の欄を埋めたか(空欄は次に調べる印として残す)
- 正体不明のものを、消さずに「不明」として置いておけたか
- 出力を1つのファイルにして、日付つきで保存したか
全部そろわなくても構いません。ひとつでも「これは何のために動いているか」が分かれば、その分だけサーバーは見通しがよくなっています。
よければ、こちらも
棚卸しの次にやると効くものを、順番に置いておきます。
- cronバッチの失敗に気づく仕組み|静かに止まるジョブを見逃さない:一覧ができたら、優先度の高いものから失敗通知をつけていくために。
- サーバー構成情報を1枚にまとめる方法:作った表の置き場所と、そろえておきたい項目。
- 引き継いだ初日にやること|作った人がいないシステムの読み解き方:棚卸しを、引き継ぎ全体のどこに置くか。
- 定期作業を手順化してチェックリストにする方法:人がやっている定期作業のほうも、同じやり方で見える化できます。

正体の分からないものを抱えたまま運用するのは、じわじわと疲れます。何か起きるたびに、まず「これは何だっけ」から始めなければならないからです。
その状態を作ったのはあなたではありません。でも、見える形に変えられるのはあなたです。今日ひとつ、crontab -l を打ってみるところから。それだけでも、このサーバーはさっきより少しだけ、あなたのものになっています。
ほかの実務ヒントは記事一覧からどうぞ。保守運用の小さな備えを、メールでも少しずつお届けしています。