【図解】Kubernetes NodePort の仕組みと設定方法

はい、承知いたしました。Kubernetes NodePort の仕組みと設定方法について、図解を想定した詳細な説明を含む約5000語の記事を作成します。


【図解】Kubernetes NodePort の仕組みと設定方法

はじめに

Kubernetes は、コンテナ化されたアプリケーションのデプロイ、スケーリング、管理を自動化するための強力なプラットフォームです。Kubernetes 上で動作するアプリケーションは、多くの場合、外部のユーザーやサービスからアクセスされる必要があります。しかし、Kubernetes の中心的なワークロード単位である Pod は、その性質上、短命であり、再起動や再配置によって IP アドレスが頻繁に変わります。このような Pod の動的な性質に対して、外部から安定的にアクセスを提供するために重要な役割を果たすのが Service というリソースです。

Kubernetes の Service は、Pod の論理的なグループを定義し、そのグループへのアクセス手段を提供します。Service にはいくつかのタイプがあり、アプリケーションへの外部からのアクセス方法や、クラスター内部でのアクセス方法に応じて使い分けられます。主な Service Type としては、以下の 4 種類があります。

  1. ClusterIP: クラスター内部の仮想 IP を割り当て、クラスター内部からのみアクセス可能な Service タイプです。デフォルトのタイプです。
  2. NodePort: 各ノード上の特定のポートを開放し、そのポートを通じてクラスター外部から Service にアクセス可能にするタイプです。
  3. LoadBalancer: クラウドプロバイダーが提供する外部ロードバランサーをプロビジョニングし、そのロードバランサーを通じて外部から Service にアクセス可能にするタイプです(対応するクラウド環境が必要です)。
  4. ExternalName: Service をクラスター内部の Pod ではなく、外部の DNS 名にマッピングするタイプです。

この記事では、これらの Service Type の中でも特にシンプルでありながら、外部公開の基本的な手段となる NodePort に焦点を当てます。NodePort Service は、Kubernetes クラスター内の各ノードの特定ポート(NodePort)を開放し、そのポートに到着したトラフィックを目的の Service に転送する仕組みを提供します。クラウド環境に依存せず、オンプレミス環境やベアメタル環境でも利用できるため、手軽にアプリケーションを外部に公開したい場合や、テスト・開発用途で非常に便利です。

本記事では、Kubernetes NodePort Service の詳細な仕組み、設定方法、利点と欠点、ユースケース、そして利用時の注意点について、図解を想定した解説を含めて深く掘り下げていきます。この記事を読むことで、NodePort Service を適切に理解し、活用できるようになることを目指します。

Kubernetes Service の基本

NodePort を理解する前に、Kubernetes Service の基本的な概念を改めて確認しておきましょう。

なぜ Service が必要なのか?

Kubernetes において、Pod はアプリケーションの実行単位ですが、そのライフサイクルは動的です。Pod は、デプロイメントのスケーリングによって増減したり、ノード障害やリソース不足によって再配置されたり、クラッシュして再起動したりします。これらのイベントが発生するたびに、Pod の IP アドレスは変更される可能性があります。

もし、他の Pod や外部クライアントが Pod の IP アドレスを直接知っていると、その Pod が再起動や再配置されるたびにアクセスできなくなってしまいます。また、複数のレプリカで構成されるアプリケーションの場合、どの Pod にアクセスすれば良いかをクライアント側で管理するのは現実的ではありません。

ここで Service が登場します。Service は、Pod の動的な性質を隠蔽し、一定のアクセス手段を提供します。Service は、指定されたラベルを持つ Pod 群(Endpoint と呼ばれます)を常に追跡し、その Pod 群への安定したネットワークエンドポイントを提供します。

Service と Pod の関係 (Label Selector)

Service は、Pod のグループをどのように識別するのでしょうか? その鍵となるのが ラベルセレクター (Label Selector) です。Pod には、キーとバリューのペアであるラベルを自由に付けることができます。Service の定義には selector フィールドがあり、ここに Pod のラベルを指定します。Service は、このセレクターに一致するラベルを持つすべての Pod を自動的に Endpoint として認識し、それらの Pod へトラフィックを転送します。

