EKSのワーカーノードで使用できるPodの制限緩和を行いました

はじめに

こんにちは!技術統括本部SREユニットに所属している岡田です。SREでは、ちょっとしたテスト環境としてAmazon Elastic Kubernetes Service (EKS)を使用しております。EC2インスタンス(ワーカーノード)はセルフマネージド型ワーカーノードであり、ネットワークなどの構成管理をTerraformで行っています。低価格なインスタンスタイプで契約をしているのですが、使用できるIPアドレスの最大数に限りがありデプロイできるPod数がかなり少ないという課題を抱えていました。ところが、この制限数を緩和できるというニュースがAWSから出されました。以下に示すEKSの物理構成図の赤枠の部分について構成の改善を行いましたので、その過程と結果を共有できればと思います。

f:id:optim-tech:20211105180333p:plain

EKSの構成

EKSでは、Kubernetes(K8s)用のAmazon VPC Container Networking Interface(CNI)プラグインがデフォルトで入っています(必須ではありません)。これを使用することで、Amazon Virtual Private Cloud (VPC)から各PodにIPアドレスを割り当てています。このCNIプラグインはK8s Nodeである各EC2にaws-nodeという名前でDaemonSetとしてデプロイされており、主に2つのコンポーネントで構成されています。

  • L-IPAMデーモン
    • Network Interfaceの作成と、EC2インスタンスへのアタッチ、Network InterfaceへのセカンダリIPアドレスの割り当て、スケジューリングされた際にKubernetes Podに割り当てるための各ノードにおけるIPアドレスのウォームプールのメンテナンスを行います。つまり、デプロイする各PodにはEC2インスタンスにアタッチされたNetwork Interfaceの1つから1つのセカンダリプライベートIPアドレスが割り当てられるということです。割り当て可能なIPアドレスの数は、EC2インスタンスのインスタンスタイプに依存します。インスタンスタイプとそれがサポートするPodの最大数はこちらのページから確認できます。
  • CNIプラグイン
    • ホストネットワークの接続とPod名前空間への正しいNetwork Interfaceの追加を行います。

このように、今まではEC2インスタンスタイプによって使用できるPodの数が制限されていました。VPC CNIプラグインを使用してPodにIPを割り当てる流れを論理構成図にしたものを以下に示します。SREはインスタンスタイプt3a.mediumで契約しています。Elastic Network Interface(ENI)が3つ、それぞれのENIでで使用できるプライベートIPアドレス(プライマリIPアドレス、セカンダリIPアドレス)が6つで 3 \times 6=18, つまり使用できるIPは18個であるといえそうです。しかしながら、EC2インスタンス自体にプライマリIPアドレスの1つを割り当てるため17がPodの最大数です。インスタンスタイプごとの使用できるENI・IPの数はこちらを参照してください。

f:id:optim-tech:20211105180343p:plain

ノードあたりのPodの制限の緩和

そんな中で、Amazon VPC Container Networking InterfaceプラグインがノードあたりのPodの制限を緩和したというニュースが2021年8月に出されました。EC2インスタンスに紐付けられているENIに、IPアドレスプレフィックスを関連づけることができる新しいVPC機能が実装されたというリリースです。これにより、Network Interfaceの1つから1つのセカンダリプライベートIPアドレスを割り当てる代わりに、/28(16 IP)のIPアドレスプレフィックスを割り当てられるようになりました。このプレフィックス割り当て機能を有効にすると、Podの最大数を変更することができます。ノード1台あたりに配置可能な最大Pod数は以下の式から算出できます。


(利用するインスタンスタイプに割り当て可能な\mathrm{ENI}の数 \times (\mathrm{ENI}ごとのスロット数制限 - 1) \times 16)

式に代入する値はこちらで確認できます。また、Podの最大数を変更した場合の論理構成図はどう変化するかを図示したものを以下に示します。

f:id:optim-tech:20211105180338p:plain

Podの最大数を変更する前の論理構成図ではVPCからセカンダリIPアドレスがENIに付与されていた(VPC CNIプラグインに制御されていた)所が、全て/28 IPアドレスプレフィックスに置き換わっています。インスタンスタイプがt3a.mediumの場合にはENIが3つ、ENI1つあたりに 16 \times 5個のIPが割り振られるため 3 \times 16 \times 5で240個のIPが割り当て可能であることがわかります。 しかしながら、1ノードあたりの最大Pod数は110とこちらで制約として掲げられているため、110を設定すべきだと考えられます。それでも、今までのPodの最大数が17であることを考えれば非常に大きな変化です。

以上から、今回はSREで使用しているEKSのAmazon VPC CNIプラグインとワーカーノードを更新し、1つのノードあたりに使用できる最大のPod数を110にすることを目指しました。

手法

