EKSノードにデプロイ可能なPod数をDatadogで監視する

記事タイトルとURLをコピーする

CI部の村上です。

今回はEKSのノードにデプロイ可能なPodの数をDatadogで見てみたという話です。

はじめに

今回検証した環境

t3.smallのノードが1つだけある構成です。

administrator:~/environment $ kubectl get node
NAME                                                STATUS   ROLES    AGE    VERSION
ip-192-168-28-124.ap-northeast-1.compute.internal   Ready    <none>   175m   v1.19.13-eks-8df270
administrator:~/environment $ kubectl get node ip-192-168-28-124.ap-northeast-1.compute.internal -o json | jq '.metadata.labels."beta.kubernetes.io/instance-type"'
"t3.small"

ノードにデプロイできるPod数に制限があるのはなぜか

EKSはノード(EC2)のENIがもつIPアドレスを使って、各PodにIPアドレスを割り振っていきます。

EC2にはインスタンスタイプごとにアタッチできるENIの数が決まっており、また、ひとつのENIに関連付けられるIPアドレス数も決まっています。

docs.aws.amazon.com

よってPodに対して割り当てるIPアドレスが枯渇した場合、そのノードにPodをデプロイすることができなくなります。

インスタンスタイプごとの最大Pod数

以下に記載があります。t3.smallの場合は11と記載されています。

github.com

t3.smallのEC2の場合、ENIの最大数は3、ENIあたりの最大IPアドレス数は4です。

よってt3.smallのEC2には、

3×4=12

のIPアドレスを付与できるのですが、各ENIのプライマリIPアドレスはPodに割り当てられませんので、

3×(4-1)=9

ただし、kube-proxyとPodへのIPアドレスの割り振りを管理するaws-nodeの2つはプライマリIPアドレスが付与されるので、

3×(4-1)+2=11

となります。

ノードにデプロイできるポッドの数を確認するには、次の式を使用します。 (Number of network interfaces for the instance type × (the number of IP addressess per network interface - 1)) + 2
https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt

実際に確かめてみる

nginxのDeploymentを使い、追加でPodが10個デプロイされるようにしてみました。

administrator:~/environment $ kubectl get po --all-namespaces -o wide
NAMESPACE     NAME                                READY   STATUS    RESTARTS   AGE    IP               NODE                                                NOMINATED NODE   READINESS GATES
default       nginx-deployment-579c9f84b5-5rpw9   1/1     Running   0          38m    192.168.21.219   ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-6mfss   1/1     Running   0          38m    192.168.4.115    ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-g6ttn   1/1     Running   0          38m    192.168.0.253    ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-lzv27   1/1     Running   0          38m    192.168.25.240   ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-qd4fc   0/1     Pending   0          38m    <none>           <none>                                              <none>           <none>
default       nginx-deployment-579c9f84b5-qdjxt   1/1     Running   0          38m    192.168.3.18     ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-qzc7w   1/1     Running   0          38m    192.168.29.223   ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-r65tc   1/1     Running   0          38m    192.168.8.199    ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-579c9f84b5-t7tq8   0/1     Pending   0          38m    <none>           <none>                                              <none>           <none>
default       nginx-deployment-579c9f84b5-zcqmf   0/1     Pending   0          38m    <none>           <none>                                              <none>           <none>
kube-system   aws-node-gdfpg                      1/1     Running   0          114m   192.168.28.124   ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
kube-system   coredns-59847d77c8-4lpzk            1/1     Running   0          120m   192.168.30.32    ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
kube-system   coredns-59847d77c8-w5qqx            1/1     Running   0          120m   192.168.4.113    ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>
kube-system   kube-proxy-l7kvf                    1/1     Running   0          114m   192.168.28.124   ip-192-168-28-124.ap-northeast-1.compute.internal   <none>           <none>

全14個のPodのうち、11個のPodがRunning、残りはPendingになっていることが分かります。

ここで気をつけないといけないのは、kube-proxyなど最初から存在するPodがあるため、nginxのPodが7個しかデプロイされていない点です。

つまり実際は、追加でデプロイできるPod数は、EC2にデプロイできる最大Pod数よりも少ない数になります。

そもそも監視する必要があるのか

Cluster Autoscalerがデプロイされている環境では、PodがPending状態になると自動的にノードを増やしてくれます。

試しにCluster Autoscalerをデプロイして、再度nginxのPodを10個デプロイしてみます。

