はい、承知いたしました。NodePortとLoadBalancerの違い、およびKubernetes Serviceの適切な選び方について、約5000語の詳細な解説記事を作成します。
NodePortとLoadBalancerの違いは?Kubernetes Serviceの適切な選び方【完全ガイド】
はじめに:Kubernetesにおける「外部公開」という永遠の課題
Kubernetesは、現代のアプリケーション開発と運用、特にマイクロサービスアーキテクチャにおいて、デファクトスタンダードとしての地位を確立しました。コンテナ化されたアプリケーションを宣言的に管理し、自己修復能力やスケーラビリティといった強力な機能を提供してくれます。しかし、その強力さゆえに、特にネットワーク周りは初学者にとって複雑で難解な領域の一つです。
アプリケーションをコンテナとしてKubernetesクラスタ上で動かすだけでは、サービスは完結しません。そのサービスを、エンドユーザーや他のシステムといった「クラスタの外部」から利用可能にする必要があります。この「外部への公開」を実現するための中心的な役割を担うのが、KubernetesのServiceリソースです。
Kubernetes Serviceにはいくつかのタイプが存在しますが、中でも外部公開の文脈で頻繁に比較検討されるのがNodePort
とLoadBalancer
です。
- 「とりあえず外部からアクセスしたいけど、
NodePort
とLoadBalancer
、どっちを使えばいいの?」 - 「オンプレミス環境でKubernetesを使っているが、最適な公開方法がわからない」
- 「クラウドで
LoadBalancer
を使っているけど、サービスごとに料金がかかってコストが心配…」 - 「そもそも、これらのServiceタイプが内部でどう動いているのかがよくわからない」
この記事では、こうした疑問や課題を抱えるエンジニアのために、NodePort
とLoadBalancer
という2つの主要なServiceタイプに焦点を当て、その違いを徹底的に解き明かします。それぞれの動作原理、メリット・デメリット、具体的なユースケース、そしてコストやセキュリティといった実用的な側面までを深く掘り下げて解説します。
最終的に、この記事を読み終えたあなたが、自身の環境や要件に最も適したServiceタイプを自信を持って選択し、堅牢で効率的なシステムを構築できるようになることを目指します。
第1章 Kubernetes Serviceの基本:なぜServiceが必要なのか?
NodePort
とLoadBalancer
の違いを理解する前に、まずKubernetesにおけるService
の基本的な役割と、なぜそれが必要不可欠なのかを再確認しましょう。
1.1 Podの儚い命とServiceの恒久性
Kubernetesでは、アプリケーションの実行単位としてPodが使われます。しかし、Podは「儚い(ephemeral)」存在です。Podは、デプロイ、スケーリング、ノード障害などの様々な理由で、頻繁に生成・破棄されます。Podが再作成されるたびに、新しい内部IPアドレスが割り当てられます。
もし、クライアントアプリケーションがPodのIPアドレスを直接参照していたらどうなるでしょうか?Podが再起動するたびにIPアドレスが変わり、クライアントは接続先を見失ってしまいます。これでは安定したサービス提供は不可能です。
この問題を解決するのがServiceです。Serviceは、論理的に関連するPodの集合に対して、単一の安定したアクセスポイントを提供します。
- 静的な仮想IP(ClusterIP): Serviceは、そのライフサイクルを通じて変わることのない、クラスタ内でのみ有効な仮想IPアドレス(ClusterIP)を持ちます。
- DNS名: Serviceには、
<service-name>.<namespace>.svc.cluster.local
という形式のDNS名が自動的に割り当てられ、クラスタ内から名前解決できます。 - ラベルとセレクター: Serviceは、どのPodにトラフィックを転送すべきかを判断するために、「ラベル」と「セレクター」という仕組みを使います。Serviceの
selector
に一致するラベルを持つPodが、自動的にそのServiceの転送先(エンドポイント)として登録されます。
これにより、Podがどれだけ頻繁に増減・再作成されても、クライアントは常に不変のServiceのClusterIPまたはDNS名にアクセスすればよく、Kubernetesが裏側で自動的に正常なPodへトラフィックを振り分けてくれるのです。
1.2 Serviceの主要なタイプ
KubernetesのServiceには、spec.type
フィールドで指定するいくつかのタイプがあります。それぞれの役割は明確に異なります。
-
ClusterIP:
- デフォルトのServiceタイプです。
- クラスタ内部でのみアクセス可能なIPアドレスを割り当てます。
- クラスタ内のマイクロサービス間通信で主に使用されます。
NodePort
やLoadBalancer
も、内部的にはこのClusterIP
をベースにしています。
-
NodePort:
ClusterIP
の機能に加え、クラスタの各ノードで静的なポート(NodePort)を一つ開放します。<NodeIP>:<NodePort>
という形式で、クラスタ外部からServiceにアクセスできるようになります。- この記事の主役の一つです。
-
LoadBalancer:
NodePort
の機能に加え、クラウドプロバイダーが提供する外部ロードバランサーを自動的にプロビジョニングし、Serviceに紐付けます。- 外部ロードバランサーが持つグローバルIPアドレスが、サービスへの単一のエントリーポイントとなります。
- この記事のもう一つの主役です。
-
ExternalName:
- クラスタ外部のサービス(例:外部のデータベースやAPI)に対して、クラスタ内にDNSエイリアス(CNAMEレコード)を作成します。
- トラフィックのプロキシは行わず、名前解決のみを提供します。
-
Headless Service:
spec.clusterIP: None
と設定することで作成されます。ClusterIP
を持たず、負荷分散も行いません。- ServiceのDNS名に問い合わせると、紐づく全PodのIPアドレスリストが返されます。StatefulSetと組み合わせて、各Podを個別にアドレス指定したい場合などに使われます。
本記事では、この中からクラスタ外部への公開を担うNodePort
とLoadBalancer
に焦点を当てて、深く掘り下げていきます。
第2章 NodePort詳解:シンプルさと普遍性の裏側
まずは、最も基本的で普遍的な外部公開方法であるNodePort
から見ていきましょう。
2.1 NodePortとは何か?
NodePort
は、その名の通り「ノードのポート」を外部に公開するServiceタイプです。type: NodePort
を指定してServiceを作成すると、Kubernetesは以下の3つのポートを連携させてトラフィックをルーティングします。
targetPort
: Serviceがトラフィックを最終的に転送する先である、Pod内のコンテナがリッスンしているポート。port
: Service自体のClusterIP
がリッスンするポート。クラスタ内からはこのポートにアクセスします。nodePort
: クラスタの全てのノードで開放されるポート。クラスタ外部からのトラフィックは、このポートを通じて侵入します。
外部のクライアントは、http://<いずれかのNodeのIP>:<nodePort>
にアクセスすることで、最終的にPod上のアプリケーションに到達できます。
2.2 NodePortの動作原理:kube-proxyの魔法
NodePort
の仕組みを理解する上で鍵となるコンポーネントが、各ノードでデーモンとして動作するkube-proxyです。NodePort
Serviceが作成されると、kube-proxy
が舞台裏で活躍します。
トラフィックの流れをステップ・バイ・ステップで追ってみましょう。
-
クライアントからのリクエスト: 外部クライアントが、Kubernetesクラスタを構成するいずれかの一つのノードのIPアドレスと、指定された
nodePort
(例:http://10.20.30.40:30080
)に対してリクエストを送信します。 -
ノードでの受信とkube-proxy: リクエストは、指定されたノード(例:
worker-node-1
)に到達します。このノード上で動作しているkube-proxy
は、カーネルのネットワーク機能(iptables
やIPVS
)を監視・設定しています。kube-proxy
は、nodePort
(30080)へのトラフィックを検知するためのルールをあらかじめ設定しています。 -
宛先NAT(DNAT):
kube-proxy
は、受信したパケットの宛先アドレスを、ServiceのClusterIP
とport
(例:10.96.10.20:80
)に書き換えます。これを宛先NAT(Destination NAT, DNAT)と呼びます。この時点で、リクエストはあたかもクラスタ内部からClusterIP
に向けて送信されたかのような形になります。 -
エンドポイントへの転送:
ClusterIP
は仮想的なIPであり、実体はありません。kube-proxy
は、このServiceに紐づく正常なPod(エンドポイント)のIPアドレスリストをAPI Serverから取得しています。そして、書き換えられたパケットを、そのリストの中からランダムまたはラウンドロビンで選択した一つのPodのIPアドレスとtargetPort
(例:192.168.1.5:8080
)に再度DNATして転送します。
重要な点は、どのノードのNodePort
にアクセスしても、最終的にはクラスタ内のいずれかの正常なPodにトラフィックが到達するということです。リクエストを受け取ったノード上に該当のPodが存在していなくても、kube-proxy
がクラスタ内の別のノードにいるPodへ適切に転送してくれます。
2.3 NodePortのYAML定義例
yaml
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
# ServiceのタイプをNodePortに指定
type: NodePort
selector:
app: my-app # このラベルを持つPodにトラフィックを転送
ports:
- protocol: TCP
# ServiceのClusterIPがリッスンするポート
port: 80
# Pod内のコンテナがリッスンしているポート
targetPort: 8080
# ノードで公開されるポート (30000-32767の範囲)
# このフィールドを省略すると、範囲内から自動で割り当てられる
nodePort: 30080
2.4 NodePortのメリット
- シンプルさと設定の容易さ: YAMLファイルで
type: NodePort
と指定するだけで、追加のインフラコンポーネントなしに外部公開が可能です。 - 普遍性: クラウド環境、オンプレミス環境、さらにはローカルの開発環境(minikubeやkind)まで、Kubernetesが動作する場所ならどこでも利用できます。クラウドプロバイダーへの依存がありません。
- デバッグやテストに便利: 外部のロードバランサーを介さずに、直接ノードにアクセスしてサービスの動作を素早く確認したい場合に非常に役立ちます。
2.5 NodePortのデメリットと課題
シンプルさの裏には、本番環境で利用するには厳しい制約や課題が潜んでいます。
- ポート番号の制約:
nodePort
として使用できるポート番号は、デフォルトで30000-32767
という高い範囲に制限されています。ユーザーにhttp://example.com:30080
のようにポート番号付きのURLを案内するのは現実的ではありません。HTTP(80)やHTTPS(443)といったWell-knownポートは通常利用できません。 - 単一障害点としてのノード: クライアントは特定のノードIPアドレスにアクセスします。もしそのノードがダウンした場合、そのIPアドレスへのアクセスは失敗します。もちろん、クライアントが別のノードのIPアドレスを知っていればそちらにアクセスできますが、クライアント側にフェイルオーバーのロジックを持たせるのは良い設計とは言えません。
- 手動での負荷分散が必要:
NodePort
自体は、複数のノードIPにトラフィックを分散する機能を提供しません。高可用性と負荷分散を実現するためには、結局のところ、全ノードをターゲットにした外部のロードバランサーを別途手動で設定する必要があります。 - セキュリティ上の懸念: クラスタを構成するノードのIPアドレスを直接外部に公開することになります。これにより攻撃対象領域が広がり、ノード自体へのセキュリティリスクが高まる可能性があります。
- ノードの増減への追従: クラスタにノードを追加したり削除したりした場合、外部ロードバランサーの設定を手動で更新し、ターゲットリストに新しいノードを追加(または古いノードを削除)する必要があります。
2.6 NodePortの主なユースケース
上記のメリット・デメリットから、NodePort
が輝くシナリオは以下の通りです。
- 開発・テスト・デモ環境: サービスを一時的に外部公開し、素早く動作確認を行いたい場合。
- オンプレミス環境での利用: 既存のハードウェアロードバランサー(F5 BIG-IPなど)やソフトウェアロードバランサー(HAProxyなど)と連携させる場合。この構成では、外部LBが全ワーカーノードの
NodePort
をバックエンドとして監視し、負荷分散とフェイルオーバーを実現します。 - Ingress Controllerの公開: 後述する
Ingress
という、より高度なルーティング機能を提供するコンポーネントを外部に公開するための土台として利用されることがあります。
第3章 LoadBalancer詳解:クラウドネイティブな自動化の世界
次に、特にクラウド環境で標準的な選択肢となるLoadBalancer
タイプを見ていきましょう。
3.1 LoadBalancerとは何か?
LoadBalancer
Serviceは、NodePort
の機能を拡張したものです。type: LoadBalancer
を指定してServiceを作成すると、Kubernetesはクラウドプロバイダーと連携し、外部ロードバランサーを自動的にプロビジョニングします。そして、そのロードバランサーに永続的なパブリックIPアドレスを割り当て、クラスタのノード群にトラフィックを転送するように設定します。
ユーザーは、プロビジョニングされたロードバランサーの単一のIPアドレス(またはDNS名)にアクセスするだけで、サービスを利用できます。ノードのIPアドレスやポート番号を意識する必要は一切ありません。
3.2 LoadBalancerの動作原理:cloud-controller-managerの活躍
LoadBalancer
Serviceの魔法の裏には、cloud-controller-managerというKubernetesのコントロールプレーンコンポーネントが存在します。このコンポーネントが、Kubernetesクラスタと各クラウドプロバイダー(AWS, GCP, Azureなど)のAPIとの間の橋渡し役を担います。
トラフィックの流れは、NodePort
の仕組みの上に成り立っています。
- Serviceの作成: ユーザーが
type: LoadBalancer
のServiceをYAMLで定義し、kubectl apply
します。 - cloud-controller-managerの検知:
cloud-controller-manager
は、新しいLoadBalancer
タイプのServiceが作成されたことをAPI Server経由で検知します。 - クラウドAPIの呼び出し:
cloud-controller-manager
は、稼働しているクラウド環境(例: AWS)を認識し、そのクラウドのAPIを呼び出して、外部ロードバランサー(例: AWSのElastic Load Balancer – ELB)の作成をリクエストします。 - ロードバランサーのプロビジョニング: クラウドプロバイダーはリクエストを受け、外部からアクセス可能なパブリックIPアドレスを持つロードバランサーをプロビジョニングします。
- ターゲット設定: プロビジョニングされたロードバランサーは、Kubernetesクラスタの全てのワーカーノードをターゲットグループとして設定します。そして、トラフィックを各ノードの対応する
NodePort
に転送するように構成されます。- ここが重要です:
LoadBalancer
Serviceを作成すると、Kubernetesは自動的に対応するNodePort
Serviceも作成します。外部ロードバランサーは、このNodePort
にトラフィックを送るのです。つまり、LoadBalancer
はNodePort
を内包し、その上に自動化と単一エントリーポイントの層を追加したもの、と理解できます。
- ここが重要です:
- 外部IPの書き戻し: ロードバランサーのプロビジョニングが完了すると、そのパブリックIPアドレスが
cloud-controller-manager
によって取得され、Serviceオブジェクトのstatus.loadBalancer.ingress
フィールドに書き戻されます。kubectl get service
で表示されるEXTERNAL-IP
がこれにあたります。 - クライアントからのリクエスト: ユーザーは、この
EXTERNAL-IP
に対してリクエストを送信します。 - LBからNodePortへ: リクエストはクラウドのロードバランサーに到達し、負荷分散され、いずれかのワーカーノードの
NodePort
に転送されます。 - 以降はNodePortと同じ: ノードに到達した後のトラフィックの流れは、前述の
NodePort
の動作原理と全く同じです(kube-proxy
によるClusterIP
へのDNAT、そしてPodへの転送)。
3.3 LoadBalancerのYAML定義例
yaml
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
# クラウドプロバイダー固有の挙動を制御するためのアノテーション
# 例: AWSでNetwork Load Balancer (NLB) を使う指定
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
# ServiceのタイプをLoadBalancerに指定
type: LoadBalancer
selector:
app: my-app
ports:
- protocol: TCP
# LBがリッスンするポート
port: 80
# Pod内のコンテナがリッスンしているポート
targetPort: 8080
3.4 LoadBalancerのメリット
- 単一の安定したエントリーポイント: ユーザーに提供するのは、単一で不変のIPアドレス(またはDNS名)だけです。ノードの増減や障害を完全に隠蔽できます。
- 完全な自動化: Kubernetesの宣言的なマニフェストを適用するだけで、ロードバランサーのプロビジョニング、設定、ヘルスチェック、削除までが自動的に行われます。インフラ管理の手間が劇的に削減されます。
- 高可用性とスケーラビリティ: クラウドプロバイダーが提供するマネージドロードバランサーは、本番環境での利用を前提としており、非常に高い可用性と、トラフィック量に応じたスケーラビリティが保証されています。
- Well-knownポートの利用: ポートの制約がなく、HTTP(80)やHTTPS(443)など、任意のポートを自由に利用できます。
3.5 LoadBalancerのデメリットと課題
自動化と高機能性にはトレードオフが存在します。
- クラウドプロバイダー依存: この機能は、
cloud-controller-manager
を介したクラウドプロバイダーのサポートが前提です。オンプレミス環境や、サポートされていないクラウドでは、標準では動作しません。(ただし、MetalLBのようなアドオンを導入することで、オンプレミスでもLoadBalancer
タイプを擬似的に実現可能です。) - コスト: マネージドロードバランサーは、便利である一方、有料のサービスです。通常、稼働時間や処理したデータ量に応じて課金されます。Serviceごとに
LoadBalancer
を作成すると、その数だけロードバランサーがプロビジョニングされ、コストが積み上がっていく可能性があります。 - プロビジョニング時間: クラウド上でロードバランサーが作成され、利用可能になるまでには、数秒から数分程度の時間がかかる場合があります。
- L4ロードバランサーが基本: ほとんどのクラウド実装では、
LoadBalancer
ServiceはTCP/UDPレベルで動作するレイヤー4(L4)ロードバランサーを作成します。URLのパス(/api/v1
など)やホスト名(api.example.com
)に基づいてルーティングを切り替えるといった、高度なレイヤー7(L7)機能は直接サポートしていません。
3.6 LoadBalancerの主なユースケース
- クラウド環境での本番サービス公開: AWS, GCP, Azureなどの主要なクラウドプラットフォームで、外部にサービスを公開する場合の、最も標準的で推奨される方法です。
- 単一のTCP/UDPサービスをシンプルに公開: HTTP/HTTPS以外のTCP/UDPプロトコル(データベース、gRPC、ゲームサーバーなど)を、高可用な単一IPで公開したい場合に最適です。
第4章 NodePort vs. LoadBalancer: 徹底比較と選択のポイント
ここまでの解説を、比較表としてまとめてみましょう。
項目 | NodePort | LoadBalancer |
---|---|---|
目的 | ノードのポートを直接公開し、外部アクセスの経路を確保する | クラウドのロードバランサーを自動作成し、サービスを公開する |
エントリーポイント | 複数のノードIP (<NodeIP>:<NodePort> ) |
単一の外部IP (<LoadBalancerIP>:<Port> ) |
動作環境 | 普遍的(クラウド、オンプレミス、ローカル) | 主にクラウド環境(またはMetalLB等を追加したオンプレミス) |
自動化 | なし(高可用性のためには手動で外部LBの設定が必要) | あり(クラウドLBのプロビジョニングから設定までを自動化) |
ポート番号 | 制限あり(デフォルト: 30000-32767) | 任意(80, 443など自由) |
コスト | Kubernetesリソースのみ(追加コストなし) | ロードバランサー利用料が発生 |
高可用性 | 手動で外部LBを構築・設定する必要がある | クラウドプロバイダーがマネージドサービスとして提供 |
設定の複雑さ | 非常に簡単 | 簡単(ただしクラウド依存のアノテーション等あり) |
主なユースケース | 開発/テスト、オンプレミスでのLB連携、Ingressの基盤 | クラウドでの本番サービス公開 |
レイヤー | L4 (TCP/UDP) | L4 (TCP/UDP) |
第5章 適切なServiceタイプの選び方:シナリオ別実践ガイド
理論を学んだところで、次は実践です。あなたの状況に最適なServiceタイプはどれでしょうか?いくつかの典型的なシナリオに沿って、意思決定のプロセスを見ていきましょう。
シナリオ1:ローカルPCでの開発や、ちょっとした機能テスト
状況: あなたは自分のラップトップ上のminikubeやDocker DesktopでKubernetesを動かしています。新しく作ったマイクロサービスの動作を、ブラウザから素早く確認したいと考えています。
- 推奨:
NodePort
- 理由:
- 迅速性:
LoadBalancer
のように外部リソースのプロビジョニングを待つ必要がありません。apply
後、すぐにminikube service my-service
のようなコマンドでURLを取得し、アクセスできます。 - コスト: 追加コストは一切かかりません。
- シンプルさ: 最も手軽にクラスタ外部からPodにアクセスする手段です。このシナリオで高可用性や美しいURLは必要ありません。
- 迅速性:
シナリオ2:オンプレミス環境での本番稼働
状況: あなたの会社は自社のデータセンターに物理サーバーやVMを所有しており、そこでKubernetesクラスタを運用しています。本番サービスを外部に公開する必要があります。
-
推奨パターンA:
NodePort
+ 既存の外部ロードバランサー- 方法: すでにデータセンターにF5 BIG-IP、Citrix ADC、HAProxyといったハードウェア/ソフトウェアロードバランサーが存在する場合、これが最も現実的な選択です。Kubernetes側で
NodePort
Serviceを作成し、そのNodePort
(例: 30080)を全ワーカーノードについて外部LBのバックエンドプールに登録します。外部LBがユーザーからのトラフィック(例:https://app.example.com
)を受け、ノード群に負荷分散します。 - 利点: 既存のインフラ資産と運用ノウハウを活用できます。
- 欠点: ノードの増減時にLBの設定を手動で変更する必要があります(自動化も可能だが作り込みが必要)。
- 方法: すでにデータセンターにF5 BIG-IP、Citrix ADC、HAProxyといったハードウェア/ソフトウェアロードバランサーが存在する場合、これが最も現実的な選択です。Kubernetes側で
-
推奨パターンB:
LoadBalancer
+ MetalLB- 方法: MetalLBは、オンプレミス環境で
LoadBalancer
タイプのServiceを実現するための素晴らしいオープンソースプロジェクトです。データセンター内の未使用のIPアドレス範囲をMetalLBに設定しておくと、LoadBalancer
Serviceが作成された際に、MetalLBがそのプールからIPアドレスを一つ割り当て、BGPやARPを使ってそのIPアドレスへのトラフィックをクラスタに引き込みます。 - 利点: クラウド環境とほぼ同じように、
type: LoadBalancer
と書くだけでサービスを公開でき、運用体験が統一されます。 - 欠点: MetalLBの導入と、ネットワークに関する一定の知識(BGP/ARP)が必要です。
- 方法: MetalLBは、オンプレミス環境で
シナリオ3:クラウド環境(AWS, GCP, Azure)での単一サービスの本番公開
状況: あなたはAWS上でEKSクラスタを運用しています。外部に公開したいのは、単一のgRPCベースのバックエンドサービスです。
- 推奨:
LoadBalancer
- 理由:
- ベストプラクティス: これは
LoadBalancer
Serviceが最も輝く、教科書通りのシナリオです。 - マネージド: AWSがロードバランサー(NLBやCLB)の高可用性、スケーラビリティ、セキュリティを管理してくれるため、運用負荷が大幅に軽減されます。
- シンプル: YAMLを一つ適用するだけで、安定した単一のIPアドレスを持つエンドポイントが手に入ります。gRPCのようなTCPベースの通信に最適です。
- ベストプラクティス: これは
シナリオ4:クラウド環境で、複数のHTTP/HTTPSサービスを同じIPで公開したい
状況: あなたはクラウド上で、api.example.com
、www.example.com
、admin.example.com
といった複数のWebサービスを運用しています。これらをすべて単一のグローバルIPアドレスで公開し、コストを抑えたいと考えています。また、api.example.com/users
とapi.example.com/products
のように、URLのパスに基づいてリクエストを異なるマイクロサービスに振り分けたいです。
- 推奨:
Ingress
(+LoadBalancer
またはNodePort
) - 理由: このシナリオは
LoadBalancer
Serviceの限界点を示しています。- コスト問題: サービスごとに
LoadBalancer
を作成すると、3つのロードバランサーがプロビジョニングされ、3倍のコストがかかります。 - L7ルーティングの必要性: ホスト名やパスに基づいたルーティングは、L4ロードバランサーである
LoadBalancer
Serviceでは実現できません。
- コスト問題: サービスごとに
ここで登場するのがIngressです。IngressはServiceとは別のKubernetesリソースで、HTTP/HTTPSトラフィックをクラスタ内のServiceにルーティングするためのルールを定義します。
- Ingressの仕組み:
- Ingressリソース:
api.example.com
へのリクエストはapi-service
へ、/users
パスはuser-service
へ、といったL7ルーティングルールを定義します。 - Ingress Controller: このルールを解釈し、実際にリバースプロキシとして動作するのがIngress Controllerです(例: NGINX Ingress Controller, Traefikなど)。これはクラスタ内で動作するただのPodです。
- Ingress Controllerの公開: そして、このIngress Controller自体をクラスタ外部に公開する必要があります。この公開手段として、
LoadBalancer
またはNodePort
タイプのServiceが使われます。
- Ingressリソース:
つまり、Ingress
はNodePort
やLoadBalancer
の代替ではなく、それらを土台として利用する、より高度なアプリケーションレイヤーのルーティングメカニズムなのです。
この構成では、LoadBalancer
はIngress Controller用に一つだけ作成すればよく、その配下にある多数のHTTP/HTTPSサービスはIngressルールを追加するだけで公開できます。これにより、ロードバランサーのコストを劇的に削減しつつ、柔軟なL7ルーティングを実現できるのです。
第6章 発展的なトピックと考慮事項
最後に、NodePort
やLoadBalancer
を使いこなす上で知っておくべき、いくつかの重要な設定や概念について触れておきます。
6.1 externalTrafficPolicy
: 送信元IPを保持する鍵
Serviceのspec
にはexternalTrafficPolicy
というフィールドがあり、Cluster
(デフォルト)またはLocal
を設定できます。これは外部からのトラフィックの挙動、特に送信元IPの保持に大きな影響を与えます。
-
externalTrafficPolicy: Cluster
(デフォルト)- 動作:
NodePort
に到達したトラフィックは、クラスタ内のいずれかのノードにいるPodに転送される可能性があります。リクエストを受信したノードにPodがいなくても、別のノードへ転送されます。 - メリット: トラフィックがクラスタ全体に均等に分散されやすいです。
- デメリット: 別のノードにパケットを転送する際に、Source NAT (SNAT) が行われます。これにより、アプリケーション(Pod)から見た送信元IPアドレスが、リクエストを転送したノードのIPアドレスになってしまい、本来のクライアントIPが失われます。これはアクセスログの分析やIPベースのアクセス制御において致命的な問題となり得ます。
- 動作:
-
externalTrafficPolicy: Local
- 動作:
NodePort
に到達したトラフィックは、そのリクエストを受信したノード上に存在するPodにのみ転送されます。もしそのノード上にPodが存在しない場合、パケットは破棄されます。 - メリット: 不要なネットワークホップがなく、SNATも行われないため、アプリケーションは本来のクライアントIPアドレスを維持できます。
- デメリット: もしクラウドのロードバランサーが、Podのいないノードにもトラフィックを送ってしまうと、リクエストが失われます。しかし、賢いクラウドLBはヘルスチェックと連携し、Podが正常に稼働しているノードにのみトラフィックを転送するように自動で設定を更新してくれます。そのため、クラウド環境で
LoadBalancer
Serviceを使い、送信元IPを保持したい場合は、externalTrafficPolicy: Local
を設定するのが一般的なベストプラクティスです。
- 動作:
6.2 セキュリティに関する考察
NodePort
: ノード自体を直接公開するため、ノードレベルのファイアウォール(セキュリティグループなど)や、KubernetesのNetworkPolicy
を駆使して、不要なアクセスを厳格に制限することが不可欠です。LoadBalancer
: クラウドプロバイダーが提供するロードバランサー側のセキュリティ機能(例: AWSのSecurity Groups, WAF連携)を活用することで、クラスタの手前で脅威をフィルタリングできます。Ingress
: TLS終端(SSL証明書をIngress Controllerで管理)、WAF連携、認証・認可(OAuth2-Proxyなどとの連携)といった、より高度でアプリケーションに近いセキュリティ機能を実装するのに最適なレイヤーです。
まとめ:あなたの最適解を見つけるために
Kubernetesにおけるサービスの外部公開は、一見すると複雑な選択肢に満ちています。しかし、その核心を理解すれば、道筋は明確になります。
-
NodePort
は、そのシンプルさと普遍性が最大の武器です。あらゆる環境で動作し、追加コストなしに素早くサービスを公開できます。開発・テスト環境や、既存のLBと連携するオンプレミス環境では、依然として強力な選択肢です。 -
LoadBalancer
は、クラウドネイティブな自動化と高可用性を提供します。クラウド環境で本番サービスを公開する際の、最も簡単で信頼性の高いデファクトスタンダードです。宣言的な設定だけで、インフラ管理の大部分をKubernetesとクラウドプロバイダーに委任できます。
どちらが優れているという議論は無意味です。これらは異なる課題を解決するために設計されたツールであり、あなたのアプリケーションの要件、運用環境、コスト許容度、そして将来の拡張計画に基づいて、戦略的に選択されるべきものです。
そして、複数のHTTP/HTTPSサービスを効率的に管理する必要が出てきたときには、NodePort
やLoadBalancer
を基盤として利用する、より高度なIngress
の世界があなたを待っています。
Kubernetesのネットワークは奥深い領域ですが、Service
の基本をしっかりと押さえることは、安定し、スケーラブルで、セキュアなアプリケーションを構築・運用するための揺るぎない第一歩です。この記事が、その一助となれば幸いです。