• トップ
  • ブログ一覧
  • CloudRunのネットワークエラーに遭遇
  • CloudRunのネットワークエラーに遭遇

    はじめに

    私たちのチームでは、長年稼働してきた巨大なモノリシックシステムを段階的にリプレースしています。
    Next.js(App Router構成)を使ったフロントと、GraphQL APIを備えた新しいバックエンドを少しずつCloud Runへ移行中です。

    LB(ロードバランサ)でパスを切り分け、旧システム(Compute Engine上)と新システム(Cloud Run上)を共存させる形で運用しています。
    この段階的リプレースは順調に見えましたが、ある日、リリースのたびに大量のネットワークエラーが発生するようになりました

    発生したエラー

    エラーの内容はこのようなものです

    [Network e]: TypeError: fetch failed
    [Network e]: Error: {"message":"Upstream returned 504. body={\"code\":504,\"message\":\"upstream request timeout\"}"}

    新しいリビジョンをデプロイした直後の15分ほどだけ大量発生。
    時間が経つと収まる——でも、リリースのたびにユーザー影響が出る。
    「これは絶対に潰さなければ」とチーム全員で調査が始まりました。

    再現と原因の手がかり

    ローカルではもちろん再現しません。
    Cloud Runのリビジョン切り替え時にしか起きないため、実際にCloud環境+負荷付きで検証する必要がありました。

    ApatchBenchで負荷をかけつつ、リビジョンを切り替えてみると——見事に再現。
    モニタリング指標を追うと、同時期にCloud NATの接続エラーが記録されていました。

    これがすべての鍵でした。

    Cloud RunのVPC接続の仕組みを理解する

    Cloud RunからVPC(内部ネットワーク)に出ていく経路には、実は2つの方法があります。

    🔹 Direct VPC egress(推奨)

    Cloud Runのインスタンス自身にVPCネットワークインタフェースがつき、直接VPCを経由して通信します。
    余計な中継がなく、低遅延・高スループット・追加コストなしが魅力。
    通信の種類を

    • private-ranges-only(プライベート IP へのリクエストのみを VPC にルーティングする)
    • all-traffic(すべてのトラフィックを VPC にルーティングする)
      から選べます。

    🔹 Serverless VPC Access コネクタ

    一方で古くからある方式がこれ。
    Cloud Run → VPCの間に専用の中継VMを立てる構成です。
    運用や費用は増えますが、IP枯渇を避けたいなどの特殊なケースではまだ使われます。私たちのプロジェクトでも以前は使用していました。

    NATにすべてが集中していた

    私たちのAPIサービスは外部APIにもアクセスしていたため、Direct VPC egressをall-traffic設定で運用していました。
    つまり、あらゆる通信がCloud NATを経由していました。

    リリース直後、同時に大量のインスタンスが立ち上がり、外部APIやDBにアクセスしようとします。
    NATゲートウェイの接続上限に達すると、新しい通信はドロップされ、結果的にfetch failed504が返ってくる。
    これがエラーの正体でした。

    NAT負荷を減らすための工夫

    まずはDB接続を見直しました。
    Cloud SQLを利用していたため、接続方式を「ソケット」から「ホスト(Private IP)」に変更。
    Public経由ではなくVPC内部のPrivate IPでつなぐことで、NATを経由しない通信にできました。

    補足:
    NATを回避できるかどうかは「socketかhost」ではなく「宛先がPrivate IPかPublic IPか」で決まります。
    今回は宛先をPrivate IPに変えたことで、NAT負荷を減らすことができました。

    フロントエンド側でも同様に

    フロント(Next.js)も同じようにall-traffic設定でした。
    ここをprivate-ranges-onlyに切り替えてNAT負荷を軽くしようとしましたが、問題発生。

    ページがエラーになり、ヘルスチェックも通らない
    原因はアプリケーション固有問題で、キャッシュ処理を行うために独自作成したプロキシを通すのに外部URL(Public)にアクセスしていたため、
    private-ranges-onlyではその通信がうまく通らなくなっていたのです。

    自己参照プロキシで突破

    ここで登場したのが自己参照プロキシというアイデアです。

    外部URLではなく自分自身(127.0.0.1)に向けてリクエストを送るようにしました。
    これにより、外部通信がなくなりprivate-ranges-onlyでも正常稼働。

    効果と安定化

    この対応により、

    • NAT接続エラー消失
    • リビジョン切り替え時のfetch failedゼロ
    • デプロイ時の安定性向上を実現できました。

    現在では最小インスタンスを数台常時稼働させた状態でも、スムーズにリビジョンを切り替えられています。

    今後に向けて

    プロジェクト全体も順調に進み、アクセス数も増えています。
    APIは他アプリや外部連携からも利用されるようになり、以前のように「メンテナンスモードで止めてリリース」することは難しくなりました。

    これからは、GraphQLスキーマも破壊的変更を避け、deprecatedフィールドを活用して徐々に移行していくフェーズです。
    システム全体がゼロダウンタイム(No-downtime)で継続的に稼働することが当たり前になる世界を目指しています。

    まとめ

    Cloud Runは便利でスケーラブルですが、裏側のネットワーク設計を甘く見ると意外な落とし穴があります。

    • Direct VPC egress と NAT の関係を理解すること
    • Private IP経由で接続できるものは極力そうすること
    • 自己参照やプロキシで無駄な外部通信を減らすこと

    これらを意識するだけで、スケール時の安定性が大きく変わります。

    「CloudRunのネットワークエラーに遭遇」した経験は、今となってはチームにとって最高の学びになりました。

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    けったん(エンジニア)
    けったん(エンジニア)
    Show more...

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background