Claude Code と進める Ingress から Gateway への移行 - エムスリーテックブログ

エムスリーテックブログ

エムスリー(m3)のエンジニア・開発メンバーによる技術ブログです

Claude Code と進める Ingress から Gateway への移行

AI・機械学習チームの苅野です。この記事はAI・機械学習チームブログリレー 9 日目の記事です。8 日目は高田さんによる DuckDB と Taskfile で作る EDA 環境の解説記事でした。

www.m3tech.blog

明日 4 月 10 日に劇場版名探偵コナン第 29 作がいよいよ公開されるので関連エピソードを復習しています。萩原刑事と松田刑事が登場した「揺れる警視庁 1200万人の人質」は映画でもおかしくないようなスケールなのでおすすめです。

さて、AIチームでは機械学習プロダクトの実行基盤としてGKE(Google Kubernetes Engine)を利用しており、外部からの HTTP トラフィックの受け口として Ingress リソースを使ってきました。しかし Kubernetes の次世代ルーティング API である Gateway API が GA となってしばらく経ち、チーム内の複数サービスで Ingress から Gateway API への移行を進めてきました。この記事では移行を 5 ステップに分けて解説するとともに、移行パターンを Claude Code の Skill として定義し 2 つ目以降のサービスでは Claude Code に作業を任せる形で進めた取り組みも紹介します。

一緒に花見した白鷺。本文とは関係ありません

なぜ Ingress から Gateway API に移行するのか

Ingress の課題

Ingress は長らく Kubernetes の外部トラフィック管理の標準でしたが、いくつかの課題がありました。

  • アノテーション依存: GKE 固有の機能(Cloud Armor、SSL ポリシーなど)をアノテーションで制御するため、設定が分散しやすい
  • 拡張性の制約: Ingress の仕様はシンプルな L7 ルーティングに限定されており、複雑なルーティング要件を表現しにくい
  • 責務の混在: Ingress リソース 1 つにインフラ設定とアプリケーションのルーティング設定が混在しがち

Kubernetes プロジェクトは Ingress の代わりに Gateway を使用することを推奨しており、Ingress は Kubernetes から取り除かれないものの今後変更も加えられません1

Gateway API とは

Gateway API は、Kubernetes コミュニティが策定した次世代のルーティング API です。従来の Ingress リソースの後継として設計されており、より表現力が高く、拡張性のある仕様になっています。

GKE では 2022 年に GA となり、Google Cloud としても GKE Ingress はメンテナンスモード2で Gateway API を推奨するルーティング方式として位置づけています。

Gateway API のメリット

Gateway API では、これらの課題が次のように解決されています。

  • ロール指向の設計: Gateway(インフラチームが管理)と HTTPRoute(アプリチームが管理)でリソースが分離されており、責務が明確
  • ポリシーアタッチメント: GCPBackendPolicy や HealthCheckPolicy といったポリシーリソースを Gateway にアタッチする形で設定でき、見通しが良い

GKE Ingress はメンテナンスモードで新機能が追加されない一方で、Gateway API は今後も活発に開発されて機能追加も行われていくことが予想されるため、Gateway への移行を決めました。

移行の全体像

リポジトリ構成

AI チームでは、Google Cloud インフラの定義(グローバル IP、証明書など)はインフラリポジトリ(Terraform)、Kubernetes マニフェスト(Ingress、Gateway、Service など)はアプリリポジトリで管理しています。移行作業はこの2つのリポジトリにまたがります。

アプリリポジトリは cookiecutter テンプレート(プロジェクトの雛形生成ツール)から生成されており、複数サービスで k8s マニフェストの構成がほぼ共通です(テンプレート管理には cruft を使っています)。そのため、1 つのサービスで移行パターンを確立できれば、他のサービスへの横展開が容易です。 このプラクティスについては別のブログ記事でも紹介しています。

移行の流れ

移行は次の5ステップで進めます。Ingress を残したまま Gateway を追加し、DNS で切り替えてから Ingress を削除するという流れです。

Step 1: Gateway リソース作成(インフラリポジトリ)
    ↓
