Traffine I/O

日本語

2022-06-18

KubernetesのService

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を起動します。

bash
$ minikube start

helloworld Podを作成します。

bash
$ 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として公開します。

bash
$ kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip

それでは、クラスタ内の別のPodからhelloworldのClusterIP Serviceへのアクセスをテストします。

bash
$ 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にアクセスすることはできません。

bash
$ 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として公開します。

bash
$ kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport

それでは、クラスタ内からhelloworld NodePort Serviceへのアクセスをテストします。

bash
$ 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を使用して、外部からもアクセスできます。

bash
$ 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として公開します。

bash
$ kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-lb

それでは、クラスタ内からhelloworld LoadBalancer Serviceへのアクセスをテストします。

bash
$ 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にアクセスすることもできます。

bash
$ 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」と呼ばれる別のリソースを提供しています。

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!