AIと一緒に一番シンドいECSヘルスチェックを通すまで

に公開

SREエンジニアの高見です。現在、AWS上のECS WEBサービスをTerraformで再整備するプロジェクトを担当しています。

これまで何度もECSの構築は経験してきましたが、一番骨が折れるのがECSタスクの起動です。特に、ターゲットグループのヘルスチェックをパスして、アプリケーションが安定稼働するまでの道のりは、まさに「鬼門」と言えるでしょう。
この記事では、AIとペアプロ(バイブコーディング)しながら、この困難な課題をどう乗り越えたかを紹介します。

簡単にアーキテクチャ紹介

今回扱った構成は、以下のようなごく一般的なWEBサービスのアーキテクチャです。

リクエストフロー: ELB -> ECS (Fargate) -> Django
デプロイ: GitHub Actionsからコンテナイメージをビルドし、ECRへプッシュ
セキュリティ: Checkovを利用して、インフラコードのセキュリティベストプラクティスを遵守

インフラ図の一部抜粋

よくあるハマりポイント

ECSのヘルスチェックが失敗する原因は多岐にわたりますが、代表的なものとして以下の様なものが挙げられます。

  • 1.ネットワークの疎通問題: セキュリティグループやNACLの設定ミスによる、ELB-ECS間の通信障害。ECRをプルしてくる際のVPCエンドポイント等も問題になりやすいですね。ただ、最近は、公式モジュールもあり、ネットワーク周りではコケづらくなりました。
  • 2.外部サービスとの接続問題: RDS (データベース) やElastiCache (Redis) などへの接続設定の不備。環境変数の設定等をミスっていたりすることも。
  • 3.タスク実行ロールの権限不足: ECRからのイメージプルや、Secrets Manager/SSMパラメータストアからの機密情報取得に必要なIAM権限の欠如。Checkovの指摘を丁寧にやっていくと設定が複雑になり、思わぬミスを誘発します。
  • 4.アプリケーション内部の問題: アプリケーション自体の起動失敗や、ヘルスチェック用エンドポイントの不備、通信プロトコルの不適合、セキュリティ要件に合わないなど。
  • 5.ヘルスチェックが早すぎる: アプリケーションが立ち上がる前に、ヘルスチェックをして失敗していることも…

今回実際にハマったポイント

今回、私たちはこれらの「よくあるハマりポイント」の複合的な問題に直面しました。

1. KMSの暗号化・復号化とタスク実行ロール権限の問題

Checkovの導入によりインフラのセキュリティを強化した結果、環境変数やDBの認証情報をKMSで暗号化して管理しました。その結果、タスク実行ロールに特定のKMSキーに対する復号化 (kms:Decrypt) 権限を明示的に付与する必要がありました。このIAMポリシーの僅かな設定漏れや、TerraformでのARNの指定漏れが原因で、ECSタスクが環境変数を読み込めず、コンテナが起動直後にクラッシュするという状況に陥りました。

2. Redisとの接続問題

Terraform側ではセキュリティを考慮してRedis (ElastiCache) へのTLS接続を必須 (transit_encryption_enabled = true) に設定していました。しかし、Djangoアプリケーション側がTLS接続に非対応だったため、接続が確立できずにいました。
さらに厄介だったのが、接続エラーのログが全く出力されなかったことです。これにより、何が原因でアプリケーションが応答しないのか特定するのに時間がかかってしまいました。

3. Django側でのHTTPS設定の問題

外部からELBへはHTTPSですが、ELBとECS間の通信はHTTPで行われる設定が一般的です。しかし、Django側でSECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')という設定が有効になっていました。
この結果、ELBからの単純にHTTP経由のヘルスチェックリクエストに対して、Djangoが適切に処理を行わず、ELBはこれを「異常」と判断してヘルスチェックが失敗していました。

4. Django側での ALLOWED_HOSTS の問題

セキュリティのため、DjangoのALLOWED_HOSTS設定には正規のドメイン名のみを許可していました。しかし、ELBのヘルスチェックは動的に変わるIPアドレスをホストに行われます。
当然、このIPアドレスは許可リストに含まれていないため、Djangoは403 Forbiddenを返し、ヘルスチェックが失敗していました。解決策を探すと、「ヘルスチェックのレスポンスコードとして403を許可する」といった暫定的な対応策が見つかりますが、これは根本的な解決とは言えません。他にも、ヘルスチェック用のnginxのサイドカーを立ち上げろとかも見つかり、皆苦労しているなと思ったポイントです。今回は苦心の末、ASGI側でヘルスチェック用のミドルウェアを噛ませる方法を取りました。