Step 2: Gateway k8s リソース有効化(アプリリポジトリ / Ingress は残す)
    ↓  ← この間、両リソースが共存(トラフィックは DNS の向き先のみ)
Step 3: DNS を Gateway に切り替え(インフラリポジトリ)
    ↓
Step 4: Ingress リソース削除(アプリリポジトリ)
    ↓
Step 5: Ingress IP アドレス削除(インフラリポジトリ)

各ステップは独立した PR として作成し、前のステップが完了してから次に進みます。急いで一気に実施せず、各ステップで動作確認を挟みました。

Claude Code Skill への落とし込み

最初のサービス移行で手順を確立した後、この移行パターンを Claude Code の Skill として記録しました。

なぜ Skill に落とし込むのか

Claude Code では、プロンプト・参照ドキュメント・コマンド例などをまとめた「Skill」を定義できます。Skill を呼び出すと Claude がその知識を持った状態で作業を進めてくれます。今回のケースでは1サービスあたり5ステップ・複数リポジトリへの PR 作成が必要で、移行対象が複数サービスにわたります。手順を Skill に落とし込むことで、各サービスの設定値の違いを Claude が吸収しながら作業を進めてくれるため、繰り返し作業の品質と速度が向上します。

今回の移行では次のような内容を Skill に記録しました:

  • 5ステップの移行手順と各ステップで行うリポジトリ操作
  • 各ステップの確認コマンド(Gateway の PROGRAMMED 確認、バックエンドのヘルスチェックなど)
  • 過去の移行 PR 一覧(参考実装として参照できる)
  • 切り戻し手順

2つ目以降のサービス移行では、Skill を呼び出して「このサービスの Gateway 移行を進めて」と伝えるだけで、Claude が手順に沿って必要なコードを生成・確認してくれました。

ステップ1: Gateway 用リソースの作成(インフラリポジトリ)

Step 1

最初のステップでは、Terraform を使って Gateway に必要なインフラリソースを作成します。

作成するリソース

次のリソースを作成します。

  1. Gateway 用グローバル IP アドレス
  2. Certificate Manager 証明書(DNS 認証方式)
  3. Certificate Map(証明書と Gateway の紐付け)

Ingress では ManagedCertificate リソースで証明書を管理していましたが、Gateway API では Certificate Manager を使います。DNS 認証方式を採用しているため、証明書の検証用 DNS レコードを先に作成し、それに依存する形で証明書を作成しています。

ステップ2: Gateway k8s リソースの有効化(アプリリポジトリ)

Step 2

次に、アプリリポジトリ側で Gateway 関連の Kubernetes リソースを有効化します。この時点では Ingress はまだ削除しません。

有効化するリソース

  • Gateway
  • HTTPRoute
  • GCPGatewayPolicy
  • GCPBackendPolicy
  • HealthCheckPolicy
  • Service(Gateway 専用で新規作成)

なぜ Gateway 専用の Service を作るのか

一見すると、既存の Ingress 用 Service をそのまま Gateway の HTTPRoute に指定すれば Service の二重管理を避けられるように思えます。しかし GKE のドキュメントには次のように明記されており、これはサポート外の構成です。

GKE Gateway does not support referencing a Service that is also referenced by a GKE Ingress.

公式ドキュメントで技術的な理由は明示されていませんが、Ingress・Gateway どちらのコントローラーも参照する Service の NEG(Network Endpoint Group)を定期的に SYNC するため、互いの操作が干渉するのが原因と考えられます。実際、検証中に同一 Service を両コントローラーから参照したところ、定期的にレイテンシが悪化する現象を確認しました。Gateway 用には必ず別 Service を作成してください。

疎通確認

リソースの作成後は Gateway の IP アドレスに直接リクエストを送って、疎通確認をします。

$ curl --resolve "myapp.com:443:$(gcloud compute addresses describe myapp-gateway \
    --project=myproject --global --format='get(address)')" \
    https://myapp.com/health

