
KubernetesのIngress でルーティングするのと、Web サーバ側でルーティングするのって何が違うの?
Kubernetes を使っていると、「Ingress でルーティングするのと、Web サーバ側でルーティングするのって何が違うの?」 と思ったことはありませんか?
実際、net/http や gin を使えば、アプリケーション内でルーティングできるし、Ingress を使わなくても動きますよね。
「じゃあ、Web サーバ側でルーティングすれば Ingress なんて不要では?」と考えるのも自然です。
でも、Ingress にはIngressを使う理由があります。
結論からいうと、Ingress は「どのサービスにリクエストを送るか?」を決める役割を持っている のに対し、Web サーバ側のルーティングは「アプリケーション内でどの処理を実行するか?」を決めるものです。
つまり、ルーティングのスコープが違うんです。
Web サーバ側のルーティング(アプリケーションレベル)
まず、Web サーバのルーティングは、「1つのアプリケーション内で、リクエストをどの処理に振り分けるか?」 を決めます。
たとえば、Golang の gin を使うと、こんな感じでルーティングできます。
r := gin.Default()
r.GET("/api/users", getUsersHandler)
r.POST("/api/users", createUserHandler)
r.GET("/images/:filename", serveImageHandler)
r.Run(":8080")
このルーティングでは、
/api/users の GET リクエスト → getUsersHandler
/api/users の POST リクエスト → createUserHandler
/images/:filename のリクエスト → serveImageHandler
と、アプリ内の処理を振り分けています。
つまり、Web サーバ側のルーティングは、「このリクエストをどの関数で処理するか?」を決める役割 を持っているわけですね。
Ingress のルーティング(Kubernetes レベル)
一方で、Ingress は 「Kubernetes クラスタ内のどのサービスにリクエストを送るか?」 を決めます。
例えば、こんな感じの Ingress 設定を考えてみましょう。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /api/
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
- path: /images/
pathType: Prefix
backend:
service:
name: static-service
port:
number: 80
この設定では、
/api/ のリクエスト → api-service へ
/images/ のリクエスト → static-service へ
と、それぞれ異なる Kubernetes の Service にルーティングされています。
Ingress は 「このリクエストはどのコンテナ(サービス)に送るか?」 を決める役割を持っています。
なので、アプリケーション内部のルーティングとは全く別の役割を果たしている んですね。
「Ingress いらなくない?」と思う場面とその問題点
ここで、「でも Web サーバ側で /api/ や /images/ のリクエストを振り分ければ、Ingress なんて不要では?」と思うかもしれません。
確かに、1つの Web サーバにすべてのリクエストを集約して、アプリケーション内でルーティングすれば、Ingress を使わずに動かすことはできます。
でも、そのやり方にはいくつか問題があります。
(1) スケールが難しくなる
例えば、API サーバと静的ファイルサーバを別々にスケールさせたい場合、Ingress を使えば 個別にスケール できますが、Web サーバでルーティングしてしまうと 1つのサーバに負荷が集中 してしまいます。
Ingress を使う場合
api-service のみをスケールアウト可能
static-service のみをスケールアウト可能
Web サーバ内でルーティングする場合
すべてのリクエストが 1 つのサーバに集中
1 つの Web サーバがボトルネックになる
(2) 異なるサービスのデプロイが複雑になる
API サーバと静的ファイルサーバを 別々にデプロイ したいのに、Web サーバが両方を処理するルールを持っていると、アプリの更新が面倒になります。
Ingress を使えば、各サービスを独立してデプロイしやすくなる ので、変更の影響を最小限に抑えることができます。
(3) マルチドメインや外部リクエストの管理が大変
Ingress を使えば、
api.example.com は API サーバへ
static.example.com は 静的ファイルサーバへ
のように、異なるドメインのリクエストを適切なサービスに振り分ける ことも簡単にできます。
Web サーバだけでやろうとすると、リクエストのヘッダを見て処理を変えるなど、実装が複雑になってしまいます。
結論:Ingress は Web サーバのルーティングとはスコープが違う
最終的に、Ingress のルーティングと Web サーバのルーティングは、目的が違う ということです。
Web サーバのルーティング → アプリ内のルーティング(エンドポイント単位)
Ingress のルーティング → どの Kubernetes サービスにリクエストを送るか決める(サービス単位)
もし、Web サーバ側で /api/ や /images/ のリクエストを振り分けると、
スケールしにくい
デプロイが複雑になる
マルチドメインや外部リクエストの管理が難しくなる
といった問題が発生します。
だから、Kubernetes では Ingress を使って「どのサービスに送るか?」を決めて、Web サーバ側で「そのサービス内でどう処理するか?」を決めるのがベスト なんです。
結局、「適材適所で使い分けることが大事」 ということですね!