EKS で1つのノードに配置できるPod数を増やす

## 一つのEC2インスタンスで実行できるPod数の制限について
EKS では、RDS などの AWS リソースに対してシームレスにつながるように、PodにVPCネットワーク上と同じIPアドレスが付与されます。
ノードをEC2で構築している場合、EC2のENIが持っているIPから割り振られるのですが、インスタンスタイプよって持てるENIの最大数が決まっており、また1つのENIで持てるIPアドレスの最大数も決まっています。このIPアドレスからPodに割り当てられないIPアドレスや`aws-node` と `kube-proxy` に割り当てられるIPアドレスなどから、Podに使用できるIPアドレス数、つまり1つのインスタンスで実行できるPodの上限数となります。

![fig1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46847/747259e1-7a6f-1634-5311-8aee17567fb0.png)

インスタンスタイプとPodの上限数は以下のページにまとまっています
[amazon-eks-ami/eni-max-pods.txt at master · awslabs/amazon-eks-ami · GitHub](https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt)

## AWS Nitro ベースのインスタンスと Amazon VPC CNI のバージョンアップで利用可能IP数を増やす
前述のように、デフォルトでは１つのEC2ノードに割り当てられるIPアドレス数はそれほど多くありません。
しかし、Amazon VPC CNI アドオンのバージョンを `1.9.0` 以上、インスタンスファミリーを `t3` や `m5` のような AWS Nitro ベースのインスタンスにすることで、`/28` IP アドレスプレフィックスを割り当てることができるようになり、1つのEC2ノードでより多くのPodを動かせるようになります。

[Amazon EC2 ノードで使用可能な IP アドレスの量を増やす](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/cni-increase-ip-addresses.html)

## Amazon EKS アドオンについて
EKS アドオン は EKS で Kubernetes クラスターを作成したときにインストールされるコンポーネントのバージョンを管理する機能です。
管理できるコンポーネントは現在は下記の3つです。

* Amazon VPC CNI
* CoreDNS
* kube-proxy

現状、`CoreDNS` や `kube-proxy` は最新バージョンがデフォルトでインストールされますが、`Amazon VPC CNI` はデフォルトのバージョンが `v1.7.5-eksbuild.2` となっており、利用可能なIP数を増やしたい場合は、このEKSアドオンを使って Amazon VPC CNI のバージョンを `v1.9.0-eksbuild.1` 以上にする必要があります。

## Amazon VPC CNI アドオンを設定する
AWSのマネジメントコンソールや`eksctl`から設定することもできますが、弊社ではTerraformで管理しているので以下のような設定で追加します（実際にはモジュール化しているので下記そのままではありませんが）

```terraform
resource "aws_eks_addon" "this" {
  cluster_name      = aws_eks_cluster.this.name
  addon_name        = "vpc-cni"
  addon_version     = "v1.9.1-eksbuild.1"
  resolve_conflicts = "OVERWRITE"
}
```

設定を適用すると各ノードで実行されている `aws-node` が指定されたバージョンに更新されます。

AWS マネジメントコンソールからも以下のように表示されて指定されたバージョンがインストールされたことがわかります。
![fig2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46847/ca963921-ecae-e39c-2eb1-3c603cff0079.png)

## `aws-node` DaemonSet のパラメーターを有効にする
Amazon VPC CNI を `1.9.0` 以上にすることができたので、以下のコマンドを実行して環境変数を設定し、パラメーターを有効にします。
```
$ kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
$ kubectl set env daemonset aws-node -n kube-system WARM_PREFIX_TARGET=1
```

## ノードグループを作り直す
ノードグループを自前で管理している（セルフマネージド）と、マネージドでノードグループを管理している場合で設定方法が異なるのですが、ここではマネージドでノードグループを管理している場合を記載します。

まず、最大Pod数をEC2インスタンスを起動時に指定する必要がありますが、マネージドでノードグループを作成している場合、自動で計算を行って起動テンプレートに以下のように最大Pod数に110と設定されていることがわかります。

```plaintext
/etc/eks/bootstrap.sh [省略] --max-pods=110' [省略] --use-max-pods false
```

最大Pod数が従来よりも多くなるのは Amazon EC2 Nitro Amazon Linux 2 のみなので、インスタンスタイプに、`t3` や `m5` などのシリーズを含める必要があります。
（上記のDaemonSetの設定を有効にしていても Nitro ベース以外のインスタンスが動かなくなるわけではありませんが、Nitroベースのものに比べるとかなり少なくなります）

また、最大Pod数はEC2インスタンスが起動時に設定されるため、インスタンスを作り直す必要があります。

## 変更した結果
設定変更前の`m5.large`の最大Pod数は`29`だったのが、変更後は`110` まで大幅に増えたことが確認できました。

```console
beta.kubernetes.io/instance-type=m5.large
...[省略]...
Capacity:
	pods:                        110
```

## まとめ
以前はリソース要求が少ないPodが多い場合、1つのノードに集約しようとしてもEC2のIPアドレスが上限に達してしまってCPUやメモリーが余ってしまうことがありましたが、今回の変更でリソースを有効に使えるようになったと思います。

参考

* [各インスタンスタイプのネットワークインターフェイスあたりの IP アドレス数](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI)
* [ポッドネットワーキング (CNI) - Amazon EKS](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/pod-networking.html)