AWSのAmazon EC2 ノードで使用可能なIPアドレスの量を増やすを参考に、Amazon VPC CNIのバージョン更新・パラメータの設定、EKSワーカーノードの設定の更新の2点を行いました。手法の最後には、更新を反映させるためにインスタンスの再作成を行いました。

  1. Amazon VPC CNIの更新
    1. 目的: IPアドレスプレフィックスの割り当てを可能にする
    2. 変更箇所
      1. Amazon VPC CNIのバージョンを1.9以上にする(既にバージョンが1.9以上の場合はこの手順をスキップ)
      2. ENABLE_PREFIX_DELEGATION=trueを設定し、IPアドレスプレフィックスの割り当てを有効にする
      3. WARM_PREFIX_TARGET=1を設定する(これを0に設定すると、PodへのIP割り当てが非常に遅くなる(参考))
    3. 作業手順
      1. Amazon VPC CNIのバージョンを1.9以上にする
        1. GithubのChangelogを参照し、最新のマイナーバージョンを確認
        2.  kubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2
          

          でクラスターのAmazon VPC CNIアドオンバージョンを確認(この時点でバージョンが1.9以上であることが判明したら、2. ENABLE_PREFIX_DELEGATION=trueを設定するの手順までスキップ)

        3.  curl -o aws-k8s-cni.yaml https://raw.githubusercontent.com/aws/amazon-vpc-cni-k8s/release-1.9/config/v1.9/aws-k8s-cni.yaml
          

          で更新に必要なマニフェストファイルをダウンロード

        4.  sed -i.bak -e 's/us-west-2/<region-code>/' aws-k8s-cni.yaml
          

          でマニフェストファイル内リージョンコードを置き換え(<region-code>にはクラスターがあるリージョンを設定)

        5.  sed -i.bak -e 's/602401143452/<account>/' aws-k8s-cni.yaml
          

          でマニフェストファイル内のアカウントを置き換え(<account>にはクラスターがあるリージョンのアドレスから取得したアカウントを設定)

        6.  kubectl apply -f aws-k8s-cni.yaml
          

          でマニフェストファイルをクラスターに適用

      2. ENABLE_PREFIX_DELEGATION=trueを設定する
        1.  kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
          

          で設定

      3. WARM_PREFIX_TARGET=1を設定
        1.  kubectl set env daemonset aws-node -n kube-system WARM_PREFIX_TARGET=1
          

          で設定

  2. EKSワーカーノードの設定の更新
    1. 目的: 1つのワーカーノードで使用できるPod数の制限を110に変更する
    2. 変更箇所
      1. EKSワーカーノードグループの設定を行うmoduleにてuserdataのパラメータ(--kubelet-extra-args, --use-max-pods)を追加
      2. root moduleにてuserdataのパラメータ(--kubelet-extra-args, --use-max-pods)を追加
    3. 作業内容
      1. EKSワーカーノードグループの設定を行うmoduleにてuserdataのパラメータを追加
        1. --kubelet-extra-argsで設定したい引数を変数として切り出し
        2. --use-max-podsのboolean値を変数として切り出し
      2. root moduleにてuserdataのパラメータを追加
        1. variables.tfファイルに新規に切り出した変数を追記
        2. terraform.tfvarsファイルに、新規に切り出した変数の設定値を追記
      3. terraform planで変更内容を確認し、terraform applyで変更を反映

結果

AWSコンソールや、kubectl describe node <node_name>実行結果のAllocatable.podsでPodの数が110になっていることを確認できます。以上の手順により、1つのワーカーノードグループで使用できるPodの最大数を110に変更することができました。しかしながら、物理構成図にもあるようにVPCで設定しているプライベートサブネットのCIDRのプレフィックス長が/20(ホスト部の自由度が4096)であり、Podに割り振れるIPアドレスに非常に余裕があるためうまくいったという背景もあります。

追加検証

Amazon VPC CNIの構成管理を行えないかどうかを調査しました。Helmを使用した場合、aws_eks_addonリソースをroot moduleに加えた場合について検証しました。

  1. 目的: コードでの構成管理を行い、ヒューマンエラーを取り除く
  2. 結果
    1. Helmを使う場合
      • デフォルトで入っているVPC CNIプラグインのバージョンと衝突してしまい、更新不可
    2. aws_eks_addonリソースを使う場合
      • 更新可能

参考資料

おわりに

今回はEKSのワーカーノードで使用できるPodの制限緩和を行いました。簡単なテスト環境としては十分なPod数となり、何か試したい時に新しくPodを作成できるかどうかを気にしなくても良さそうです。設定を更新するうちにEKS・VPC CNIプラグインの様々なパラメータを調べましたが、そもそもこの制限緩和を行うためにはサブネットの分割方法が考えられていることが必要であったり、Terraformなどで構成管理されていることで変更が容易になるということも今回の実装で学んだ点になります。構成管理の重要さを噛み締めながら、今後も業務に取り組んでいこうと思います。


OPTiMでは、クラウドサービスを用いたインフラ構築経験、構成管理ツールによるInfrastructure as Codeの運用経験のある方など、随時エンジニアを募集しております。

www.optim.co.jp