Cloud Runでコンテナ起動時にDB接続がタイムアウトする問題を解決する
はじめに
Cloud Runでアプリケーションをデプロイした際、コンテナ起動後の最初のデータベースアクセスがタイムアウトしてしまうという問題に直面しました。この問題は、その後のアクセスでは発生しないため、特にコールドスタート時の挙動に起因している可能性が高いと考えられます。今回はこの問題の調査と、最終的な解決策についてご紹介します。
環境
今回の事象が発生した環境は以下の通りです。
- データベース: Compute Engine上に構築
- APIサーバー: Cloud Run上にGo言語で構築
- ネットワーク: Cloud RunとCompute Engine(データベース)間の通信にはDirect VPC Egressを使用
結論
先に結論からお伝えすると、ファイアウォールルールのソースフィルタにソースタグを使用するのをやめ、IPv4範囲を直接指定することで、タイムアウトが解消され、安定したDB接続が可能になりました。
調査と解決の経緯
問題は、Cloud Runコンテナが起動した直後の最初のリクエストが必ず失敗し、タイムアウトすることでした。一度コネクションが確立されると、その後の通信は問題なく行われるため、特に初期接続時に何らかの問題があることが示唆されました。リトライ処理でごまかすのは避けたいと思い、詳細なを開始しました。
初期調査:Pingによる接続テスト
まず、APIサーバーの起動時にDBコネクションを確立し、Pingを実行するように実装を修正しました。これにより、初期接続の成否をより具体的に把握できると考えたためです。
しかし、この変更後もすぐに問題が解決したわけではありません。Pingは1〜2回程度失敗した後にようやく成功するような状況でした。その結果、それまで数百ミリ秒だったコンテナの起動時間が、およそ4秒程度にまで延びてしまいました。単純にDBへの接続に時間がかかっていることが分かりました。
ネットワークの問題を特定
次に、Pingを実行している箇所に詳細なログを仕込み、同時にtcpdumpを使用してネットワークトラフィックをキャプチャしました。ログの出力タイミングとtcpdumpのキャプチャ内容を比較すると、Pingが成功したときにはtcpdumpにもパケットが記録されている一方で、失敗した際にはtcpdumpに何も出力されていないことが判明しました。この結果から、問題はアプリケーションレイヤーではなく、ネットワークレイヤーにある可能性が高いと判断しました。
ファイアウォール設定の変更
「もしかしてファイアウォールの設定に何かあるのでは?」という漠然とした疑念から、ファイアウォールルールを見直しました。これまで、ソースフィルタにはソースタグを使用していましたが、これをIPv4範囲に直接変更してみたところ、驚くべきことに問題は解消されました。
変更後、DBコネクションは失敗することなく、数百ミリ秒という速さでレスポンスが返ってくるようになりました。
なぜ解決したのか?
現時点では、なぜソースタグからIPv4範囲への変更で問題が解決したのか、その詳細な技術的背景までは調べ切れていません。しかし、Cloud Runのコールドスタート時にDirect VPC Egress経由でVPCネットワーク内のリソース(Compute Engine上のDB)にアクセスする際、ソースタグの解決に何らかの遅延や競合が発生していた可能性が考えられます。
もし同様の事象でお困りの方がいらっしゃいましたら、ファイアウォールルールのソースフィルタを見直してみることをお勧めします。
Discussion