[Kubernetes]ClusterIPの動作を確認する

#はじめに
これまで、PodやDeploymentなどのWorkloadリソースの動作を確認してきました。
Kubernetesは各ノード間で内部ネットワークを構成していますので、Pod間の通信はPodをデプロイするだけで可能です。しかし、「Service」を利用することで、ロードバランシングやDNSが利用できるようになりますので、「Service」を利用するのが一般的だと思います。
そこで今回はServiceの一つである「ClusterIP」の動作を確認したいと思います。

#ClusterIPの概要
ClusterIPは、クラスタ内でのみ利用可能な仮想IPを持つロードバランサです。
Pod間の通信をロードバランシングします。クラスタの外部に出ることはできません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/08108d69-d564-aac0-f467-3eb4a404ddac.png)

##設定
ClusterIPの設定を見ていきます。今回は以下のマニフェストを作成しました。
ClusterIPとDeploymentを合わせて記載しています。

```sampleClusterIP.yaml
apiVersion: v1
kind: Service
metadata:
  name: cluster-ip
spec:
  type: ClusterIP
  ports:
    - name: cluster-port
      port: 8080
      targetPort: 80
  selector:
    app: nginx-dep
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-dep
  template:
    metadata:
      labels:
        app: nginx-dep
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
```

上下が逆になりますが、まずはDeploymentの設定から見ていきます。
ReplicaSetは2つです。各Podには「app: nginx-dep」のラベルが付与されており、コンテナが使用するポートは「80」です。

次にClusterIPの設定を見てみます。
「8080」のポートからのトラフィックを「80」のポートに転送します。そして、SelectorとしてPodのラベルである「app: nginx-dep」を指定しています。指定したラベルを持つPodにバランシングする動作になります。

#動作確認
##ClusterIPとDeploymentの作成
このマニフェストをapplyします。

```
$ kubectl apply -f sampleClusterIP.yaml
service/cluster-ip created
deployment.apps/nginx created
$ kubectl get service/cluster-ip
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
cluster-ip   ClusterIP   10.103.135.178   <none>        8080/TCP   44s
$ $ kubectl get pod -L app -o wide
NAME                     READY   STATUS    RESTARTS   AGE     IP               NODE           NOMINATED NODE   READINESS GATES   APP
nginx-6c4975c9f5-m8cv9   1/1     Running   0          3m46s   192.168.79.75    k8s-worker01   <none>           <none>            nginx-dep
nginx-6c4975c9f5-xwlzj   1/1     Running   0          3m46s   192.168.69.238   k8s-worker02   <none>           <none>            nginx-dep
```
ClusterIPの詳細を確認します。

```
$ kubectl describe service/cluster-ip
Name:              cluster-ip
Namespace:         default
Labels:            <none>
Annotations:       kubectl.kubernetes.io/last-applied-configuration:
                     {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"name":"cluster-ip","namespace":"default"},"spec":{"ports":[{"name":"clus...
Selector:          app=nginx-dep
Type:              ClusterIP
IP:                10.103.135.178
Port:              cluster-port  8080/TCP
TargetPort:        80/TCP
Endpoints:         192.168.69.238:80,192.168.79.75:80
Session Affinity:  None
Events:            <none>
```
「IP」の値として「10.103.135.178」が表示されています。これは自動で設定されたClusterIPのIPアドレスです。
次に「Endpoints」に各PodのIPアドレスが表示されていることを確認します。Selectorで設定した値と同じラベルを持つPodのIPアドレスが表示されます。
もし別サービスで同じラベルを持つPodがクラスタ内に存在する場合、そのPodにもバランシングされてしまいますので、ラベル名のつけ方に統一したルールを決めておく必要があります。そのため、意図したPodのIPアドレスが「Endpoints」に表示されていることの他に、意図しないPodのIPアドレスが表示されていないことも確認する必要があります。

##動作確認
設定は問題なさそうですが、実際の動作も確認したいと思います。
方法としては、動作確認用のPodをクラスタ内にデプロイして、そのPodからClusterIPに対してHTTPのリクエストを送ることで確認してみたいと思います。
###下準備
2つのPodに対してどちらにバランシングされたかを確認するために、nginxのindex.htmlに何か目印をつけておきたいと思います。
各Podにログインして、index.htmlを編集します。

```
$ kubectl exec -it nginx-6c4975c9f5-m8cv9 /bin/bash

root@nginx-6c4975c9f5-m8cv9:/# cd /usr/share/nginx/html/
root@nginx-6c4975c9f5-m8cv9:/usr/share/nginx/html# vi index.html
bash: vi: command not found
root@nginx-6c4975c9f5-m8cv9:/usr/share/nginx/html# echo pod1 >> index.html
root@nginx-6c4975c9f5-m8cv9:/usr/share/nginx/html# exit
exit
```
viで編集しようと思いましたが、入ってないんですね。。。インストールしても良かったんですが、目印をつけたいだけですので、最後の行に追記しました。雑なやり方ですが、まあわかるでしょう。
もう一つのPodには同様に「pod2」と目印を付けました。

###動作確認用Podのデプロイと確認
動作確認用のPodとして、以下のマニフェストを作成しました。

```test_pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
    - name: centos
      image: centos:latest
      command:
      - sh
      - -c
      args:
      - for i in 1 2 3 4 5 ; do curl -s http://10.103.135.178:8080 ; sleep 5; done ;exit 0
```
5秒間隔で5回HTTPのリクエストを送信します。

このマニフェストをapplyして、30秒ほど待ってからログを確認します。

```
$ kubectl apply -f test_pod.yaml
pod/test-pod created
$ kubectl logs test-pod | grep pod
pod2
pod1
pod2
pod2
pod1
```
ちゃんと2つのPodにバランシングされてますね。

#まとめ
今回はServiceの1つであるClusterIPの動作を確認しました。
クラスタ内ではありますがPod間で通信することによって、マイクロサービスっぽくなってきましたね。
バランシングのポリシー（ラウンドロビンとか）設定ができるのかなど、ほかにどのような設定ができるのか調べてみたいと思います。