EKSでPrivate IPアドレス枯渇したのでaws-nodeの設定を見直した

本記事は[ZOZO Advent Calendar 2021](https://qiita.com/advent-calendar/2021/zozo)その1の15日目の記事です。

# はじめに
最近地方移住を進めており、ワクワクすっぞな亀井と申します。

さて、ZOZOTOWNはモノリシックなアーキテクチャからマイクロサービスアーキテクチャにリプレイスを進めており、マルチテナントなEKSクラスタを運用しております。
また、ZOZOTOWNは毎年正月にセールを行っており、ありがたいことに1年のピークとなるトラフィックが流れるイベントとなっております。

リプレイスによるサービスの増加と、正月セールのためのPodスケールにより、EKSでPrivate IPアドレスが枯渇してしまう事態に遭遇しました。その際対応した[aws-node](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/pod-networking.html) daemonsetの設定変更について記事にしようと思います。

Podが多数稼働するEKSクラスタを運用されている方の参考になれば幸いです。

# Private IPアドレス枯渇？
Podスケールを行った際にPodがPendingで起動しない事態に遭遇しました。
AWSマネジメントコンソールでEKSの該当ノードグループを確認したところ、下記のような問題が出力されておりました。

```
Amazon Autoscaling was unable to launch instances because there are not enough free addresses in the subnet associated with your AutoScaling group(s).
```

Privateサブネットは、サブネットマスクが/20（IPアドレス数 4096）で3AZを使用しており4096*3=12,288のIPアドレスが使用可能な、比較的大きめのサブネットを用意しておりました。Podスケールを行ったとはいえ、起動ノードは合計で400台程だったため、400台で12,288のIPアドレスが足りない・・・だと？という状態でした。

# Private IPアドレス枯渇の原因
aws-nodeの下記パラメータの初期設定により、稼働Pod以上のIPアドレス数がノードごとに確保されてしまっていることがIPアドレス枯渇の原因でした。

`WARM_ENI_TRAGET: 1`（ノードが確保する余剰ENI数）
ref. https://github.com/aws/amazon-vpc-cni-k8s#warm_eni_target

上記設定により最低確保されるIPアドレスは「[ENIごとのIPアドレス数（インスタンスタイプごとに異なる）](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html)*2（ENI数。標準の1+WARN_ENI_TARGET:1）」で計算され、例えばインスタンスタイプm5.xlargeのノードでは「15*2」で最低で30IPが確保されてしまいます。

400台程のノードが稼働していたので、400ノード*30IP=12,000IPが使用されておりました。実際にはm5.xlargeよりサイズの大きいインスタンスタイプも存在したため、12,288IPに到達してしまっていたようです。

ノードで確保されているIPアドレスは、AWSマネージドコンソールから該当のノードのEC2 Instance、ネットワーキングタブで確認可能です。

# aws-nodeの設定見直し
IPアドレス枯渇の対応として、下記が考えられましたが

* (1)ノードの確保IPアドレスを減らし起動可能なノード数を増やす
* (2)Privateサブネットを拡張しPrivate IPアドレスを増やす

まずは(1)を進めることにしました。

## ノードの確保IPアドレスを減らす
aws-nodeの下記パラメータをチューニングしました。

* [MINIMUM_IP_TARGET](https://github.com/aws/amazon-vpc-cni-k8s#minimum_ip_target-v160)
  * ノードが確保する最低IPアドレス数
  * デフォルトnone
  * 搭載予定Pod数+αの値を設定する
* [WARM_IP_TARGET](https://github.com/aws/amazon-vpc-cni-k8s#warm_ip_target)
  * ノードが確保する余剰IPアドレス数
  * デフォルトnone
  * このパラメータが設定されると、`WARM_ENI_TARGE`は無視される

1ノードに8Pod程度（deamonset、deploymentなど）搭載が予想されたため、下記の様に設定を行いました。

* `MINIMUM_IP_TARGE: 10`
* `WARM_IP_TARGET: 2`

aws-nodeではこれらのパラメータを環境変数で設定出来、下記コマンドで設定が可能です。

```
kubectl set env -n kube-system daemonset/aws-node MINIMUM_IP_TARGET=10 WARM_IP_TARGET=2
```

または、aws-node daemonsetのmanifestに下記を追加しapplyすることでも設定が可能です。（該当箇所のみ記載しております）

```
spec:
  template:
    spec:
      containers:
      - name: aws-node
        env:
        - name: "MINIMUM_IP_TARGET"
          value: "10"
        - name: "WARM_IP_TARGET"
          value: "2"
```

設定された環境変数は下記コマンドで確認が可能です。

```
kubectl get daemonset -n kube-system aws-node -o yaml |yq -r '.spec.template.spec.containers[] |select ( .name == "aws-node" ).env'
```

この設定により、インスタンスタイプm5.xlargeのノードが確保するIPは 30→12 に減らすことが出来ました。

## EKSアドオン環境における設定方法

EKS v1.18以降では、いくつかのdaemonsetを[EKSアドオン](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/eks-add-ons.html)としてeksctlや[CFn](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-eks-addon.html)などから管理が可能となりました。aws-nodeも対応しており、弊社はCFnで[aws-nodeをEKSアドオンとして管理](https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/managing-vpc-cni.html)しております。

残念ながら、CFnでは環境変数を設定するオプションは現在提供されておりません・・・。そのため、上記の`kubectl set env`を実行する方法でお茶を濁している状況です。

AWSのコンテナロードマップには、EKSアドオンから`MINIMUM_IP_TARGET`や`WARM_IP_TARGET`を設定を変更できるようにする[issue](https://github.com/aws/containers-roadmap/issues/1333)が発行されているので、ゆくゆくはCFnからオプションとして設定が可能になるだろうと期待しております。

同じ気持ちの方は、是非issueへ👍をお願いします。

# まとめ
* EKSのノードはaws-node daemonsetのデフォルト設定により、多数のPrivate IPアドレスが確保されてしまい（m5.xlargeの場合最低で30IP）、思いがけずPrivate IP枯渇に直面する可能性があります。
* aws-nodeの環境変数`MINIMUM_IP_TARGET`や`WARM_IP_TARGET`を設定することで、ノードが確保するIPアドレスを抑制することが出来、IP枯渇を回避することが可能です。
* ただし、環境変数は現在EKSアドオンからは設定できず、`kubectl set env`コマンドなどを実行し設定する必要があります。（ゆくゆく設定が可能になるだろうと期待しております）