メインコンテンツまでスキップ

主要な Ingress の比較

· 約8分

今回は k8s クラスタでよく使われる ingress コンポーネントを比較してみます。ingress はクラスタにおける HTTP と HTTPS トラフィックのエントリーポイントの役割を担っています。Ingress はトラフィックを Kubernetes クラスタ内のさまざまな Service にルーティングでき、ロードバランシングとトラフィック制御の機能を実現します。

なぜ Ingress に注目するのか

クラスタ内のサービスは、デフォルトではクラスタ内部からしかアクセスできません。サービスを外部に公開する最も手軽な方法は NodePort または LoadBalancer タイプの Service ですが、どちらにも制約があります。NodePort はポート範囲が限られ、ドメインやパスの管理がしづらい。LoadBalancer はサービスを 1 つ公開するごとにロードバランサーを 1 台占有し、クラウド上では実費がかかることを意味します。

Ingress が解決するのはまさにこの問題です。統一されたエントリーポイントですべての外部 HTTP/HTTPS トラフィックを受け止め、ドメインとパスに応じてクラスタ内の各 Service へ振り分けます。どの Ingress コントローラーを選ぶかは、その後のルーティング設定、TLS 管理、L4 公開といった日常運用の体験を直接左右するため、選定段階で主要な選択肢を並べて比較する価値があります。

動作の仕組み

Ingress の動作原理は、HTTP と HTTPS のリクエストを Service にマッピングすることで実現されています。Kubernetes において、Service はトラフィックを Pod にルーティングするためのリソースオブジェクトです。Ingress が外部からの HTTP または HTTPS リクエストを受け取ると、リクエスト内のホスト名とパス情報をもとに Ingress ルールとマッチングを行い、リクエストを対応する Service にルーティングします。

ここに混同しやすいポイントがあります。Ingress リソース自体は宣言的なルーティングルールにすぎず、書いただけでは自動的に有効にはなりません。実際に働くのは Ingress コントローラーです。コントローラーは Pod としてクラスタ内で動作し、API Server 上の Ingress、Service、Endpoint などのリソース変更を継続的に watch し、これらのルールを自身の下層プロキシ(Nginx、Envoy、Traefik 内蔵のプロキシなど)の設定に変換し、ホットリロードで反映します。つまり:

  1. Ingress リソース:「どのドメインのどのパスをどの Service に転送するか」を宣言する。
  2. Ingress コントローラー:ルールの変更を監視し、プロキシ設定を生成してロードする。
  3. 下層プロキシ:実際に外部リクエストを受け取り、転送を行う。

リクエストのマッチング時、コントローラーはまず Host でバーチャルホストをマッチングし、次に Path でルーティングルールをマッチングして、最後にリクエストを対応する Service の背後にある Pod へ転送します。TLS 証明書は通常 Secret の形で Ingress ルールにマウントされ、コントローラーがエントリーポイントで TLS 終端(オフロード)を行います。

主要な Ingress コントローラー

Ingress を使うには、まず Ingress コントローラーをインストールする必要があります。Kubernetes はデフォルトの Ingress コントローラーを提供していませんが、サードパーティ製の Ingress コントローラーが数多く存在し、選択できます。

主要な選択肢のトレードオフを簡単に説明します。

  1. Nginx Ingress Controller:コミュニティで最もよく使われる選択肢。Nginx をリバースプロキシとして使い、ドキュメントと事例が豊富で、多くの設定を annotation で行います。デフォルトの選択肢として適しています。
  2. Traefik:Dashboard が付属し、設定が動的に反映されます。Nginx のような reload が不要で、Let's Encrypt と連携した証明書の自動発行も扱いやすいです。
  3. Istio Ingress Gateway:クラスタがすでに Istio サービスメッシュを導入しているなら、その Gateway をエントリーポイントにすることで、メッシュ内のトラフィック制御(カナリアリリース、サーキットブレーカー、テレメトリ)と連携できます。ただしエントリーポイントのためだけに Istio を導入するのは重すぎます。
  4. その他、HAProxy や Kong などは、それぞれ性能や API ゲートウェイ機能に強みがあります。

