Kubernetes サービス: ClusterIP、Nodeport、LoadBalancer

By 清水 孝郎 - DECEMBER 8, 2022

SHARE:

本文の内容は、2022年12月8日に JAVIER MARTÍNEZ が投稿したブログ(https://sysdig.com/blog/kubernetes-services-clusterip-nodeport-loadbalancer/)を元に日本語に翻訳・再構成した内容となっております。

Podははかないものです。そして、そうであることを意図しています。デプロイを使えば、シームレスに破棄して置き換えることができます。また、HPA(Horizontal Pod Autoscaling)を使用すれば、ある時点でスケールさせることができます。

つまり、コンテナ内で動作するアプリケーションと社内外で接続する際に、将来的にPodが存在しない可能性があるため、PodのIPアドレスに依存することはできないのです。

KubernetesのPodには、IPアドレスが割り当てられることにお気づきでしょうか:

stable-kube-state-metrics-758c964b95-6fnbl 1/1 Running 0 3d20h 100.96.2.5 ip-172-20-54-111.ec2.internal <none> <none>
stable-prometheus-node-exporter-4brgv 1/1 Running 0 3d20h 172.20.60.26 ip-172-20-60-26.ec2.internal

これは、この特定のPodのためのユニークで内部的なIPですが、Podの性質上、将来もこのIPが存在する保証はありません。

サービス

Kubernetes Serviceは、アプリケーションを内部と外部の両方に公開するためのメカニズムです。

どのサービスもコネクタとして使用できる常時接続のIPアドレスを作成します。

さらに、 targetPortにリンクされる port をオープンします。サービスによっては、各NodeにPortを作成し、さらに外部IPを作成してクラスター外にコネクターを作成することができます。

IPとPortの両方の組み合わせで、アプリケーションを一意に識別する方法を作成することができます。

サービスの作成

すべてのサービスには、クラスター内の一連のPodとリンクさせるためのフィルタであるセレクターがあります。

spec:
selector:
app.kubernetes.io/name: myapp

つまり、myappというラベルを持つすべてのPodは、このサービスにリンクされます。

Serviceの設定には、3つのポート属性があります:

 ports:
- port: 80
targetPort: 8080
nodePort: 30036
protocol: TCP

  • port: アプリケーションに接続するために作成される新しいサービスポートです。
  • targetPort: サービスリクエストでターゲットにしたいアプリケーションポートです。
  • nodePort: 各ノードで開放される30000~32767の範囲のポートです。空のままだと、Kubernetesはその範囲内で空いているものを選択します。
  • プロトコルを指定します。TCPがデフォルトですが、SCTPやUDPなど他のものも使用できます。
作成されたサービスを確認することができます:

kubectl get services
kubectl get svc

サービスの種類

Kubernetesでは、以下のような種類のサービスを作成することができます。

  • ClusterIP (default)
  • Nodeport
  • LoadBalancer
  • ExternalName

それぞれについて詳しく見ていきましょう。

ClusterIP

Kubernetesのサービスのデフォルトタイプです。

名前からわかるように、これはクラスター内部で使えるアドレスに過ぎません。

例えば、Prometheus Stackの初期helmインストールを例にとってみましょう。PrometheusとGrafanaのエコシステムに必要なPod、デプロイ、サービスをインストールします。

NAME                                     TYPE      CLUSTER-IP    EXTERNAL-IP PORT(S)                    AGE
alertmanager-operated ClusterIP None <none> 9093/TCP,9094/TCP,9094/UDP 3m27s
kubernetes ClusterIP 100.64.0.1 <none> 443/TCP 18h
prometheus-operated ClusterIP None <none> 9090/TCP 3m27s
stable-grafana ClusterIP 100.66.46.251 <none> 80/TCP 3m29s
stable-kube-prometheus-sta-alertmanager ClusterIP 100.64.23.19 <none> 9093/TCP 3m29s
stable-kube-prometheus-sta-operator ClusterIP 100.69.14.239 <none> 443/TCP 3m29s
stable-kube-prometheus-sta-prometheus ClusterIP 100.70.168.92 <none> 9090/TCP 3m29s
stable-kube-state-metrics ClusterIP 100.70.80.72 <none> 8080/TCP 3m29s
stable-prometheus-node-exporter ClusterIP 100.68.71.253 <none> 9100/TCP 3m29s

Kubernetes Services ClusterIP

これは、内部Cluster IPアドレスとPortを使用した接続を作成します。

しかし、Clusterの外からこのコネクターを使用する必要がある場合はどうでしょうか?このIPは内部のものであり、外部では動作しません。

そこで、残りのサービスが登場します。

NodePort

NodePort は各ノードでポートを公開するという意味で ClusterIP とは異なります。

NodePortが作成されると、kube-proxyは30000-32767の範囲のポートを公開します:

apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
selector:
app: myapp
type: NodePort
ports:
- port: 80
targetPort: 8080
nodePort: 30036
protocol: TCP

Kubernetes Services Nodeport

NodePortは、非HTTP通信のための好ましい要素です。

NodePortを使用する際の問題点は、やはり各Nodeに個別にアクセスする必要があることです。

では、次の項目を見てみましょう…

LoadBalancer

LoadBalancerはKubernetesのサービスの一つで、以下のような機能を持っています。

  • ClusterIPのようなサービスを作成する
  • NodePortのようなポートを各ノードでオープンする。
  • クラウドプロバイダのLoadBalancer実装を使用する(LoadBalancerが動作するためには、クラウドプロバイダーがこれをサポートする必要があります)。

apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- name: web
port: 80
selector:
app: web
type: LoadBalancer
my-service LoadBalancer 100.71.69.103 <pending> 80:32147/TCP 12s
my-service LoadBalancer 100.71.69.103 a16038a91350f45bebb49af853ab6bd3-2079646983.us-east-1.elb.amazonaws.com 80:32147/TCP 16m

今回は、Amazon Web Service(AWS)を利用していたため、AWSからの外部IPが作成されました。

そして、 kubectl describe my-serviceを使用すると、いくつかの新しい属性が追加されていることがわかります。

Name:                    my-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app.kubernetes.io/name=pegasus
Type: LoadBalancer
IP Family Policy: SingleStack
IP Families: IPv4
IP: 100.71.69.103
IPs: 100.71.69.103
LoadBalancer Ingress: a16038a91350f45bebb49af853ab6bd3-2079646983.us-east-1.elb.amazonaws.com
Port: <unset> 80/TCP
TargetPort: 9376/TCP
NodePort: <unset> 32147/TCP
Endpoints: <none>
Session Affinity: None
External Traffic Policy: Cluster

NodePortとの主な違いは、LoadBalancerにアクセスすることができ、Nodeにリクエストを均等に割り当てようとすることです。

Kubernetes Service LoadBalancer

ExternalName

ExternalNameサービスは、Kubernetesクラスター外の要素に接続する必要性から導入されました。クラスター内のアイテムに接続する方法ではなく、クラスターの外部要素に接続するコネクターとお考えください。

これには2つの目的があります:

  • そのエレメントへのすべての通信のための単一のエンドポイントを作成します。
  • その外部サービスを交換する必要がある場合、すべての接続ではなく、ExternalNameを修正するだけで簡単に切り替えることができる。

apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- name: web
port: 80
selector:
app: web
type: ExternalName
externalName: db.myexternalserver.com

まとめ

サービスは、クラスターの内外に内部エンドポイントを公開する方法を提供するため、Kubernetesの重要な側面です。

ClusterIPサービスは、ノード内通信のためのコネクターを作成するだけです。ノード内の他者と接続する必要がある特定のアプリケーションがある場合にのみ使用してください。

NodePortとLoadBalancerは、アプリケーションへの外部アクセスに使用されます。複数Podの実装では、LoadBalancerを使用してリクエストを均等に分散することが望ましいですが、これを利用するためには、ベンダーがロードバランシングを実装する必要があることに注意してください。

これらとは別に、KubernetesにはIngressesという外部向けのロードバランシング付きHTTP接続を作成する方法が用意されています。