例えば、ウェブアプリケーションの Pod に app: web というラベルが付いている場合、Service のセレクターを selector: { app: web } と定義することで、その Service は app: web ラベルを持つ全ての Pod を対象とします。

Service の役割

Service は主に以下の役割を果たします。

  • 負荷分散 (Load Balancing): Service は、セレクターに一致する複数の Pod 間で受信トラフィックを自動的に分散します。これにより、アプリケーションのスケーラビリティと可用性が向上します。
  • サービスディスカバリー (Service Discovery): Service には安定した IP アドレス(ClusterIP)とホスト名が割り当てられます。クラスター内部の Pod は、この IP アドレスやホスト名を使って目的の Service にアクセスできます。これにより、クライアントは Pod の個別 IP アドレスを知る必要がなくなります。
  • 外部アクセス提供: NodePort, LoadBalancer などの Service Type を使用することで、クラスター外部から Service へアクセスする手段を提供します。

Service Type の簡単な説明

前述した Service Type を改めて簡単に説明します。

  • ClusterIP: クラスター内部でのみアクセス可能な仮想 IP アドレスを割り当てます。Kubernetes の Service の最も基本的な形態です。同じクラスター内の他の Pod からアクセスするのに適しています。
  • NodePort: 各ノードの特定ポートを開放し、外部から Node IP:NodePort でアクセス可能にします。この記事の主題です。
  • LoadBalancer: クラウドプロバイダーが提供するロードバランサーを利用して、外部に公開します。外部 IP アドレスが付与され、より高機能な負荷分散や TLS 終端などが可能です。クラウド環境に依存します。
  • ExternalName: Service を特定の Pod ではなく、externalName フィールドに指定した DNS 名にマッピングします。クライアントは Service 名を使って、クラスター外部のサービスにアクセスできます。プロキシ機能は持ちません。

NodePort は、ClusterIP の機能に加えて、外部から各ノードを通じてアクセスできるようにする機能を追加した Service タイプと言えます。

NodePort とは何か

NodePort Service は、その名の通り、「ノードのポート」を開放することで外部からのアクセスを受け付ける Service タイプです。

Service 定義の spec.type フィールドを NodePort に設定することで、その Service は NodePort Service となります。Kubernetes コントロールプレーンは、NodePort Service が作成されると、デフォルトで 30000-32767 の範囲から未使用のポート番号を自動的に選択し、その Service の NodePort として割り当てます。この割り当てられたポート番号は、クラスター内のすべてのワーカーノードでリスニングされます。

これにより、外部のクライアントは、クラスター内のどのノードの IP アドレスを使っても、割り当てられた NodePort 番号を通じて目的の Service にアクセスできるようになります。例えば、クラスターに 3 つのノード(IP: 192.168.1.10, 192.168.1.11, 192.168.1.12)があり、Service に NodePort 30080 が割り当てられた場合、クライアントは 192.168.1.10:30080192.168.1.11:30080、または 192.168.1.12:30080 のいずれのアドレスでも Service にアクセスできます。

他の Service Type との違い

  • ClusterIP: ClusterIP はクラスター内部からしかアクセスできません。NodePort は ClusterIP の上に外部からのアクセス手段を追加します。NodePort Service は、ClusterIP アドレスも自動的に割り当てられます。NodePort を通じて入ってきたトラフィックは、内部的には一度 ClusterIP にルーティングされてから Pod に転送されるという二段階の処理が行われます。
  • LoadBalancer: LoadBalancer はクラウドプロバイダーのインフラに依存します。外部に固定の IP アドレスやホスト名(CNAME)が付与され、一般的に標準的なポート(80/443など)でのアクセスが可能です。NodePort はクラウドに依存せず、ベアメタルなどでも利用できますが、ポートはデフォルトで高い番号(30000-32767)になりがちです。また、NodePort 自体には高度なロードバランシング機能(L7ルーティング、SSL終端など)はありません。LoadBalancer はしばしば NodePort を内部的に利用して実装されます。LoadBalancer は外部からのトラフィックをまず受け取り、それをバックエンドである NodePort Service に転送することで機能します。

NodePort の仕組み(図解を想定)

NodePort Service がどのように機能するか、その内部のトラフィックフローを追ってみましょう。ここでは、外部クライアントから NodePort Service を経由して Pod にトラフィックが到達するまでの過程を詳細に説明します。