今度はすべてのPodがRunningの状態になっており、ノードが2つに増えていることが分かります。

administrator:~/environment $ kubectl get pod -o wide -A
NAMESPACE     NAME                                 READY   STATUS    RESTARTS   AGE     IP               NODE                                               NOMINATED NODE   READINESS GATES
default       nginx-deployment-7cbb8c6dc5-4nps8    1/1     Running   0          3m41s   192.168.29.69    ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
default       nginx-deployment-7cbb8c6dc5-5fn99    1/1     Running   0          3m41s   192.168.86.20    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-7cbb8c6dc5-9drb4    1/1     Running   0          3m41s   192.168.16.52    ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
default       nginx-deployment-7cbb8c6dc5-hz5q7    1/1     Running   0          3m41s   192.168.76.2     ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-7cbb8c6dc5-jn9fd    1/1     Running   0          3m41s   192.168.69.21    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-7cbb8c6dc5-lmhw9    1/1     Running   0          3m41s   192.168.24.198   ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
default       nginx-deployment-7cbb8c6dc5-mfvnp    1/1     Running   0          3m41s   192.168.88.24    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-7cbb8c6dc5-r8j28    1/1     Running   0          3m41s   192.168.20.128   ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
default       nginx-deployment-7cbb8c6dc5-vgn7q    1/1     Running   0          3m41s   192.168.69.150   ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-7cbb8c6dc5-wzqz7    1/1     Running   0          3m41s   192.168.1.152    ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
kube-system   aws-node-c9gxc                       1/1     Running   0          15m     192.168.78.38    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
kube-system   aws-node-zmljm                       1/1     Running   0          74m     192.168.6.58     ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
kube-system   cluster-autoscaler-6b8bd8cc5-8s7vm   1/1     Running   0          19m     192.168.19.1     ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
kube-system   coredns-59847d77c8-s28hp             1/1     Running   0          80m     192.168.2.223    ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
kube-system   coredns-59847d77c8-wm4qn             1/1     Running   0          80m     192.168.29.232   ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>
kube-system   kube-proxy-jkgg8                     1/1     Running   0          15m     192.168.78.38    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
kube-system   kube-proxy-pshbq                     1/1     Running   0          74m     192.168.6.58     ip-192-168-6-58.ap-northeast-1.compute.internal    <none>           <none>

よって、ノードにデプロイ可能なPod数が0になってもCluster Autoscalerがノードを増やしてくれるので、人力での対応は基本的に不要です。

なので監視は不要!とするのもひとつですが、リソースの使用状況を見るためのリソースメトリクスとして監視するのもアリだと考えます。

例えば、コンテナのCPU要求spec.containers[].resources.requests.cpuを高くしすぎてしまった場合を考えてみます。

一度nginxのPodをすべて削除して、以下のようにnginxのDeploymentのspec.containers[].resources.requests.cpu400mにして再デプロイしてみます。ちなみにmはmillicoresのことで1000m=1vCPUです。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 10
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80
        resources:
          requests:
            memory: "16Mi"
            cpu: "400m"

すると、さっきはノードが2つに増えただけでしたが、今度はノードが3つに増えていることがわかります。

administrator:~/environment $ kubectl get node
NAME                                               STATUS   ROLES    AGE     VERSION
ip-192-168-1-158.ap-northeast-1.compute.internal   Ready    <none>   6m58s   v1.19.13-eks-8df270
ip-192-168-45-66.ap-northeast-1.compute.internal   Ready    <none>   7m7s    v1.19.13-eks-8df270
ip-192-168-78-38.ap-northeast-1.compute.internal   Ready    <none>   109m    v1.19.13-eks-8df270

これはノードが各コンテナに割り当てられるCPUリソースの上限を超えたため、早々にPodがノードにデプロイできなくなりPendingの状態となったことから、ノードがスケールアウトしたのが原因です。

コンテナのCPU要求spec.containers[].resources.requests.cpuが適切な値であれば良いのですが、そうでない場合は、まだノードにPodをデプロイできる余地があるのにスケールアウトしてしまったことになります。

Podの一覧を見ても、1つのノードあたり11個のPodをデプロイできるのに、5~8個のPodしかデプロイされていません。