このコマンドで Gateway の IP アドレスに直接 HTTPS リクエストを送り、200 が返ることを確認します。この時点では DNS はまだ Ingress を向いているので、--resolve オプションで Gateway の IP を指定してアクセスします。

ステップ3: DNS の切り替え(インフラリポジトリ)

Step 3

Gateway が正常に動作していることを確認できたら、DNS レコードを Ingress IP から Gateway IP に切り替えます。

切り替え作業

次の3点を確認してから DNS を切り替えます。

  1. Gateway が PROGRAMMED 状態であること
  2. バックエンドがすべて HEALTHY であること
  3. Gateway IP への直接アクセスで 200 が返ること

Terraform で DNS レコードの参照先を変更します。具体的には、google_dns_record_setrrdatas を Ingress 用 IP から Gateway 用 IP に切り替えるだけです。

切り替え後の確認

Terraform apply の実行後、DNS が正しく Gateway IP を返すことを確認します。

# DNS 解決結果が Gateway IP と一致すること
$ dig myapp.com +short
x.x.x.x

DNS が正しく切り替わっていることを確認したら、実際にHTTPリクエストを送って疎通確認をします。

# 疎通確認
$ curl -s https://myapp.com/health -o /dev/null -w "HTTP Status: %{http_code}\n"
HTTP Status: 200

この時点では Ingress と Gateway の両方が動作しています。DNS が Gateway を向いているので、通常のトラフィックは Gateway 経由になりますが、万が一の場合は DNS を戻すだけで Ingress に切り戻せます。

ステップ4: Ingress リソースの削除(アプリリポジトリ)

Step 4

DNS 切り替え後、Ingress 側にトラフィックが来ていないことを Log Analytics で確認できたら、Ingress リソースを削除します。

トラフィックの確認

Log Analytics を使って、Ingress の forwarding rule にリクエストが来ていないことを確認します。

WITH
  scope_query AS (
    SELECT
      http_request,
      timestamp,
      resource
    FROM
      `myproject.global._Default._Default`
    WHERE
      timestamp >= "2026-04-01T00:00:00Z"
      AND http_request.request_url LIKE '%myapp.com%'
  )
SELECT
  STRING(resource.labels.forwarding_rule_name) AS forwarding_rule,
  COUNT(*) AS request_count
FROM
  scope_query
GROUP BY
  forwarding_rule
ORDER BY
  request_count DESC

結果で gkegw1-...(Gateway)にトラフィックが集中し、k8s2-...(Ingress)がゼロまたは不正スキャンのみであれば安全に削除できます。

削除対象

削除対象のリソースは次のとおりです。

  • Ingress リソース(Ingress、および FrontendConfig・BackendConfig・ManagedCertificate などの関連リソース)
  • Service に付与していた Ingress 用アノテーション(beta.cloud.google.com/backend-config など)

ステップ5: Ingress IP アドレスの削除(インフラリポジトリ)

Step 5

最後に、不要になった Ingress 用のグローバル IP アドレスを Terraform から削除します。削除前に以下を確認します。

  • IP アドレスの status が RESERVED(未使用)になっていること
  • users フィールドが空であること(どのリソースにも紐付いていないこと)

これで移行は完了です。

まとめ

GKE Ingress から Gateway API への移行は、5つのステップに分けて進めることでダウンタイムを最小限に抑えて移行を実施できます。

  1. Gateway リソースの作成(Terraform)
  2. Gateway k8s リソースの有効化(Ingress と並行稼働)
  3. DNS の切り替え
  4. Ingress リソースの削除
  5. Ingress IP の削除

AI チームではこのパターンで複数サービスの移行を完了しており、再現性の高い手順として確立しています。

We are hiring!

エムスリーでは、ML プロダクトの基盤も支えるエンジニアを募集しています。GKE や Terraform を使ったクラウドインフラの設計・運用に加え、Claude Code の Skill を活用した AI による開発効率化にも取り組んでいます。興味がある方、ぜひお気軽にご連絡ください。

エンジニア採用ページはこちら

jobs.m3.com

カジュアル面談もお気軽にどうぞ

jobs.m3.com

インターンも常時募集しています

open.talentio.com