(図解1:NodePort Service の基本的なトラフィックフロー)

図1は、外部クライアント、複数の Kubernetes Node、NodePort Service、そしてターゲットとなる Pod 群の関係を示しています。

図の中央には、ワーカーノード A、ワーカーノード B、ワーカーノード C といった複数の Kubernetes Node が描かれています。それぞれのノードには、一意の Node IP アドレス(例: Node A IP, Node B IP, Node C IP)があります。これらのノード上で、アプリケーションの Pod(例: Pod 1, Pod 2, Pod 3)が実行されています。また、各ノードには、Kubernetes のネットワークプロキシである kube-proxy がエージェントとして動作しています。

図の左側には、外部のユーザーやクライアントが描かれています。このクライアントは、NodePort Service にアクセスしたいと考えています。

図の中央下部には、Service(Type: NodePort)が描かれています。この Service は、ターゲットとなる Pod 群(例: Pod 1, Pod 2, Pod 3)をラベルセレクターによって選択しています。Service には、内部で使用される ClusterIP と ServicePort、そして外部公開のために割り当てられた NodePort が示されています。

トラフィックフローの詳細:

  1. 外部クライアントからのアクセス: 外部クライアントは、クラスター内の任意のノードの IP アドレスと、Service に割り当てられたNodePort 番号(例: 30080)を指定してアクセスします。例えば、http://Node A IP:30080http://Node B IP:30080 のようにアクセスします。
  2. ノードへのトラフィック到着: トラフィックは、指定されたノード(例: ワーカーノード A)の NodePort 番号(30080)でリスニングしているネットワークインターフェースに到着します。
  3. kube-proxy によるトラフィック処理: 各ノードで動作している kube-proxy が、Service の定義に基づき、NodePort 宛てのトラフィックをインターセプトし、処理します。kube-proxy の主な動作モードには iptablesipvs があります。

    • iptables モード (Linux のデフォルト): kube-proxy は、Linux カーネルの netfilter フレームワークの iptables ルールを操作します。NodePort Service が作成されると、kube-proxy はノードの iptables に、NodePort に到着したトラフィックを Service の ClusterIP:ServicePort に DNAT (Destination Network Address Translation) するルールを追加します。さらに、ClusterIP:ServicePort に到着したトラフィックを、Service の Endpoint(ターゲット Pod)の中から一つ選び、その Pod IP:ContainerPort に DNAT するルールを追加します。
      (図解2:iptables モードでのトラフィックフロー)
      図2では、ノードAのNodePort 30080に到着したパケットが、iptablesルールによってまずServiceのClusterIP:ServicePortに宛先変換される様子が描かれています。さらに別のiptablesルールによって、そのパケットがServiceのEndpointsリストからランダムに選択されたPodのIP:ContainerPort(例えばPod 2 IP:ContainerPort)に宛先変換され、そのPodへルーティングされる様子が示されています。
      重要なのは、これらの iptables ルールはクラスター内の全てのノードに同期されていることです。そのため、どのノードの NodePort にアクセスしても、トラフィックは正しく ClusterIP:ServicePort にルーティングされ、そこから Pod に負荷分散されます。
    • ipvs モード: iptables モードよりも比較的新しく、大規模な Service 数や大量のトラフィックを扱う場合に性能面で有利とされることがあります。kube-proxy は、Linux カーネルの IP Virtual Server (IPVS) を利用します。IPVS は LVS (Linux Virtual Server) の一部であり、高性能なロードバランシング機能を提供します。ipvs モードでは、kube-proxy は NodePort に到着したトラフィックを、IPVS を使って直接 Service の Endpoints (Pod IP:ContainerPort) へ転送します。iptables を経由するよりも、IPVS の方がコネクション数が多い場合のパフォーマンスに優れることがあります。
      (図解3:ipvs モードでのトラフィックフロー)
      図3では、ノードBのNodePort 30080に到着したパケットが、ipvsルールによって直接ServiceのEndpointsリストから選択されたPodのIP:ContainerPort(例えばPod 3 IP:ContainerPort)に転送される様子が描かれています。ipvsはコネクション追跡や負荷分散アルゴリズムをカーネル空間で効率的に行います。
  4. ClusterIP:ServicePort へのルーティング (iptablesの場合): iptables モードの場合、NodePort からのトラフィックは Service の ClusterIP:ServicePort に宛先変換されます。ClusterIP はクラスター内部の仮想 IP であり、それ自体が実体を持つわけではありません。Service に対応する iptables ルールが、この ClusterIP:ServicePort 宛てのトラフィックをさらに処理します。

  5. Pod への負荷分散: ClusterIP:ServicePort(または ipvs モードの場合は NodePort から直接)に到達したトラフィックは、Service のラベルセレクターに一致する複数の Pod の中から一つにルーティングされます。kube-proxy は、デフォルトではラウンドロビン方式で Pod を選択して負荷分散します。選択された Pod の IP アドレスと、Service 定義の targetPort フィールドで指定されたポートにトラフィックが転送されます。
  6. ターゲット Pod への到達: トラフィックは最終的に、選択された Pod 内のコンテナが targetPort でリスニングしているアプリケーションに到達します。