選定の考え方はシンプルでかまいません。特別な要件がなければ Nginx Ingress を使う。動的設定やよりモダンな運用体験が欲しければ Traefik を検討する。すでにサービスメッシュを使っているなら、その流れでメッシュ付属の Gateway を使う。

L4 サービスの公開

ところで、HTTP の L7 プロトコルだけでなく、MySQL、Redis、MongoDB などの L4 プロトコルベースのサービスも、クラスタ外部に公開してアクセスできるようにしたい場面はよくあります。

しかし Kubernetes の Ingress 仕様自体は HTTP と HTTPS プロトコルしかサポートしていないため、デフォルトの Ingress コントローラーもこの 2 つのプロトコルしかサポートしていません。ただし、一部のサードパーティ Ingress コントローラーは拡張によって TCP と UDP プロトコルの公開をサポートできます。

  1. Traefik:Traefik は TCP プロトコルの公開をサポートしており、Ingress ルールで traefik.tcp.routerstraefik.tcp.services を指定することで TCP サービスとルーティングを設定できます。
  2. Istio:Istio はサービスメッシュフレームワークで、その Ingress Gateway コンポーネントを通じて TCP プロトコルの公開をサポートできます。Ingress Gateway 内で VirtualService を定義することで、TCP サービスとルーティングを設定できます。

補足すると、Nginx Ingress Controller も TCP/UDP サービスを公開できます。やり方は、tcp-servicesudp-services という 2 つの ConfigMap をメンテナンスし、「外部公開ポート → Namespace/Service:ポート」のマッピングを書き込み、さらにコントローラーの Service 側で対応するポートを開放するというものです。これは Ingress リソースを経由せず、コントローラー独自の拡張機構です。

L4 公開には L7 と本質的な違いがあります。TCP 層には Host や Path の概念がなく、HTTP のようにドメインでバックエンドを区別できないため、ポート番号でしかサービスを区別できません。そのため TCP サービスを 1 つ公開するごとにエントリーポイントのポートを 1 つ占有することになり、サービスが増えるとポート管理が煩雑になっていきます。

ハマりどころと注意点

  1. Ingress リソースを適用したのに効かない場合、たいていはクラスタにそもそもコントローラーがインストールされていないか、Ingress の ingressClassName がコントローラーと一致していないかのどちらかです。クラスタ内で複数のコントローラーを動かしているときに特にハマりやすいポイントです。
  2. データベース系サービス(MySQL、Redis など)を Ingress 経由でパブリックに公開するのは慎重に。L4 転送には認証の強化が一切付いてこないため、内部ネットワーク、VPN、踏み台サーバー経由にするのがより堅実な方法です。
  3. コントローラーごとに annotation は互換性がありません。Nginx から Traefik に移行する際は、annotation で実現していたリライト、レート制限、タイムアウトの設定を 1 つずつ翻訳し直す必要があります。
  4. ロングコネクション系の L4 サービスでは、プロキシのアイドルタイムアウト設定に注意しましょう。デフォルト値はデータベースクライアントのコネクションプールが想定するよりも短いことが多く、コネクションが途中で切断される現象が起きやすくなります。

まとめ

Ingress はクラスタの南北(North-South)トラフィックの統一エントリーポイントです。ルールは Ingress リソースで宣言し、実際の転送はコントローラーが行います。L7 のシナリオでは主要なコントローラーのどれもが十分に役割を果たせ、違いは主に設定方法とエコシステムにあります。L4 公開は Ingress 仕様自体の範囲を超えており、Traefik、Istio Gateway、Nginx Ingress の ConfigMap といった各実装独自の拡張機構に頼る必要があります。選定の際は、機能リストの充実度を追い求めるよりも、チームの既存技術スタックと運用習慣に合わせて決めるほうが現実的です。

COMMENTS