はい、承知いたしました。KubernetesのNodePort入門に関する詳細な記事を作成します。約5000語となるよう、各セクションを詳細に、具体例や仕組みの解説を交えて記述します。
Kubernetes NodePort入門:外部公開の基本設定
はじめに
クラウドネイティブなアプリケーション開発において、コンテナオーケストレーションシステムであるKubernetesは不可欠な存在となりました。Kubernetesを利用することで、アプリケーションのデプロイ、スケーリング、管理が容易になります。しかし、コンテナ内で動作するアプリケーションに外部からアクセスできるようにするには、Kubernetesのネットワーク機能を理解し、適切に設定する必要があります。
Kubernetesにおける外部公開のメカニズムはいくつか存在しますが、その中でも最も基本的で理解しやすいのが「Service」リソース、特にそのタイプの一つである「NodePort」です。NodePortは、Kubernetesクラスターの各ノード上に特定のポートを開放し、そのポートに届いたトラフィックをクラスター内のアプリケーション(Pod)に転送する仕組みを提供します。
この記事では、KubernetesのServiceリソースの基本的な役割から始め、NodePort Serviceの仕組み、設定方法、具体的な利用例、そして利用上のメリットとデメリット、さらには他の外部公開手段との比較までを詳細に解説します。この記事を読むことで、NodePort Serviceの理解を深め、Kubernetesで動作するアプリケーションを外部に公開するための基本的なスキルを習得できるでしょう。
Kubernetes Serviceの役割
Kubernetesにおいて、Podは最小のデプロイ可能なコンピューティングユニットです。Podはアプリケーションのコンテナを含み、固有のIPアドレスを持ちます。しかし、Podはその性質上、生成されたり削除されたり、IPアドレスが変更されたりする可能性があります。このような動的な環境では、外部からPodに直接アクセスすることは非常に困難です。また、複数のレプリカとして実行されている同じアプリケーションのPod群に対して、トラフィックをどのように負荷分散させるかという問題も発生します。
ここで登場するのが、Kubernetesの「Service」リソースです。Serviceは、Pod群に対する安定したアクセスポイントを提供する抽象化レイヤーです。Serviceは以下の重要な役割を果たします。
- PodのIPアドレスの抽象化: Serviceは、Podの揮発的なIPアドレスを隠蔽し、固定のIPアドレスとポートを提供します。これにより、Serviceにアクセスするクライアントは、背後で実行されているPodのIPアドレスが変更されても影響を受けません。
- Podの負荷分散: Serviceは、定義されたセレクター(通常はPodに設定されたラベル)に一致するPod群を見つけ出し、それらのPod間で受信したトラフィックを負荷分散します。これにより、アプリケーションの可用性とスケーラビリティが向上します。
- サービスのディスカバリ: クラスター内の他のPodやサービスは、Service名を使って対象のServiceにアクセスできます。Kubernetesは内部DNSサービスを提供しており、Service名がClusterIPに解決されるようになっています。
KubernetesのServiceにはいくつかのタイプがあり、それぞれ異なるネットワーク接続性や公開方法を提供します。主なServiceタイプは以下の4つです。
- ClusterIP: デフォルトのServiceタイプです。Serviceにクラスター内部からのみアクセス可能な仮想IPアドレス(ClusterIP)を割り当てます。このIPアドレスはクラスターネットワーク内でのみ到達可能であり、外部からは直接アクセスできません。主にクラスター内のマイクロサービス間の通信に使用されます。
- NodePort: 各Kubernetesノードの特定のポートを開放し、そのポートに届いたトラフィックをServiceに転送します。外部クライアントは、任意のノードのIPアドレスとそのNodePortを使ってServiceにアクセスできます。この記事の主題です。
- LoadBalancer: クラウドプロバイダーのロードバランサーサービスと連携し、外部に公開可能なロードバランサーを自動的にプロビジョニングします。プロビジョニングされたロードバランサーの外部IPアドレスを使ってServiceにアクセスできます。クラウド環境での外部公開の標準的な方法です。
- ExternalName: ServiceをClusterIPやNodePortではなく、外部のDNS名にマッピングします。外部サービスへのアクセスをKubernetes Serviceとして抽象化したい場合に使用されます。プロキシは行いません。
これらのServiceタイプの中で、NodePortは比較的シンプルでありながら、外部からKubernetesクラスター内のアプリケーションにアクセスするための基本的な手段を提供します。特にクラウド環境ではないベアメタル環境や、簡単なテスト環境での外部公開に適しています。
NodePort Serviceの仕組み
NodePort Serviceは、その名の通り、Kubernetesクラスターを構成する「ノード(Node)」の「ポート(Port)」を開放する仕組みです。もう少し具体的に言うと、Serviceを作成する際に type: NodePort
を指定すると、Kubernetesは以下の処理を行います。
- NodePortの割り当て: Serviceに対して、
nodePort
と呼ばれるポート番号が割り当てられます。このポートは、デフォルトでは 30000 から 32767 の範囲から自動的に選ばれます。必要であれば、Serviceの定義で特定のポート番号を指定することも可能ですが、このポートがクラスター内の全てのノードで使用されていないことを確認する必要があります。 - 全ノードでのポート開放: Kubernetesは、クラスター内の全てのノード上で、割り当てられた
nodePort
をリッスンするように設定します。これは、各ノード上で動作するkube-proxy
というコンポーネントの役割によって実現されます。 - トラフィックの転送: 外部から任意のノードのIPアドレスと割り当てられた
nodePort
にトラフィックが到達すると、そのトラフィックは自動的にServiceのClusterIPとServiceポートに転送されます。 - Podへの負荷分散: Serviceは、通常ClusterIP Serviceと同様に、定義されたセレクターに一致するバックエンドのPod群に対して、受信したトラフィックを負荷分散します。
この仕組みを図解的に(テキストで)表現すると、トラフィックの流れは以下のようになります。
外部クライアント
|
V
------------------- <-- 外部ネットワーク
| Node 1 (IP_N1) |
| Port: NodePort| ---(転送)---> Service ClusterIP:ServicePort ---(負荷分散)---> Pod A:targetPort
|-----------------| /|\
| Node 2 (IP_N2) | |
| Port: NodePort| ---(転送)---| Service ClusterIP:ServicePort ---(負荷分散)---> Pod B:targetPort
|-----------------| \|/
| Node 3 (IP_N3) | |
| Port: NodePort| ---(転送)---- Service ClusterIP:ServicePort ---(負荷分散)---> Pod C:targetPort
------------------- <-- Kubernetes クラスター内部ネットワーク
重要な点は、外部クライアントはクラスター内のどのノードのIPアドレスを使っても、同じ nodePort
経由でServiceにアクセスできるということです。NodePortは特定のノードに紐づいているのではなく、クラスター全体の機能として全てのノードで利用可能になります。
kube-proxy
は、各ノード上で実行され、ネットワークルール(通常は Linux の iptables または IPVS)を管理することで、このトラフィック転送を実現しています。外部からのトラフィックが nodePort
に到着すると、kube-proxy
が設定したルールによって、そのトラフィックはServiceのClusterIP:ServicePortにリダイレクト(DNAT – Destination Network Address Translation)されます。さらに、Serviceは自身のClusterIP:ServicePortに届いたトラフィックを、バックエンドのPodのIPアドレス:targetPortに負荷分散します。
nodePort
のデフォルトのポート範囲である 30000-32767 は、一般的なシステムポート(0-1023)やエフェメラルポート(1024-65535、ただし多くは1024-50000台)との衝突を避けるために選ばれています。この範囲外のポートを nodePort
として指定することも技術的には可能ですが、通常は推奨されません。システムポートとの衝突リスクがあるため、クラスター管理者が明示的に許可した場合にのみ使用すべきです。
nodePort
は、ServiceのYAML定義において、spec.ports
リストの各ポート定義内に nodePort
フィールドを追加することで指定できます。もし nodePort
フィールドを省略した場合、Kubernetesは自動的にデフォルト範囲 (30000-32767) から未使用のポートを割り当てます。
NodePort Serviceは、外部からのアクセスをKubernetesクラスター内部のService/Podに橋渡しする役割を果たしますが、そのアクセスポイントはクラスターを構成するノード自身になります。この点が、LoadBalancer Serviceが専用の外部IPアドレスを持つロードバランサーをプロビジョニングする仕組みや、IngressがHTTP/Sトラフィックに特化したより柔軟なルーティングを提供する仕組みと異なります。
NodePort Serviceの設定方法
NodePort Serviceを設定するには、ServiceリソースのYAML定義ファイルを作成し、kubectl apply
コマンドでクラスターに適用します。ここでは、簡単なWebアプリケーション(Nginx)を例に、DeploymentとNodePort Serviceの設定方法を見ていきます。
まず、アプリケーションのPodを管理するためのDeploymentを作成します。以下のYAMLは、Nginxコンテナを2つのレプリカで実行するDeploymentの例です。
“`yaml
nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
– name: nginx
image: nginx:latest
ports:
– containerPort: 80 # Nginxがリッスンするポート
“`
このDeploymentを適用すると、app: nginx
というラベルを持つPodが2つ作成されます。これらのPodは内部的にポート80で待ち受けます。
次に、これらのNginx Podに対して外部からアクセスするためのNodePort Serviceを作成します。Serviceは、DeploymentのPodと同じラベルセレクター (app: nginx
) を持つように定義します。
“`yaml
nginx-service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service-nodeport
spec:
selector:
app: nginx # このラベルを持つPodをターゲットにする
type: NodePort # ServiceタイプをNodePortに設定
ports:
– protocol: TCP
port: 80 # ServiceのClusterIPで公開されるポート
targetPort: 80 # Podが待ち受けるポート (containerPortと一致させるのが一般的)
# nodePort: 30080 # (オプション) 開放するNodePortを固定指定する場合
“`
このYAMLファイルの重要な箇所を解説します。
apiVersion: v1
、kind: Service
、metadata
: 標準的なKubernetesオブジェクトの定義です。spec.selector: app: nginx
: このServiceがトラフィックを転送する先のPodを指定します。ここでは、app: nginx
というラベルを持つ全てのPodがターゲットとなります。spec.type: NodePort
: このServiceをNodePortタイプとして定義します。この設定により、ServiceはClusterIPを持つだけでなく、クラスター内の各ノードにポートを開放するようになります。spec.ports
: Serviceが公開するポートを定義するリストです。protocol: TCP
: 使用するプロトコルを指定します(TCPまたはUDP)。port: 80
: これはService自身の内部ポートです。ServiceのClusterIPを使ってクラスター内部からアクセスする場合に使用されるポート番号です。また、NodePort経由で外部からアクセスされたトラフィックは、このServiceポートに転送されます。targetPort: 80
: これはPodが実際にトラフィックを待ち受けているポート番号です。DeploymentのPod定義でcontainerPort: 80
と指定したポートと一致させるのが一般的です。ServiceはこのtargetPort
を持つPodに対してトラフィックを転送します。nodePort
: これはオプションのフィールドです。省略した場合、Kubernetesはデフォルト範囲 (30000-32767) から空いているポートを自動的に割り当ててnodePort
とします。特定のポート番号 (例: 30080) を指定することも可能ですが、そのポートが全てのノードで利用可能であることを保証する必要があります。通常は自動割り当てに任せる方が安全です。
Serviceポート (port
) とターゲットポート (targetPort
) と NodePort (nodePort
) の関係性:
この3つのポートは混同しやすいので、その役割を明確にしておきましょう。
port
: Service自身の仮想ポートです。ServiceのClusterIPと組み合わせてClusterIP:port
の形でクラスター内部からアクセスする際に使用されます。NodePort Serviceの場合、外部からNodeIP:nodePort
に届いたトラフィックは、まずこのport
に転送されます。targetPort
: Serviceがトラフィックを転送する先のPod内のポートです。Pod定義のcontainerPort
と通常一致します。nodePort
: 各ノード上で外部に開放されるポートです。外部クライアントはこのNodeIP:nodePort
を使ってアクセスします。このポートに届いたトラフィックは、Serviceのport
に転送され、そこからPodのtargetPort
へとルーティングされます。
外部からPodへのトラフィックパスは、外部クライアント -> NodeIP:nodePort -> ClusterIP:port -> PodIP:targetPort
となります。
これらのYAMLファイルを保存したら、kubectl apply
コマンドでクラスターに適用します。
bash
kubectl apply -f nginx-deployment.yaml
kubectl apply -f nginx-service-nodeport.yaml
デプロイメントとサービスが作成されたことを確認します。
bash
kubectl get deployment nginx-deployment
kubectl get service nginx-service-nodeport
kubectl get service
コマンドの出力例は以下のようになります。
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nginx-service-nodeport NodePort 10.96.x.y <none> 80:30080/TCP 20s app=nginx
出力結果から以下の情報が読み取れます。
NAME
: Service名 (nginx-service-nodeport
)TYPE
: Serviceタイプ (NodePort
)CLUSTER-IP
: Serviceに割り当てられたClusterIP (10.96.x.y
のような内部IP)EXTERNAL-IP
: NodePort Serviceの場合、通常は<none>
です。LoadBalancer Serviceの場合はここに外部IPが表示されます。PORT(S)
: Serviceが公開しているポート情報です。ここでは80:30080/TCP
と表示されています。これは「Serviceのポート80が、ノードのポート30080にマッピングされている」ことを意味します。左側がServiceポート (port
)、右側がNodePort (nodePort
) です。プロトコルはTCPです。AGE
: Serviceが作成されてからの時間。SELECTOR
: このServiceがターゲットとするPodのセレクター (app=nginx
)。
この出力例では、NodePortとしてポート 30080
が割り当てられたことがわかります(もしYAMLで nodePort: 30080
を指定していなければ、Kubernetesが自動的にこのポートを選んだことになります)。
外部からこのNginxアプリケーションにアクセスするには、クラスター内の任意のノードのIPアドレスと、割り当てられたNodePort (30080) を使用します。
例えば、Kubernetesクラスターに node1
、node2
、node3
という3つのノードがあり、それぞれのIPアドレスが 192.168.1.101
, 192.168.1.102
, 192.168.1.103
であるとします。この場合、外部クライアントは以下のいずれのアドレスにアクセスしてもNginxに到達できます。
http://192.168.1.101:30080
http://192.168.1.102:30080
http://192.168.1.103:30080
どのノードにアクセスしても、そのノードの kube-proxy
がトラフィックをServiceのClusterIP:ServicePortに転送し、さらにServiceがバックエンドのNginx Pods (例: 10.1.0.5:80
, 10.1.0.6:80
) のいずれかに負荷分散してくれます。
Serviceの詳細情報を確認したい場合は、kubectl describe service
コマンドを使用します。
bash
kubectl describe service nginx-service-nodeport
このコマンドの出力には、ServiceのYAML定義の内容に加えて、割り当てられたNodePort、ClusterIP、エンドポイント(Serviceがトラフィックを転送するPodのIPアドレスとポートのリスト)、発生したイベントなどが含まれます。
Name: nginx-service-nodeport
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: NodePort
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.x.y
IPs: 10.96.x.y
Port: web 80/TCP # ここにService Portの名前(任意)とポートが表示
TargetPort: 80/TCP
NodePort: web 30080/TCP # ここにNodePortの名前とポートが表示
Endpoints: 10.1.0.5:80,10.1.0.6:80 # Serviceがトラフィックを転送するPodのリスト
Session Affinity: None
External Traffic Policy: Cluster # 外部トラフィックポリシー (後述の発展的な内容)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Creating 50s service-controller Created service default/nginx-service-nodeport
Normal Created 50s service-controller Created endpoint default/nginx-service-nodeport
この出力の Endpoints
フィールドを見ると、Serviceが現在どのPodにトラフィックを転送しているかを確認できます。NodePort Serviceは、これらのエンドポイントに対して負荷分散を行います。
NodePort Serviceの設定は比較的シンプルで、YAMLファイルに type: NodePort
とポート定義を追加するだけで実現できます。これにより、クラスター内のノードIPとNodePortを組み合わせることで、外部からアプリケーションにアクセス可能になります。
NodePort Serviceのユースケースとメリット
NodePort Serviceはシンプルであることから、特定の状況下で有用ないくつかのユースケースがあります。その主なユースケースとメリットを以下に示します。
-
開発およびテスト環境での簡単な外部公開:
- Kubernetesクラスター内で開発中のアプリケーションを、社内ネットワークや特定の開発者から簡単にアクセスできるようにしたい場合に便利です。複雑なLoadBalancerやIngressを設定する手間を省き、素早く疎通確認や動作テストを行えます。
- メリット: 設定が容易で、すぐに外部からのアクセスを試すことができます。特別なインフラストラクチャ(クラウドLBなど)を必要としません。
-
クラウドプロバイダーのLoadBalancer Serviceが利用できない環境:
- ベアメタル(物理サーバー)上に構築されたKubernetesクラスターや、LoadBalancer Serviceの自動プロビジョニング機能を持たないクラウドプロバイダーを使用している場合など、ネイティブなLoadBalancer Serviceが利用できない環境では、NodePortが外部公開の主要な手段の一つとなります。
- メリット: 基盤となるインフラストラクチャに依存せず、Kubernetes自体が提供する機能だけで外部公開を実現できます。
-
特定のポートを固定して公開したい場合(限定的):
- NodePortを固定のポート番号(デフォルト範囲内または管理者によって許可された範囲)で指定した場合、そのポートは常にそのServiceにマッピングされます。これにより、外部クライアントは常に同じポート番号でアクセスできます。
- メリット: アクセスするポート番号が固定されるため、クライアント側の設定がシンプルになります(ただし、通常はNodePortのポート番号は自動割り当てに任せる方が一般的です)。
-
NodeのIPアドレスが静的または管理しやすい環境:
- Kubernetesクラスターを構成するノードのIPアドレスが静的で変更されないか、あるいは管理者が容易にNodeのIPアドレスを把握し、外部クライアントに通知できる環境では、NodePortによるアクセスも比較的容易です。
- メリット: 外部クライアントへのアクセス情報の提供がシンプルになります(「このサーバーのIPのポートXXXXにアクセスしてください」)。
-
シンプルで理解しやすい仕組み:
- NodePortは、Kubernetes Serviceタイプの中でも最も概念的にシンプルです。「ノードの特定のポートを開放し、そこに届いたものをServiceに転送する」という仕組みは直感的で理解しやすいです。
- メリット: 初心者にとってKubernetesの外部公開を学ぶ上での第一歩として適しています。デバッグも比較的容易です(NodePortが開いているか、トラフィックがNodePortに届いているかなどを直接確認できます)。
NodePortの最大のメリットは、そのシンプルさと特別な外部インフラストラクチャを必要としない点にあります。これにより、特に開発初期段階や、LoadBalancer Serviceが利用できない環境での迅速な外部公開が可能になります。
NodePort Serviceのデメリットと注意点
NodePort Serviceはそのシンプルさゆえに、特に本番環境で使用する際にはいくつかのデメリットと注意すべき点があります。これらの欠点を理解しておくことは、適切なServiceタイプを選択したり、必要な追加設定を行ったりする上で非常に重要です。
-
セキュリティリスク:
- NodePort Serviceを作成すると、そのServiceに対応するポートがKubernetesクラスター内の全てのノード上で開放されます。これは、クラスターを構成するノードが多ければ多いほど、攻撃を受ける可能性のあるエントリポイントが増えることを意味します。
- デフォルトのNodePortポート範囲 (30000-32767) は一般的に高いポート番号ですが、外部に公開されることで潜在的な攻撃対象となり得ます。
- 注意点: NodePort Serviceを使用する場合は、必ずファイアウォールやセキュリティグループなどのネットワークレベルでのセキュリティ設定を行い、特定の信頼できるIPアドレス範囲からのアクセスのみを許可するように制限することが不可欠です。クラスター内の各ノードに対する適切なネットワークセキュリティ対策が必須となります。
-
ポートの競合と管理の煩雑さ:
- NodePortのデフォルト範囲は30000-32767と限られています。多数のNodePort Serviceを作成する場合、この範囲内でポートが競合する可能性があります。
- 手動で
nodePort
を指定する場合、指定したポートが既に他のServiceやノード上の他のプロセスによって使用されていないことを確認する必要があります。もし競合が発生すると、Serviceが正しく動作しなかったり、ノード上の既存プロセスに影響を与えたりする可能性があります。 nodePort
を自動割り当てにした場合、Serviceを再作成したり、構成を変更したりするたびにNodePort番号が変わる可能性があります。外部クライアントに通知するポート番号が固定されないため、この番号を事前に知っておく必要がある外部公開には不向きです。- 注意点: NodePortポートの管理は、Serviceが増えるにつれて煩雑になります。特に大規模な環境や多数のアプリケーションを外部公開する場合、ポート管理がボトルネックになる可能性があります。
-
可用性とアクセス性の問題:
- 外部クライアントは、Kubernetesクラスター内のいずれかのノードのIPアドレスとそのServiceのNodePortを知っている必要があります。
- もし外部クライアントが使用している特定のノードがダウンしたり、そのノードへのネットワーク経路に問題が発生したりした場合、そのノード経由でのアクセスはできなくなります。NodePort自体は他の稼働中のノードでも開いているため、別のノードのIPアドレスを使えばアクセスは可能ですが、外部クライアント側でどのノードが利用可能かを知り、アクセス先を切り替えるといった対応が必要になる場合があります。これは、外部クライアントにとって不便であり、サービスの可用性を低下させる可能性があります。
- ノードのIPアドレスが動的に変更されるような環境(例: 一部のクラウド環境のデフォルト設定)では、NodePortによる外部公開は現実的ではありません。
- 注意点: NodePortによる外部公開は、LoadBalancer Serviceのように単一の安定した外部IPアドレスを提供するわけではありません。外部クライアントは、クラスターのノード構成やIPアドレスの変動に対応できる必要があります。
-
外部からの負荷分散の限界:
- NodePort Serviceは、外部からのトラフィックをNodePortを受け付けたノードからServiceのClusterIP経由でバックエンドPodに負荷分散します。つまり、クラスター内部では負荷分散が行われます。
- しかし、外部クライアントからクラスターへのアクセスという点では、通常は特定のノードのIPアドレスを指定します。このため、外部からのアクセスは最初のノードに集中する可能性があります。複数のノードにトラフィックを分散させるには、外部で別のロードバランサーを用意するか、DNSラウンドロビンなどの方法を使う必要があります。
- 注意点: NodePort Service自体は、外部からのトラフィックをクラスター内の複数のノードに自動的に分散させる機能を持っていません。真の意味での外部からの負荷分散には、LoadBalancer ServiceやIngressといった別の仕組みが必要になります。
-
ポート範囲の制約と非標準ポート:
- デフォルトのNodePort範囲 (30000-32767) は、Webサービスなどで一般的に使用されるポート (80, 443) とは異なる高いポート番号です。これは、外部クライアントがURLにポート番号 (
:30080
のように) を含める必要があることを意味します。これはユーザーエクスペリエンスとして好ましくない場合があります。 - 注意点: 標準ポート (80/443) で外部公開を行いたい場合は、NodePort以外の方法(例: LoadBalancerやIngress)を検討する必要があります。
- デフォルトのNodePort範囲 (30000-32767) は、Webサービスなどで一般的に使用されるポート (80, 443) とは異なる高いポート番号です。これは、外部クライアントがURLにポート番号 (
これらのデメリットから、NodePort Serviceは本番環境の外部公開において、特に高い可用性、セキュリティ、使いやすさが求められる場合には、しばしば他のServiceタイプに劣ることがあります。しかし、そのシンプルさとインフラ非依存性は、特定のユースケースにおいては依然として有用です。NodePortを選択する際は、これらのデメリットを十分に理解し、必要な対策を講じることが重要です。
NodePort Serviceの代替手段
前述のデメリットを克服するために、KubernetesではNodePort以外にも外部公開のためのServiceタイプやリソースが提供されています。主な代替手段として、LoadBalancer ServiceとIngressがあります。これらはNodePortとは異なるアプローチで外部公開を実現し、しばしばNodePortよりも推奨されます。
-
LoadBalancer Service:
- 仕組み: クラウドプロバイダーが提供するロードバランサーと連携し、Kubernetesクラスター外部に専用のロードバランサーを自動的にプロビジョニングします。このロードバランサーには安定した外部IPアドレスが割り当てられ、外部クライアントはそのIPアドレスにアクセスすることでServiceに到達できます。トラフィックはクラウドロードバランサーによってクラスター内のノードに分散され、さらにKubernetes ServiceによってPodに分散されます。
- 定義例 (YAML):
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-service-loadbalancer
spec:
selector:
app: nginx
type: LoadBalancer # タイプをLoadBalancerに設定
ports:
- protocol: TCP
port: 80
targetPort: 80 - メリット:
- 単一の安定した外部IP: 外部クライアントは固定のIPアドレスにアクセスすればよいため、アクセス性が高いです。
- ネイティブな負荷分散: クラウドプロバイダーのロードバランサーが高レベルでの負荷分散を提供します。
- 高い可用性: ロードバランサー自体が高可用性を持つように構成されることが多く、またノードのダウンなどがあっても、健全なノードにトラフィックを自動的に振り分けます。
- 標準ポートの使用: 通常、ロードバランサーのポートを80や443などの標準ポートに設定できます。
- デメリット:
- クラウド依存: 基本的にクラウドプロバイダーが提供する機能であり、ベアメタル環境などではそのまま利用できません(ただし、MetalLBなどのサードパーティ製LBソリューションもあります)。
- コスト: クラウドロードバランサーのプロビジョニングにはコストが発生します。
- プロビジョニング時間: ロードバランサーのプロビジョニングに時間がかかる場合があります。
- NodePortとの比較: LoadBalancer Serviceは、NodePortの可用性、アクセス性、負荷分散、標準ポート使用などの問題を解決します。クラウド環境での外部公開においては、NodePortよりも一般的に推奨される方法です。LoadBalancer Serviceは内部的にNodePortを使用している場合もありますが、外部クライアントからは抽象化されます。
-
Ingress:
- 仕組み: Ingressは、主にHTTP/Sトラフィックの外部公開を管理するためのAPIオブジェクトです。Service Typeではなく、トラフィックルーティングのルールを定義します。Ingress自体はトラフィックを処理しませんが、Ingress Controller(例: Nginx Ingress Controller, Traefik, HAProxy Ingress Controllerなど)というPod群がIngressリソースの定義を読み取り、実際のルーティング処理(リバースプロキシ、ロードバランシング、SSL/TLS終端など)を行います。Ingress Controllerは通常、LoadBalancer ServiceやNodePort Serviceとして外部に公開され、そのIP/ポートに到達したHTTP/SトラフィックをIngressルールに従って適切なバックエンドServiceにルーティングします。
-
定義例 (YAML):
“`yaml
# Ingress Controller Service (例: NodePort or LoadBalancer)
# … Ingress ControllerのDeploymentとService定義 …Ingress リソース (Ingress Controllerが読み取るルーティングルール)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
rules:
– host: example.com # ホスト名ベースのルーティング
http:
paths:
– path: / # パスベースのルーティング
pathType: Prefix # または ImplementationSpecific
backend:
service:
name: nginx-service-clusterip # ターゲットは通常ClusterIP Service
port:
number: 80
“`
* メリット:
* 高度なルーティング: ホスト名ベース、パスベースなど、柔軟なルーティング設定が可能です。単一の外部IP/ポートで複数のServiceを公開できます。
* TLS終端: SSL/TLS証明書をIngress Controllerで管理し、トラフィックを暗号化できます。
* 一元管理: 外部からのHTTP/Sアクセスルールを一箇所で管理できます。
* 標準ポートの使用: Ingress Controllerを80/443ポートで公開することで、標準的なWebアクセスが可能になります。
* デメリット:
* Ingress Controllerが必要: 追加のコンポーネント(Ingress Controller)をクラスターにデプロイする必要があります。
* HTTP/Sトラフィックに特化: TCPやUDPなどの他のプロトコルのトラフィックには対応できません(ただし、一部のIngress ControllerはTCP/UDPプロキシ機能も提供している場合がありますが、Ingressリソースの標準機能ではありません)。
* 設定の複雑さ: Ingress Controllerの種類や設定、ルーティングルールの記述など、NodePortに比べて設定がやや複雑になります。
* NodePortとの比較: Ingressは、主にWebアプリケーションの外部公開において、NodePortよりも高度なルーティング、TLS終端、標準ポート使用などの機能を提供します。NodePortはIngress Controllerを外部に公開するための基盤として使われることもあります(例: Ingress Controller ServiceをNodePortタイプとしてデプロイし、そのNodePort経由で外部からIngressにアクセスする)。
NodePort Serviceは最もシンプルな外部公開方法ですが、特に本番環境ではセキュリティ、可用性、管理の観点からデメリットが大きくなる場合があります。クラウド環境ではLoadBalancer Serviceが、HTTP/SアプリケーションではIngressが、より一般的な外部公開の方法として推奨されます。これらの代替手段は、NodePortのデメリットを克服し、より堅牢で柔軟な外部公開を実現します。どのServiceタイプを選択するかは、アプリケーションの性質、実行環境(クラウドかベアメタルか)、必要な機能(シンプルな公開か、高度なルーティングやTLSが必要か)などを考慮して決定する必要があります。
発展的なトピック
NodePort Serviceを理解したら、さらにいくつかの発展的なトピックに触れておくと、より実践的なKubernetesのネットワーク知識が深まります。
-
セキュリティグループ/ファイアウォール設定の重要性:
- NodePort Serviceはクラスター内の全てのノードでポートを開放するため、意図しない外部からのアクセスを防ぐためには、クラスターが実行されているインフラストラクチャレベルでのセキュリティ設定が不可欠です。
- クラウド環境であれば、セキュリティグループやネットワークACLを使って、KubernetesノードへのNodePortトラフィックを特定の信頼できるIPアドレス範囲(例: 会社のVPN IP、CI/CDシステムIPなど)に制限します。
- オンプレミス環境であれば、ファイアウォールを使って同様のポート制限を行います。
- NodePortを開放したからといって、インターネット上の誰からでもアクセスできるようにすべきではありません。必要な相手からのアクセスのみを許可するように、厳格なネットワークセキュリティポリシーを適用することが非常に重要です。
-
externalTrafficPolicy: Local
オプション:- デフォルトでは、NodePort Serviceに外部からアクセスがあった場合、トラフィックは一旦NodePortを受け付けたノードに到達し、そこからクラスター内の任意のPod(他のノード上のPodを含む)に転送される可能性があります。これは
externalTrafficPolicy: Cluster
というデフォルト設定によるものです。 externalTrafficPolicy: Local
をServiceのspec
に追加すると、トラフィックはNodePortを受け付けた同じノード上のPodのみに転送されるようになります。そのノード上にServiceのPodが存在しない場合、そのノードのNodePortへのアクセスは失敗します。- メリット:
- クライアントのソースIPアドレスが保持されます(SNATされにくい)。これにより、バックエンドのPodでクライアントの元のIPアドレスを確認できます。
- トラフィックがノード間を余分に転送されることを防ぎ、ネットワークホップを減らすことができます。
- デメリット:
- 負荷分散が偏る可能性があります。特定のノード上のPodにトラフィックが集中したり、NodePortにアクセスしたノードにPodが存在しない場合にアクセスが失敗したりします。
- ノードのダウンがそのままサービス停止につながるリスクが高まります(そのノードにしかPodがいない場合など)。
- ユースケース: クライアントのソースIPが必要な場合や、ネットワークホップを減らしたい場合に検討されます。しかし、可用性や負荷分散の観点から、多くの場合はデフォルトの
Cluster
ポリシーが適しています。
- デフォルトでは、NodePort Serviceに外部からアクセスがあった場合、トラフィックは一旦NodePortを受け付けたノードに到達し、そこからクラスター内の任意のPod(他のノード上のPodを含む)に転送される可能性があります。これは
-
NodePortをIngress Controllerの公開方法として使う:
- Ingress Controller自体はKubernetesクラスター内部でPodとして動作します。このIngress Controller Pod群を外部に公開するために、Serviceリソースを使用します。
- クラウド環境では、Ingress ControllerをLoadBalancer Serviceとして公開するのが最も一般的です。LoadBalancerがプロビジョニングされ、そのIPに80/443ポートでアクセスすることでIngress Controllerに到達します。
- ベアメタル環境などLoadBalancerが使えない環境では、Ingress ControllerをNodePort Serviceとして公開することがあります。この場合、外部クライアントは任意のノードのIPアドレスとIngress Controller ServiceのNodePort(通常はHTTP/S用に設定されたポート)を使ってIngress Controllerにアクセスします。その後、Ingress ControllerがIngressルールに従ってトラフィックを適切なバックエンドService(通常はClusterIP Service)にルーティングします。
- この構成は、NodePortのデメリット(ポート管理、IPの変動など)をIngressのメリット(標準ポート、高度なルーティング、TLS終端)で補う形になります。NodePortはあくまでIngress Controllerへの「入り口」として機能し、実際のアプリケーションへのアクセスはIngressルールによって行われます。
これらの発展的なトピックは、NodePort Serviceを単体で使うだけでなく、Kubernetesネットワーク全体のコンテキストでNodePortがどのように位置づけられ、より複雑な要件に対してどのように他のコンポーネントと組み合わせて使われるかを理解するのに役立ちます。
まとめ
この記事では、KubernetesのNodePort Serviceについて詳細に解説しました。NodePortは、Kubernetesクラスターの各ノード上に特定のポートを開放し、外部からのトラフィックをService経由でバックエンドのPodに転送する、最も基本的な外部公開の仕組みです。
その仕組みはシンプルであり、Serviceタイプを NodePort
に設定し、ポート定義を行うだけで実現できます。割り当てられたNodePort(通常は30000-32767の範囲)を使って、クラスター内の任意のノードのIPアドレス経由でアプリケーションにアクセス可能になります。
NodePort Serviceは、開発・テスト環境での手軽な外部公開や、LoadBalancer Serviceが利用できないベアメタル環境などにおいて有用です。設定の容易さ、特別なインフラ不要な点がメリットとして挙げられます。
しかしながら、NodePort Serviceにはデメリットも多く存在します。クラスター内の全てのノードでポートが開放されることによるセキュリティリスク、ポート競合や管理の煩雑さ、ノードIPへの依存による可用性・アクセス性の問題、外部からのトラフィック分散の限界などです。これらのデメリットから、特にセキュリティ、可用性、管理の容易さが重視される本番環境では、NodePort Serviceを単独で使用することは推奨されない場合が多いです。
本番環境における主要な外部公開手段としては、クラウドプロバイダーのロードバランサーと連携するLoadBalancer Serviceや、HTTP/Sトラフィックに特化した高度なルーティングを提供するIngressがより適しています。NodePortは、これらの代替手段が利用できない場合や、Ingress Controllerの公開手段として利用されるなど、限定的なユースケースで検討されるべきです。
どのServiceタイプを選択するかは、アプリケーションの要件、実行環境、求められるセキュリティや可用性のレベルなどを総合的に判断して決定することが重要です。NodePortはKubernetesの外部公開を理解する上での基礎となりますが、その制約を理解し、必要に応じてLoadBalancerやIngressといったより高度な仕組みの利用を検討することが、Kubernetesを効果的に運用するために不可欠です。
この記事が、Kubernetes NodePort Serviceの理解を深め、アプリケーションの適切な外部公開設定を行うための一助となれば幸いです。
付録: よくある質問 (FAQ)
Q1: NodePort Serviceは本番環境で使用しても良いですか?
A1: 原則として、多くの本番環境ではNodePort Serviceを単独でインターネットに直接公開することは推奨されません。理由は、セキュリティリスク(全ノードでのポート開放)、可用性の問題(特定のノードIPへの依存)、管理の煩雑さ(ポート範囲の制約、IP変動)などが挙げられるためです。クラウド環境であればLoadBalancer Service、HTTP/SアプリケーションであればIngressを使用するのが一般的でより推奨されます。ただし、厳格なファイアウォールでアクセス元IPアドレスを制限したり、NodePortを他のレイヤー(例: Ingress Controllerの入り口)として使用したりする場合は、特定の条件下で許容されることもあります。
Q2: NodePortとして指定できるポート範囲を変更できますか?
A2: はい、Kubernetesクラスターの設定(kube-apiserverの起動オプション --service-node-port-range
)によって、NodePortとして割り当てられるポート範囲を変更できます。ただし、これはクラスター全体の設定変更であり、クラスター管理者のみが行える操作です。個別のService定義でデフォルト範囲外のポートを指定することは可能ですが、クラスター設定で許可されている範囲内でなければServiceは作成できません。範囲を変更する場合でも、システムポートや他の標準的なポートとの衝突には十分注意が必要です。
Q3: 特定のノードだけでNodePortを開くことはできますか?
A3: Kubernetesの標準機能であるNodePort Serviceは、その設計上、クラスター内の全てのノード上で指定されたポートを開放します。特定のノードだけでNodePortを開放するという機能は、NodePort Serviceの標準的な動作としては提供されていません。もし特定のノードのみを外部公開ポイントとしたい場合は、そのノードに対してのみファイアウォールを開けるといったインフラレベルでの対策を講じるか、Kubernetesのより高度なネットワーキング機能(例: DaemonSetで特定ノードにだけIngress Controllerをデプロイし、そのIngress Controllerを公開するなど)を組み合わせる必要があります。しかし、これはNodePort Serviceの典型的な利用方法ではありません。
Q4: NodePortでUDPトラフィックを扱うことはできますか?
A4: はい、NodePort ServiceはUDPトラフィックも扱うことができます。ServiceのYAML定義の spec.ports
リストで protocol: UDP
を指定すれば、対応するUDPポートがNodePortとして開放され、UDPトラフィックが転送されるようになります。ただし、NodePortはあくまでTCP/UDPのパケット転送機能を提供するものであり、UDPの特性上(コネクションレスなど)、TCPとは異なる考慮が必要になる場合があります。
Q5: externalTrafficPolicy: Local
を使うと何が変わりますか?
A5: externalTrafficPolicy: Local
を使用すると、NodePortに到達した外部トラフィックは、そのトラフィックを受け付けたノード上に存在するバックエンドPodにのみ転送されるようになります。デフォルトの Cluster
設定では、ノード間でトラフィックが転送され、クラスター内の任意のノード上のPodに到達する可能性があります。Local
ポリシーの利点はクライアントのソースIPアドレスを保持しやすいことですが、ノード間の負荷分散が偏ったり、アクセスしたノードにPodがいない場合にアクセスが失敗したりするリスクがあります。用途に応じて選択が必要なオプションです。