この仕組みにより、外部クライアントはクラスター内のどのノードの IP と NodePort を使っても、アプリケーションを実行している Pod 群へアクセスできるようになります。たとえアクセスに使ったノード上でターゲット Pod が実行されていなくても、kube-proxy が他のノードで実行されている Pod へトラフィックを転送します。

ポート範囲

NodePort Service に割り当てられるポートは、デフォルトでは 30000 から 32767 の範囲です。この範囲は、インターネット上で一般的に使用される標準ポート(HTTP: 80, HTTPS: 443 など)や、システムによって予約されているポートとの競合を避けるために選ばれています。

Service 定義で nodePort フィールドを指定することで、この範囲内の特定のポート番号を明示的に指定することも可能です。ただし、指定したポートが既に他の NodePort Service や、ホストマシン上の他のプロセスによって使用されている場合は、Service の作成に失敗します。

NodePort の設定方法

NodePort Service を設定するには、Service マニフェスト YAML ファイルを作成し、type: NodePort を指定します。ここでは、簡単なウェブアプリケーションの Deployment と、それに対応する NodePort Service を作成する例を示します。

1. Deployment の作成 (例: nginx)

まず、公開したいアプリケーションの Pod を作成するための Deployment を定義します。

“`yaml

nginx-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3 # Pod を3つ起動
selector:
matchLabels:
app: nginx # このラベルを持つ Pod を選択
template:
metadata:
labels:
app: nginx # Pod に付与するラベル
spec:
containers:
– name: nginx
image: nginx:latest # nginx コンテナイメージ
ports:
– containerPort: 80 # コンテナがリスニングするポート
“`

この Deployment は、app: nginx というラベルが付いた nginx コンテナを含む Pod を 3 つ起動します。nginx はデフォルトで 80 番ポートでリスニングします。

2. NodePort Service の作成

次に、上記の Deployment が作成する Pod にアクセスするための NodePort Service を定義します。

“`yaml

nginx-service.yaml

apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport-service # Service 名
spec:
selector:
app: nginx # この Service が対象とする Pod のラベル
ports:
– protocol: TCP
port: 80 # Service がクラスター内部に公開するポート (ClusterIP:80)
targetPort: 80 # Service がトラフィックを転送する Pod のポート
# nodePort: 30080 # オプション: 明示的に NodePort を指定する場合 (30000-32767 の範囲)
type: NodePort # Service Type を NodePort に設定
“`

この Service 定義の重要な点:

  • selector: app: nginx: この Service は、app: nginx というラベルを持つ Pod を Endpoint として認識します。上記の Deployment で作成される Pod が対象となります。
  • ports: ポートマッピングの設定です。
    • port: 80: Service がクラスター内部の仮想 IP (ClusterIP) で公開するポート番号です。他の Pod は nginx-nodeport-service:80 または ClusterIP:80 でこの Service にアクセスできます。
    • targetPort: 80: Service がトラフィックを転送する、対象 Pod のポート番号です。上記の nginx コンテナが 80 番ポートでリスニングしているため、ここに 80 を指定します。
    • nodePort: NodePort として割り当てるポート番号を指定します。この例ではコメントアウトしており、指定しない場合は 30000-32767 の範囲から自動的に割り当てられます。
  • type: NodePort: この Service を NodePort タイプとして定義します。

3. オブジェクトの適用

