Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】The configuration we changed in June arrived one pod at a time in August

2026年09月19日に「Dev.to」が公開したITニュース「The configuration we changed in June arrived one pod at a time in August」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

システム設定(ConfigMap)の変更が一部のPodに即座に適用されず、古い設定が残りメールの重複送信が発生した。デプロイメントが設定変更を検知せずPodが自動更新されなかったため。設定と実行状態の乖離を防ぐため、設定のハッシュ値をデプロイメントに含め、変更時にPodが自動更新されるよう改善した。

ITニュース解説

メールが顧客に二重に送信されるという問題が発生し、その原因を探る過程で、システム設定の変更が意図通りに反映されないという複雑な問題が明らかになった。この問題は、すぐに再現しない、特定の顧客に限定されない、といった特性を持つため、原因究明は困難を極めた。

システムの構成は、Kubernetesという技術を使って構築されていた。具体的には、24個の「Pod(ポッド)」と呼ばれる小さな実行単位があり、これらがメール送信の処理を担当していた。これらのPodは「Deployment(デプロイメント)」という管理単位によって一括で管理され、共通の「Image(イメージ)」から作られていた。そして、Podが動作するために必要な設定値は「ConfigMap(コンフィグマップ)」というオブジェクトにまとめられていた。問題発生時、24個のPodのうち6個が、なぜか古い設定値で動作し続けていることが判明した。

この問題の根本は、6月に行われたConfigMapの変更にあった。当時、処理が途中で停止してしまう「スタック」したジョブが長時間戻ってこないという問題が発生していたため、ジョブがワーカーに割り当てられてから、そのワーカーがジョブを「保持する(リースする)」期間を短縮することにした。具体的には、このリース時間を10分から2分に短縮した。この変更はConfigMap上で正しく行われ、チーム内での承認手続き(プルリクエストの承認)も完了し、すべての関係者が変更が完了したと認識していた。

しかし、ここに落とし穴があった。ConfigMapで設定された値がPodの内部でどのように使われるかが重要だった。このシステムでは、ConfigMapの値を「envFrom」という方法でPodの環境変数として取り込んでいた。コンテナ(Podの内部で動作するアプリケーション)は、起動する際に一度だけこれらの環境変数を読み込む。つまり、一度起動したコンテナは、その後ConfigMapの内容が変更されても、自身の環境変数を再読み込みしない。

さらに、ConfigMapを編集しても、それ自体が既存のPodを再起動させることはない。また、「Deployment(デプロイメント)」と呼ばれるPodの管理者が、Podの更新(「ロールアウト」と呼ぶ)を行うきっかけもなかった。なぜなら、デプロイメントが参照しているConfigMapの「名前」は変更されておらず、デプロイメント自身の仕様(定義ファイル)には何も変更が加えられていなかったからだ。デプロイメントは、参照するConfigMapの名前が変わらない限り、自身の管理するPodを更新する必要がないと判断する。このようにして、「私たちが編集したConfigMap」と「実際にPodが読み込んで実行しているConfigMapの値」との間に乖離が生じてしまったのである。

このサービスは普段あまりデプロイ(更新)が行われないため、6月にConfigMapを変更した後も、既存のPodはロールアウトされず、古い設定値(リース時間10分)で動作し続けていた。問題が顕在化したのは8月になってからだった。システムの基盤となる「ノードプール」(Podが動作する物理・仮想サーバーの集まり)がアップグレードされることになり、その過程でサーバーが数台ずつ順次停止(「ドレイン」と呼ぶ)し、新しいサーバーにPodが再配置・再起動された。

このノードプールのアップグレードがきっかけで、一部のPod(6個)は新しいサーバーで再起動する際に、更新されたConfigMap(リース時間2分)を読み込んで動作し始めた。しかし、残りのPod(18個)はアップグレードの影響を受けずにそのまま動作し続けたため、古い設定値(リース時間10分)で動き続けた。

この状況で、メール送信に時間がかかるケースが発生した。例えば、メールプロバイダーの応答が遅く、メール送信処理に3分かかった場合を考える。古いリース時間(10分)で動作しているPodがこのジョブを処理した場合、3分はリース期間内なので、ジョブは正常に完了する。しかし、新しいリース時間(2分)で動作しているPodが同じジョブを処理した場合、3分はリース期間(2分)を超過するため、Podはジョブを完了する前に「失敗」したと見なされ、そのジョブはキューに戻される。キューは、そのジョブを別のPodに再割り当てする。結果として、同じメールが別のPodによって再度送信され、顧客にはメールが二重に届くことになった。この事象は、ジョブを処理したPodがたまたまどちらの設定で動いていたかによって決まり、約9000回に1回という非常に低い頻度で発生した。

この教訓を受けて、再発防止のためにいくつかの対策が講じられた。まず、すべてのデプロイメントの定義に、そのデプロイメントが使用する設定(ConfigMapなど)の「ハッシュ値」を含む「アノテーション」(追加情報)を付与するようにした。ハッシュ値とは、設定内容から一意に生成される短い文字列で、設定内容が少しでも変わるとハッシュ値も変わる。ConfigMapの内容が編集されると、そのConfigMapを参照するデプロイメントのアノテーションに含まれるハッシュ値も自動的に更新される。デプロイメントは、自身の定義(Podテンプレート)に何らかの変更があったと認識するため、自動的にPodのロールアウト(更新)を開始するようになる。これにより、ConfigMapの変更がすぐにPodに反映される仕組みが構築された。

さらに、各サービスが実際にロードした設定のハッシュ値を「メトリック」(システムの状態を示す数値データ)として公開するようにした。そして、このメトリックを監視し、もし一つのサービス群(フリート)の中で、デプロイメントのロールアウトにかかる時間よりも長い期間にわたって、複数の異なるハッシュ値が報告された場合には、「アラート」を発生させる仕組みを導入した。これにより、設定の乖離が検知され次第、迅速に対応できるようになる。

この一連の出来事から得られた最も重要な教訓は、「私たちがシステムに適用した変更」と「実際にシステム上で実行されている変更」とは、全く異なる状態であるということだ。そして、これら二つの状態間の乖離を可視化し、監視する仕組みがこれまで存在しなかったことが、今回の問題の根本原因だった。システムエンジニアとして、設定変更が本当に意図通りに反映され、実行されているかを常に確認できる仕組みを持つことが極めて重要であると認識を改めることになった。

関連コンテンツ

関連IT用語

関連ITニュース