KubernetesのServiceとは
Kubernetesでは、アプリケーションの一部が互いにまたは外部サービスと通信する方法を管理することが重要です。そのために"Service"という概念が重要になります。KubernetesにおけるServiceは、一連のPodで実行されているアプリケーションをネットワークサービスとして公開するために使用するリソースです。
Serviceは、ラベルセレクタを使用してPodのIPアドレスを追跡します。Podは一時的なものであるため、作成や破棄が行われることにより、Serviceがトラフィックを送信するPodのセットは動的に変化する可能性があります。ServiceのIPアドレスは時間の経過とともに変わらず、他のアプリケーションはこの一貫したアドレスを基にしたPodの入れ替わりにも対応できます。
KubernetesのServiceは、L4(第4層)ロードバランサーとして機能します。トラフィックが利用可能なPodの間で均等に分散されるようにします。
次の図は、Serviceの動作を示しています。
+--------------+ +------------+ +------------+
| | | | | |
| Client +-----> Service +-----> Pod |
| | | | | |
+--------------+ +------------+ +------------+
/\ |
/ \
selector / \ label
/ \
+------------+ +------------+
| | | |
| Pod | | Pod |
| | | |
+------------+ +------------+
- Client:リクエストの開始元
- Service:ネットワークトラフィックの分散
- Pods:リクエストの処理
KubernetesのServiceのタイプ
Kubernetesには、次の3つのタイプのServiceがあります。
- ClusterIP
- NodePort
- LoadBalancer
ClusterIP Service
Podは一時的な性質を持っており、どのノードにPodがデプロイされているかを把握することは現実的ではありません。それに加えて、Podは頻繁に再起動されることもあり、常に同じPodにアクセスできるという保証はありません。
ClusterIP Serviceを使用することで、一時的なPodのIPを抽象化し、それらの前に静的なIPを持つプロキシを配置することができます。これにより、PodのIPを知る必要がなくなり、Podへのアクセスのためのロードバランシングが可能となります。
例:ClusterIPを使用してクラスタ内のPodを公開およびロードバランスする
Minikubeを起動します。
$ minikube start
helloworld
Podを作成します。
$ kubectl run --port 8080 --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created
helloworld
PodをClusterIP Service helloworld-clusterip
として公開します。
$ kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip
それでは、クラスタ内の別のPodからhelloworld
のClusterIP Serviceへのアクセスをテストします。
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
/ $ curl helloworld-clusterip:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $ exit
ただし、ホストOSはPodにアクセスすることはできません。
$ kubectl get pod,svc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/helloworld 1/1 Running 0 3m57s 10.244.0.3 minikube <none> <none>
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
service/helloworld-clusterip ClusterIP 10.99.232.132 <none> 8080/TCP 2m37s run=helloworld
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5m4s <none>
$ curl 10.99.232.132:8080
curl: (28) Failed to connect to 10.99.232.132 port 8080 after 75007 ms: Operation timed out
NodePort Service
NodePort Serviceを使用すると、ClusterIPでは外部ネットワークにPodを公開することができません。NodePort Serviceでは、PodをノードのIPおよび指定されたポートを介してアクセス可能にします。
例:NodePortを使用してPodを外部に公開する
PodをNodePort Serviceとして公開します。
$ kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport
それでは、クラスタ内からhelloworld
NodePort Serviceへのアクセスをテストします。
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
/ $ curl helloworld-nodeport:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $ exit
ノードのIPとNodePortを使用して、外部からもアクセスできます。
$ minikube service helloworld-nodeport --url
$ curl $(minikube service helloworld-nodeport --url)
Hello, world!
Version: 1.0.0
Hostname: helloworld
ただし、NodePortを使用する場合のデメリットは、ノードのIPとNodePortの両方を知る必要があることです。通常、NodePortは30000以上の高いポート番号です。さらに、複数のホストからなるクラスタでは、ノードのIPが変更される可能性があり、アクセス方法が不安定になります。
これらの問題に対処するために、ノードの前にロードバランサーを配置し、静的なIPとDNSを提供する「LoadBalancer」Serviceイプを使用できます。
LoadBalancer Service
LoadBalancer Serviceは、NodePort Serviceの拡張であり、主にクラウド環境で使用されます。これにより、クラウドプロバイダーのロードバランサーが特定のポートを介して外部トラフィックをノードにルーティングし、最終的にPodにアクセスできるようになります。
例:LoadBalancerを使用してPodを外部に公開する
PodをLoadBalancer Serviceとして公開します。
$ kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-lb
それでは、クラスタ内からhelloworld
LoadBalancer Serviceへのアクセスをテストします。
$ kubectl run --restart Never --image curlimages/curl:7.68.0 -it --rm curl sh
/ $ curl helloworld-lb:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $ exit
curlを使用して、外部からLoadBalancerのURLにアクセスすることもできます。
$ minikube service helloworld-lb --url
$ curl $(minikube service helloworld-lb --url)
Hello, world!
Version: 1.0.0
Hostname: helloworld
Kubernetesクラスタをクラウドで運用する場合、LoadBalancer ServiceはパブリックIPとDNSが割り当てられ、そのServiceにアクセスできるようになります。
LoadBalancerの問題点
LoadBalancer Serviceは、Podを外部に公開し、ノードのIPを抽象化する優れた方法を提供しますが、いくつかの欠点もあります。
- 各Serviceには独自のロードバランサーが必要であり、コストがかかる場合がある
- L4で動作するため、TCP/IPスタックを超えた部分については意識せず、HTTPホスト/パスベースのルーティングを処理することができない
より高度なL7(アプリケーションレイヤ)ロードバランシングを実現し、HTTPホストおよびパスベースのルーティングを可能にするためには、Kubernetesは「Ingress」と呼ばれる別のリソースを提供しています。