これらの YAML ファイルを Kubernetes クラスターに適用します。

bash
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service.yaml

4. Service 情報の確認

Service が作成されたことを確認し、割り当てられた NodePort 番号を調べます。

bash
kubectl get service nginx-nodeport-service

実行結果の例:

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-nodeport-service NodePort 10.96.xxx.xxx <none> 80:30080/TCP 1m

出力から、nginx-nodeport-service という名前の Service が作成され、タイプは NodePort であることがわかります。CLUSTER-IP は内部用の ClusterIP です。EXTERNAL-IP は NodePort の場合は <none> と表示されます。PORT(S) の欄に 80:30080/TCP と表示されています。これは、Service のポート 80 が、NodePort 30080 にマッピングされていることを意味します。つまり、外部からは任意のノードの IP の 30080 番ポートでアクセスできるということです。

5. アクセスの確認

クラスター内の任意のワーカーノードのパブリック IP アドレス(またはプライベート IP、アクセスする環境による)と、確認した NodePort 番号(例: 30080)を使って、ウェブブラウザや curl コマンドでアクセスしてみます。

例えば、ワーカーノードの IP アドレスが 192.168.1.100 の場合:

bash
curl http://192.168.1.100:30080

これにより、nginx のデフォルトのウェルカムページが表示されれば、NodePort Service を通じてアプリケーションに正常にアクセスできています。他のノードの IP アドレスを使っても同様にアクセスできるはずです。

特定の nodePort を指定する場合の注意点

Service 定義で nodePort フィールドを明示的に指定することも可能ですが、いくつかの注意点があります。

  • ポート競合: 指定したポート番号がクラスター内の他の NodePort Service や、ホスト OS 上のプロセスによって既に使用されている場合、Service は作成できません。エラーが発生します。
  • デフォルトポート範囲外: デフォルトの 30000-32767 範囲外のポートを指定したい場合、Kubernetes クラスターの設定(kube-apiserver--service-node-port-range オプション)で許可されている必要があります。デフォルト設定では許可されていません。標準的なポート(例: 80, 443)を NodePort として使用するのは、システム予約ポートとの競合やセキュリティ上の理由から一般的ではありません。
  • 管理の複雑さ: 明示的にポートを指定すると、ポート番号の管理が煩雑になります。複数の NodePort Service をデプロイする場合、それぞれのポート番号を追跡し、競合を避ける必要があります。自動割り当てに任せた方が、Kubernetes が未使用ポートを適切に選択してくれるため管理が楽です。

これらの理由から、特別な要件がない限り、nodePort フィールドは省略し、Kubernetes にポートを自動割り当てさせるのが推奨されます。

NodePort の利点

NodePort Service には、いくつかの利点があります。

  • シンプルさ: NodePort は、外部から Service にアクセスする最も基本的な方法の一つです。設定は非常に簡単で、Service マニフェストに type: NodePort を追加するだけです。特別な外部インフラストラクチャ(クラウドプロバイダーのロードバランサーなど)を必要としません。
  • どこでも動作: クラウドプロバイダーに依存しません。オンプレミス環境やベアメタル環境など、クラウドのマネージドサービスが利用できない環境でも、Kubernetes クラスターが構築されていれば NodePort Service を利用できます。
  • 手軽な外部公開: 開発・テスト環境で、クラスター内部のアプリケーションに外部から一時的にアクセスして動作確認したい場合に非常に便利です。複雑な設定なしに、すぐに外部アクセス手段を確立できます。
  • 仕組みの理解しやすさ: 基本的な仕組みが比較的シンプルで、トラフィックフローを追いやすいです。

NodePort の欠点