administrator:~/environment $ kubectl get pod -A -o wide
NAMESPACE     NAME                                 READY   STATUS    RESTARTS   AGE     IP               NODE                                               NOMINATED NODE   READINESS GATES
default       nginx-deployment-6c84f6948f-25wss    1/1     Running   0          8m58s   192.168.29.13    ip-192-168-1-158.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-2wlwv    1/1     Running   0          8m59s   192.168.69.150   ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-8hzv7    1/1     Running   0          8m58s   192.168.13.101   ip-192-168-1-158.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-94r26    1/1     Running   0          8m58s   192.168.40.119   ip-192-168-45-66.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-9jwkl    1/1     Running   0          8m59s   192.168.69.21    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-9pdgf    1/1     Running   0          8m59s   192.168.85.52    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-9r92b    1/1     Running   0          8m58s   192.168.47.229   ip-192-168-45-66.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-hkfmc    1/1     Running   0          8m58s   192.168.58.177   ip-192-168-45-66.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-qvdd2    1/1     Running   0          8m58s   192.168.54.22    ip-192-168-45-66.ap-northeast-1.compute.internal   <none>           <none>
default       nginx-deployment-6c84f6948f-wnthn    1/1     Running   0          8m58s   192.168.3.105    ip-192-168-1-158.ap-northeast-1.compute.internal   <none>           <none>
kube-system   aws-node-4h7c6                       1/1     Running   0          7m44s   192.168.1.158    ip-192-168-1-158.ap-northeast-1.compute.internal   <none>           <none>
kube-system   aws-node-c9gxc                       1/1     Running   0          110m    192.168.78.38    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
kube-system   aws-node-gwjdf                       1/1     Running   0          7m52s   192.168.45.66    ip-192-168-45-66.ap-northeast-1.compute.internal   <none>           <none>
kube-system   cluster-autoscaler-6b8bd8cc5-cw6v2   1/1     Running   0          90m     192.168.86.20    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
kube-system   coredns-59847d77c8-4j7t5             1/1     Running   0          90m     192.168.76.2     ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
kube-system   coredns-59847d77c8-dgdz4             1/1     Running   0          90m     192.168.88.24    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>
kube-system   kube-proxy-6plfm                     1/1     Running   0          7m44s   192.168.1.158    ip-192-168-1-158.ap-northeast-1.compute.internal   <none>           <none>
kube-system   kube-proxy-f865g                     1/1     Running   0          7m52s   192.168.45.66    ip-192-168-45-66.ap-northeast-1.compute.internal   <none>           <none>
kube-system   kube-proxy-jkgg8                     1/1     Running   0          110m    192.168.78.38    ip-192-168-78-38.ap-northeast-1.compute.internal   <none>           <none>

ですので、Cluster Autoscalerが正しく動作しているか調べるための指標として、ノードにデプロイ可能な最大Pod数に対する起動中のPod数は見れるようにしておくのもアリだと思います。

kubernetes.io

Datadogで監視する

Datadogで監視する場合、以下のメトリクスを使います。

  • ノードにデプロイできる最大Pod数
  • 現在ノードにデプロイされているPod数

ノードにデプロイできる最大Pod数

kubernetes_state.node.pods_allocatableで取得できます。

t3.smallを使っている環境なので、11と表示されています。

現在ノードにデプロイされているPod数

kubernetes.pods.runningで取得できます。

以下のとおり現在のPod数は8ですが、Datadog上でも8と表示されています。

administrator:~/environment $ kubectl get pod -A 
NAMESPACE     NAME                                             READY   STATUS    RESTARTS   AGE
default       dd-agent-datadog-cluster-agent-575474dff-jgk7g   1/1     Running   0          17m
default       dd-agent-datadog-fq9kv                           3/3     Running   0          17m
default       dd-agent-kube-state-metrics-7f4f4f4dd5-6b6rn     1/1     Running   0          17m
kube-system   aws-node-c9gxc                                   1/1     Running   0          51m
kube-system   cluster-autoscaler-6b8bd8cc5-cw6v2               1/1     Running   0          32m
kube-system   coredns-59847d77c8-4j7t5                         1/1     Running   0          32m
kube-system   coredns-59847d77c8-dgdz4                         1/1     Running   0          32m
kube-system   kube-proxy-jkgg8                                 1/1     Running   0          51m

まとめ

最後まで読んでいただきありがとうございました。

上記2つのメトリクスを使って、モニターやダッシュボードを設定してみてはいかがでしょうか。

村上博哉 (執筆記事の一覧)

2020年4月入社。機械学習が好きです。記事へのご意見など:hiroya.murakami@serverworks.co.jp