罠が多すぎて、1つ1つ潰すのは大変

このように、実際に発生していた問題は1つではなく、複数の要因が絡み合っていました。また、ネットワーク構成、環境変数、権限、Django設定などインフラからバックエンドコードまで可能性が多岐にわたるため、調査だけで一苦労です。こういう状況で、自分でデバッグするとかなり時間がかかる一方で、ただエラーログをAIに見せて「調査して修正せよ」と指示するだけでは、同じ場所をぐるぐる回る堂々巡りになったり、セキュリティがガバガバになったり、余計にどツボにハマったりもします。そこで、今回はAIと共に、より戦略的に問題解決に取り組む手法を試しました。

結果として、セキュリティや設定の妥協をせず、かつ、体感値で通常の3倍のスピードで問題を解消できたと感じています。見せてもらおうか…最新AIのデバッグ性能とやらをッ!

今回改めて学んだ、AIとの上手な付き合い方

AIとの協業で、以下の5つのポイントが特に重要だと再認識しました。

1. 可能性を上から順に潰していく

まずはネットワークなど、レイヤーの低い部分から可能性を排除していきます。セキュリティグループや、ポート番号等の可能性を潰したら、「ネットワークが原因ではないことが確定した」と明確に伝え、AIの思考のスコープを狭めてあげます。これにより、別のAIエージェントに作業を引き継ぐ際もスムーズになります。

2. 状況確認と修正計画を緻密に行う

エラーを見てすぐ実装に入る・AIに実装させるのはNGです。まずは、状況を確認しましょう

要約させる: まずはログを分析させ、「何が問題で、どこに原因がありそうか」の要点をまとめさせ、妥当かどうかを判断します。
ベストプラクティスを調査させる: ALLOWED_HOSTS のような複雑な問題は、実装に入る前に「Djangoにおけるヘルスチェックのベストプラクティス」を調査させます。これを怠ると、AIは「403を許可すればヘルスチェックは通ります」→「Terraformを修正してコミットしておきました」といった安易で不適切な解決策を提案・実行してくることがあります。

3. 複雑すぎる提案は一度立ち止まる

AIがインフラ構成をガラリと変えるような、大掛かりで複雑な解消法を提案し始めたら、それは危険信号です。そのアプローチは間違っている可能性が高いと考え、一度提案を却下しましょう。
そして、「その仮説は一旦捨てて、別の可能性を考慮して概要を教えて」と指示し、思考をリセットさせることが有効です。

4. 適切な情報を渡し、ログを出力させるコードを書かせる

調査が行き詰まったり、AIが的外れな提案を繰り返したりする時は、情報不足が原因かもしれません。

メタ質問を投げかける: 「原因を特定するのに、現状のログだけで不十分と判断した場合は、どの様な情報が追加で必要かを記載せよ」「一度立ち戻り、原因の仮定は確信度高く推察していたか再考察せよ」などとAIに問いかけます。
ログ出力を強化させる: 不足していると回答が来たら、必要なログの場所を探させたり、Djangoのコードを修正して詳細なログを出力させるコードをAI自身に書かせたりします。

5. にっちもさっちもいかない時は、AIエージェントやモデルを変える

どうしても解決の糸口が見えない場合は、環境を変えてみるのが一番です。

記憶をリセット: 同じAIエージェントでも、チャット履歴をクリアして新しいセッションで始めると、過去の誤った仮説に引っ張られずに済みます。
別のモデルを試す: 可能であれば、全く別のAIモデル(例: Claude -> Codex など)を使ってみます。驚くほどあっさりと、一瞬で正解にたどり着くことがあります。

まとめ

2025年現在、AIは非常に賢くなりましたが、それでもまだ人間の思考通りに完璧に動いてくれるわけではありません。
複雑な問題に対しては、人間がある程度の戦略を立て、問題を切り分け、AIをナビゲートしてあげる方が、結果として解決までのスピードはまだまだ速いと感じます。

今後、AIはさらにどう進化していくのでしょうか。楽しみです。

WiseVine Tech Blog

Discussion