はじめに
Status Desk は通常、小さなキャッシュを毎分更新します。しかし、見慣れないアップロードプログラムも内部コレクターに合成の練習用リクエストを送っています。停止すると改善したように見えても、また戻ってきます。通常の状態更新を維持しながら、繰り返し起動する設定を取り除きましょう。
必要なのは基本的なターミナル操作だけです。Status Server は対象コンテナ内の許可された管理者シェルで、開始ディレクトリは /srv/status です。Status Desk はコレクターの実際のカウンターを表示します。両コンテナは練習用インスタンスのカーネルを共有します。データとリクエストは無害です。この実験は cron による再起動を扱い、本番ホストの包括的な調査ではありません。
戻ってくるプログラムを観察する
このステップでは、動作中のアップロードプログラムを停止し、1 つのインスタンスを終了しても原因が残ることを確認します。
Status Desk を開きます。refreshes は成功したキャッシュ更新リクエスト数で、毎分増えるはずです。uploads は不要な練習用リクエスト数で、通常は 5 秒ごとに 1 件増えます。修復後も過去の件数は残ります。ページを再読み込みして最新値を取得してください。
Status Server に切り替えます。プロセスとは実行中のプログラムです。PID はそのインスタンスを識別し、パスと引数は実行内容を示します。ps はプロセス一覧を表示します。-e はすべてを選び、-o は表示列を指定します。ここでは PID、親 PID(PPID)、引数付きの完全なコマンドです。
ps -eo pid,ppid,args
/usr/bin/python3 /opt/status/uploader.py upload を探します。Python はインタープリター、/opt/status/uploader.py はプログラムファイル、upload は練習用の動作を選ぶ引数です。近くの flock プロセスはロックを保持し、cron が複数のコピーを同時に作らないようにします。キャッシュ更新プログラムは変更しません。
シグナルはプロセスへの要求です。TERM は通常の終了を要求します。次の pkill は -f でコマンド行全体を選びます。引用符内の ^ と $ は先頭と末尾を指定するため、親や現在のシェルではなく、この Python ワーカーだけに一致します。1 回実行してください。
pkill -TERM -f '^/usr/bin/python3 /opt/status/uploader.py upload$'
何も表示されなくても正常です。一致するプロセスがなかった場合は、すべての Python を対象に広げず、もう一度一覧を確認します。終了まで 1 秒待ち、再表示します。
sleep 1
ps -eo pid,ppid,args
Python のアップロードプロセスが消えているはずです。チェックポイントは元のインスタンスの終了を確認しますが、ホストの問題がすべて解決したという意味ではありません。
sleep は指定した秒数待機します。少なくとも 1 回の実際の分境界をまたぐよう、80 秒待ってから一覧を表示します。
sleep 80
ps -eo pid,ppid,args
同じパスと upload 引数が別の PID で戻るはずです。親プロセスの連鎖には、スケジューラのジョブ起動役である CRON が含まれます。新しい PID は新しい実行を表し、別の元ジョブになったわけではありません。環境の負荷で起動が遅れる場合は、さらに 20 秒待って確認します。Status Desk を再読み込みするとアップロードが再開し、正規の更新も続きます。何がこのプログラムを起動するのか調べる必要があります。
繰り返し起動する設定を見つけて無効化する
このステップでは、戻ってきたプロセスと特定のスケジュールを結び付け、正規のジョブを残してその項目だけを無効化します。
Cron はデーモン、つまりバックグラウンドで動作して予定されたコマンドを開始するサービスです。ユーザー crontab には 1 つのアカウントのジョブを保存します。このターミナルは練習用コンテナ内の root なので、crontab -l は対象アカウントの設定を表示します。プラットフォームのアカウントには影響しません。
crontab -l
次の内容が表示されます。
* * * * * /usr/bin/flock -n /run/uploader.lock /usr/bin/python3 /opt/status/uploader.py upload
最初の 5 フィールドは分、時、日、月、曜日です。* はすべての値を意味し、* * * * * は毎分実行します。残りはコマンドです。flock -n は待機せずロックを取得し、別のアップロードプログラムが保持していれば重複した呼び出しを終了します。実行対象は停止したプロセスと一致しています。
システムの設定は /etc/cron.d/ にもあります。ls はファイル一覧、cat は短いファイルの内容を表示します。ディレクトリ後の * は中のファイルに展開されます。
ls /etc/cron.d
cat /etc/cron.d/*
status-cache ファイルには次の内容があります。
* * * * * root /usr/bin/python3 /opt/status/cache-refresh.py refresh
ユーザー crontab と異なり、システムの cron ファイルには 5 つの時刻フィールドとコマンドの間にアカウント欄があります。ここでは root です。この許可されたコマンドが Status Desk を更新します。時刻が似ているだけでは未承認とは判断できません。パッケージが用意した他の保守項目は残して構いません。
安全に編集するため、まず現在のユーザー設定を作業用テキストにコピーします。> は一覧をファイルに書き込み、以前のコピーがあれば置き換えます。編集前に 1 回だけ実行してください。繰り返すと編集中の内容を上書きします。
crontab -l > /srv/status/root.cron
nano はテキストエディターです。アップロードの行頭に # を追加します。Cron は # で始まるコメント行を無視します。復元できるよう本文を残し、他の項目は変えません。
nano /srv/status/root.cron
矢印キーで行頭へ移動し、# を入力します。Ctrl+O、Enter で保存し、Ctrl+X で終了します。編集したファイルのパスを crontab に渡して登録します。
crontab /srv/status/root.cron
crontab -l
アップロード行が # で始まることを確認します。Cron は変更を自動で再読み込みするので再起動は不要です。作業コピーにコメントを付けるだけでは足りず、登録する必要があります。別の行を編集した場合は、下書きを開いて復元し、再登録します。スケジュールを削除しても実行中のプロセスは終了しないため、現在のアップロードプログラムはまだ動いている場合があります。
実行中のコピーを終了して復旧を確認する
このステップでは、除去を完了し、完全な実行間隔にわたって不要な活動と業務機能を比較します。
同じ厳密なパターンで現在の Python アップロードプロセスを停止します。
pkill -TERM -f '^/usr/bin/python3 /opt/status/uploader.py upload$'
すでに存在しない場合、一致なしの終了は想定どおりなので続行します。終了まで 1 秒待ちます。
sleep 1
curl はネットワークリクエストを送信します。-sS は進行表示を隠し、エラーを表示します。この URL は Status Server から到達できる内部コレクターのコンテナ名を指します。/state は現在の件数と最新リクエストの Unix タイムスタンプを返します。
curl -sS http://collector:8080/state
uploads、refreshes、last_refresh を確認し、実際の cron が動くのを待ちます。
sleep 80
curl -sS http://collector:8080/state
uploads は変わらず、refreshes と last_refresh は増える必要があります。Status Desk を再読み込みしても同じ事実を確認できます。過去のアップロードは証拠として残ります。カウンターの消去は履歴を隠すだけで、再起動を解決しません。
プロセス一覧をもう一度表示します。
ps -eo pid,ppid,args
cron -f は残っているはずです。-f はこのコンテナのデーモンをフォアグラウンドに保ちます。アップロードプログラムは消えたままである必要があります。チェックポイントは別途 80 秒観察するため、採点には約 90 秒かかります。設定と稼働状態を読み取るだけです。
アップロードが増えたら、cron の 2 つの場所と、コメント化したユーザー crontab の登録を確認します。更新が止まったら、正規の status-cache 項目を復元します。症状を隠すために cron を停止したり、全設定を削除したりしてはいけません。状態サービスに必要だからです。この修復が取り除くのは実演した cron の仕組みであり、実際のホストに他の永続化がないという証明ではありません。
まとめ
プロセスのインスタンスと起動元を区別し、親プロセスをたどって cron を発見しました。ユーザーとシステムの設定を確認し、不要な起動設定だけを無効化して、新しいアップロードがない 1 分間も実際の業務更新が続くことを確認しました。