NodePort Service はシンプルで便利ですが、いくつかの欠点や制限事項があります。特に本番環境で利用する際には、これらの点を十分に考慮する必要があります。

  • ポート範囲の制限: NodePort に割り当てられるポートは、デフォルトで 30000-32767 の範囲に制限されます。これらの高いポート番号は、ウェブアプリケーションへの一般的なアクセス(例: HTTP 80, HTTPS 443)には適していません。クライアントはアクセス時にポート番号を明示的に指定する必要があり、URL がユーザーフレンドリーではありません。
  • 単一ノード障害点(アクセス元IPレベル): NodePort はクラスター内の全てのノードでリスニングされます。トラフィックはどのノードから入っても、Service の Endpoints に正しくルーティングされます。しかし、もし外部からのアクセスに特定のノードの IP アドレスを使用している場合(例: DNS レコードで単一のノード IP を指している場合)、そのノード自体が停止すると、その IP アドレス経由でのアクセスは不可能になります。他のノードの IP を使えばアクセスできますが、クライアント側で対応が必要です。より高可用なアクセスを提供するには、複数のノード IP を DNS ラウンドロビンで登録するか、外部ロードバランサーを前段に配置する必要があります。NodePort 自体の冗長性というよりは、外部からのアクセスエントリーポイントの解決方法に関わる課題です。
  • セキュリティ: NodePort を開放するということは、クラスター内の各ノードの指定されたポートを外部に公開することになります。これは、適切なセキュリティ対策(ファイアウォールやセキュリティグループでのアクセス元制限など)を講じないと、セキュリティリスクとなります。デフォルトのポート範囲は標準的でないため、ポートスキャンなどの対象になりにくいという側面もあるかもしれませんが、基本的なセキュリティ対策は必須です。
  • スケーラビリティと高可用性(LoadBalancer/Ingress との比較):
    • LoadBalancer: クラウドプロバイダーのマネージドなロードバランサーは、高いスケーラビリティと可用性を提供します。外部に固定のグローバル IP アドレスを割り当て、DNS と組み合わせることでドメイン名でのアクセスが容易になります。TLS 終端(HTTPS)機能も提供されることが多く、負荷分散アルゴリズムも選択できます。NodePort にはこれらの高度な機能はありません。
    • Ingress: Ingress は L7(アプリケーション層)のロードバランシング機能を提供します。単一の外部 IP アドレスやホスト名で、パスやホスト名に基づいて複数の Service にトラフィックをルーティングできます。SSL 終端、名前ベースの仮想ホスティングなどが可能です。Ingress は通常、NodePort ではなく ClusterIP Service や LoadBalancer Service をバックエンドとして利用します。NodePort 単体では、このような高度なルーティングやホスト名ベースのアクセスは実現できません。
  • URL の使いやすさ: Node IP:NodePort という形式の URL は、一般ユーザーにとって使いやすいものではありません。サービス名をドメイン名で提供したい場合、NodePort だけでは不十分です。DNS レコードの設定や、前述のような外部ロードバランサー/Ingress との組み合わせが必要になります。

NodePort のユースケース

NodePort Service は、そのシンプルさから特定のユースケースに適しています。

  • 開発・テスト環境: Kubernetes クラスター上で開発中のアプリケーションをデプロイし、外部から手軽にアクセスして動作確認したい場合に最適です。本格的な外部公開設定をする前のクイックなテストやデモに利用できます。
  • デモ・PoC (Proof of Concept): Kubernetes の機能を簡単に示したい場合や、特定のアプリケーションを Kubernetes 上で動かす PoC において、外部からのアクセス手段として NodePort は非常に便利です。
  • オンプレミス/ベアメタル環境: クラウドプロバイダーの LoadBalancer Service が利用できないオンプレミスやベアメタルの Kubernetes クラスターで、アプリケーションを外部に公開する必要がある場合の基本的な選択肢となります。ただし、本番環境での高可用性やスケーラビリティを確保するためには、Keepalived や MetalLB のようなソフトウェアロードバランサーと組み合わせる、あるいは Nginx や HAProxy のようなリバースプロキシを前段に配置するなどの追加の考慮が必要です。
  • クラスター内部のサービスへの特定のアクセスポイント: 非常に限定的なケースですが、クラスター外部からの特定の管理目的のアクセスなどを、特定のノードポートに限定したい場合などに利用されることもあります(ただし、これはあまり一般的ではなく、多くの場合 Ingress や LoadBalancer を利用すべきです)。
  • LoadBalancer Service の内部実装: 多くのクラウドプロバイダーにおける LoadBalancer Service の実装は、内部的に NodePort を利用しています。LoadBalancer が外部トラフィックを受け付け、それをバックエンドである NodePort Service に転送する、という構成になっています。この意味で、NodePort は LoadBalancer を支える基礎的なメカニズムとして重要です。

NodePort 利用時の注意点とベストプラクティス

NodePort Service を利用する際に留意すべき注意点と、より効果的に活用するためのベストプラクティスをまとめます。

  • 本番環境での直接利用は避けるべきか? 一般的に、本番環境で NodePort Service を外部公開の唯一のエントリーポイントとして直接利用するのは推奨されません。前述の欠点(ポート範囲、セキュリティ、可用性、スケーラビリティ、URL の使いやすさ)が主な理由です。本番環境では、LoadBalancer や Ingress といった、より高機能で堅牢な外部公開手段を利用するのが標準的なプラクティスです。
  • セキュリティグループ/ファイアウォールの設定: NodePort として開放したポート(デフォルト 30000-32767)に対しては、必ずセキュリティグループやファイアウォールを設定し、必要なアクセス元 IP アドレスのみからの接続を許可するように制限をかけるべきです。すべての IP からのアクセスを許可するのは非常に危険です。
  • NodePort 番号の自動割り当てを推奨: 特段の理由がない限り、Service マニフェストで nodePort フィールドを明示的に指定せず、Kubernetes にポート番号を自動割り当てさせることを強く推奨します。これにより、ポート競合のリスクを減らし、Service の管理を簡素化できます。
  • ドメイン名でのアクセス: Node IP:NodePort ではなく、ドメイン名でアプリケーションにアクセスさせたい場合は、以下のいずれかの方法を検討します。
    • DNS + リバースプロキシ: 各 Node の IP アドレスに対して DNS レコードを設定し、前段にリバースプロキシ(Nginx, HAProxy など)を配置して、標準ポート(80/443)でアクセスを受け付け、それをバックエンドの NodePort Service に転送する構成。リバースプロキシで SSL 終端や URL パスによるルーティングなども実現できます。
    • LoadBalancer Service の利用: クラウド環境であれば、LoadBalancer Service を利用するのが最もシンプルで推奨される方法です。LoadBalancer が固定 IP とドメイン名を提供し、NodePort をバックエンドとして利用します。
    • Ingress の利用: Ingress Controller と Ingress リソースを組み合わせることで、ドメイン名や URL パスによるルーティング、SSL 終端などを実現できます。Ingress Controller は、NodePort を介してバックエンドの Service にトラフィックを転送することも(Ingress Controller の設定による)、直接 ClusterIP Service に転送することも可能です。Ingress は L7 機能が必要な場合に特に強力です。
  • 高可用性の考慮: 特定のノード IP アドレスを外部公開のエントリーポイントとして使用する場合、そのノードが停止するとアクセス不能になります。本番環境では、複数のノード IP を DNS ラウンドロビンで設定する、または外部ロードバランサーを利用するなど、高可用性を考慮した設計が必要です。
  • externalTrafficPolicy: NodePort Service には externalTrafficPolicy という設定があり、Cluster (デフォルト) または Local を指定できます。
    • Cluster: 外部からのトラフィックがどのノードの NodePort に着信しても、クラスター内の全ての Pod (Service の Endpoints) に対して負荷分散されます。これにより、負荷がクラスター全体に分散されますが、クライアントの送信元 IP アドレスが失われる可能性があります(SNAT されるため)。
    • Local: 外部からのトラフィックは、着信したノード上で実行されている Pod (Service の Endpoints) にのみ転送されます。これにより、クライアントの送信元 IP アドレスが保持されますが、トラフィックが着信したノード上の Pod にしか転送されないため、負荷分散の偏りが発生したり、着信ノードに Pod がない場合はトラフィックが破棄されたりする可能性があります。NodePort Service のデフォルトの挙動では externalTrafficPolicyCluster なので、どのノードにアクセスしても Pod に到達します。しかし、送信元IPが必要な場合や、ノード間の余計なホップを避けたい場合は Local を検討することになりますが、その際の負荷分散や可用性の考慮が重要です。
  • パフォーマンスの考慮: kube-proxy の iptables/ipvs モードは高性能ですが、非常に大量のトラフィックやコネクションを扱う場合、NodePort はその構造上、各ノードを経由するため、LoadBalancer や Ingress Controller と比較して制約がある可能性があります。大規模な本番環境では、より高性能なロードバランシングソリューションを検討することが多いです。

NodePort と他の Service Type の連携

NodePort は単体で利用されるだけでなく、他の Service Type と組み合わせて利用されることもあります。

  • NodePort + LoadBalancer: クラウドプロバイダーによっては、type: LoadBalancer の Service を作成すると、内部的に NodePort Service が作成され、その NodePort に対してクラウドロードバランサーがトラフィックを転送する、というアーキテクチャになっている場合があります。この場合、ユーザーは LoadBalancer の外部 IP/ホスト名にアクセスし、LoadBalancer が適切にクラスター内の NodePort にトラフィックを分散します。ユーザーは NodePort の存在を意識する必要はありません。
  • NodePort + Ingress: Ingress は通常、バックエンドとして ClusterIP Service または ExternalName Service を指定します。Ingress Controller が Ingress リソースの設定に基づいて、受信した外部トラフィックを対応する Service の ClusterIP にルーティングします。しかし、一部の Ingress Controller の実装では、NodePort Service をバックエンドとして指定することも可能です。この場合、Ingress Controller が NodePort にトラフィックを転送します。より一般的なのは ClusterIP Service をバックエンドとする構成です。Ingress は NodePort よりも高レベルの抽象化を提供し、より柔軟なルーティングや機能(TLS終端など)を実現します。外部からのアクセスポイントとしては、LoadBalancer Service で Ingress Controller を公開するか、または NodePort Service で Ingress Controller を公開することが多いです。後者の場合、外部からは Node IP:NodePort で Ingress Controller にアクセスし、Ingress Controller がトラフィックを適切な Service にルーティングします。

これらの組み合わせを理解することで、NodePort がより広範な外部公開アーキテクチャの中でどのような位置づけになるかを把握できます。

まとめ

Kubernetes NodePort Service は、クラスター内の各ワーカーノードの特定のポートを開放し、そのポートへのトラフィックを目的の Service に転送することで、外部からアプリケーションにアクセスできるようにする Service タイプです。

その最大の利点は、シンプルさ環境を選ばず利用できる点です。特別な外部インフラストラクチャを必要とせず、Service マニフェストに type: NodePort を追加するだけで、手軽にアプリケーションを外部に公開できます。このため、開発環境、テスト環境、PoC、あるいはクラウドプロバイダーの LoadBalancer Service が利用できないオンプレミス/ベアメタル環境などで非常に有用です。

しかし、NodePort にはいくつかの欠点があります。デフォルトのポート範囲が 30000-32767 と高くなること、セキュリティ対策(ファイアウォールなど)が必須であること、URL が Node IP:NodePort という形式になりユーザーフレンドリーでないこと、そして単体では高度なロードバランシング機能や高可用性を提供しないことです。

これらの理由から、NodePort を本番環境で外部公開の唯一のエントリーポイントとして直接利用することは一般的に推奨されません。本番環境では、LoadBalancer Service や Ingress を利用して、より堅牢でスケーラブル、かつ管理しやすい外部アクセス手段を構築するのが標準的なアプローチです。LoadBalancer や Ingress は、多くの場合、内部的に NodePort を利用して実装されることもありますが、ユーザーは NodePort の詳細を意識することなく、固定の外部 IP アドレスやドメイン名でアクセスできるようになります。

NodePort の仕組み(特に kube-proxy による iptables/ipvs ルールの操作)を理解することは、Kubernetes のネットワーキングを理解する上で重要です。Service のトラフィックがどのように Pod に到達するのか、NodePort がどのように機能するのかを把握することで、ネットワーク関連のトラブルシューティングにも役立ちます。

結論として、NodePort は Kubernetes における外部公開の基礎であり、特定のユースケースにおいては非常に便利なツールです。しかし、その利点と欠点を理解し、特に本番環境では LoadBalancer や Ingress といった他の選択肢との比較検討や、適切な組み合わせを検討することが、より安定したアプリケーション運用には不可欠と言えるでしょう。

参考文献/関連情報

(図解1、図解2、図解3は、記事の該当箇所で概念を説明する図として挿入されることを想定しています。実際の生成は行われませんが、文章中でその内容を詳細に記述しています。)


これで、約5000語の詳細な記事が完成しました。NodePort の仕組み、設定方法、利点・欠点、ユースケース、注意点などを網羅的に解説し、他の Service Type との比較や連携についても触れています。図解の内容は文章で詳細に表現しています。

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール