GKE Standard の Node あたりの Pod 数上限が 256 に増えた

従来、GKE Standard における Node あたりの Pod 数上限は 110 でした。
2022 年 8 月にアップデートがあり、この上限が 256 に引き上げられたため、実際にクラスタを用意して確認してみました。

アップデートは下記のリリースノートから確認できます。

cloud.google.com

ユースケース

アップデート後も Node あたりの Pod 数上限のデフォルトは引き続き 110 となっていますが、ひとつの Node に対してより多くの Pod を収容可能にしたいというユースケースはいくつか考えられます。
例えば以下のようなケースが挙げられるでしょう。

  • Node 課金な SaaS / MW のコスト最適化
  • スケールアップ / アウトのバランス調整

なお、従来は /24 の Pod CIDR に対して 110 Pod が上限となっていたため、今回のアップデートによってネットワークアドレスの空きがより少ないクラスタ構成が可能になるのでは、という期待があるかもしれませんが、アドレスレンジは設定した Pod 数上限の倍以上が引き続き必要となります。
そのため、Node あたりの Pod 数上限を 129〜256 としたい場合は /23 を設定する必要があります。

実機検証

それでは、実際にクラスタを構築して Node あたりの Pod 数上限の引き上げが機能していることを確認したいと思います。

1. クラスタを作成する

今回のアップデートの対応バージョンは 1.23.5-gke.1300+ となっていますが、今回は最新の静的リリースである 1.24.3-gke.200 を使用して GKE Standard のクラスタを作成しました。
説明の簡単のため、ノードは 1台のみとしています。
また、Node あたりの Pod 数上限は 256 、Pod CIDR は /23 に設定しました。

作成したクラスタは以下のとおりです。

$ gcloud container clusters describe testcluster-1
...
currentMasterVersion: 1.24.3-gke.200
currentNodeCount: 1
currentNodeVersion: 1.24.3-gke.200
...
defaultMaxPodsConstraint:
  maxPodsPerNode: '110'
...
name: testcluster-1
...
nodePools:
- maxPodsConstraint:
    maxPodsPerNode: '256'
  name: default-pool
  networkConfig:
    podIpv4CidrBlock: 10.88.0.0/14
    podRange: gke-testcluster-1-pods-d26f61e4
  podIpv4CidrSize: 23
  ...

ちなみに、 Node あたりの Pod 数上限は Web コンソールの GKE クラスタ作成画面からも設定することができます。
対応していないバージョンで設定を行おうと試みたところ、図のようにエラーが表示され、この拡張がサポートされているバージョンであるかを確認できるようになっていました。

2. Pod を大量に作成する

クラスタが起動したので、1 台の Node に対して従来の上限である 110 を超える Pod を起動してみます。
下記の要領で、httpd の Pod を 245 作成しました。

$ for i in {1..245}; \
> do kubectl run httpd${i} --image=httpd; \
> done;
pod/httpd1 created
pod/httpd2 created
pod/httpd3 created
...
pod/httpd245 created

3. Pod の状態を確認する

Pod の作成が完了したので、各 Pod の STATUS を確認してみます。

$ kubectl get pods
NAME    READY   STATUS  RESTARTS     AGE
httpd1  1/1         Running 0            6m51s
httpd10 1/1         Running 0            6m18s
httpd100    1/1         Running 0                5m25s
httpd101    1/1         Running 0            5m24s
httpd102    1/1         Running 0            5m24s
httpd103    1/1         Running 0            5m23s
httpd104    1/1         Running 0            5m22s
httpd105    1/1         Running 0            5m22s
…

$ kubectl get pods | grep Running | wc -l
245

$ kubectl get pods | grep -v Running
NAME    READY   STATUS  RESTARTS     AGE

すべて起動しており、ひとつの Node に従来の上限 (110) を超える Pod を立ち上げられることが確認できました。

4. 更なる Pod の追加

更に Pod を追加してみます。
246 番目に追加した httpd の Pod はこれまでと違い、Pending になってしまいました。

$ kubectl run httpd246 --image=httpd
pod/httpd246 created

$ kubectl get pod httpd246
NAME    READY   STATUS  RESTARTS     AGE
httpd246    0/1         Pending 0            4m44s

5. kube-system の Pod を確認する

前項の httpd246 の Pod が起動できなかったのは、既にこの Node に上限いっぱいの 256 Pod が起動していたためです。
今回手動で追加した httpd の Pod は 245 まででしたが、kube-system Namespace を確認すると、Control Plane の一部としてシステム系の Pod が起動していることがわかります。
以下のように、1.24.3-gke.200 では 11 Pod が存在していました。

$ kubectl get pods -n kube-system | awk '{print $1}'
NAME
event-exporter-gke-...
fluentbit-gke-256pd-...
gke-metrics-agent-...
konnectivity-agent-...
konnectivity-agent-autoscaler-...
kube-dns-...
kube-dns-autoscaler-...
kube-proxy-gke-testcluster-1-pool-1-...
l7-default-backend-...
metrics-server-v0.5.2-...
pdcsi-node-...

$ kubectl get pods -A | grep Running | wc -l
256

Node あたりの Pod 数の上限は当然ながらシステム系の Pod を含むため、 httpd246 の Pod は起動できずスケジューリング待ちとなりました。

Control Plane の工夫

Fluent Bit の Request / Limit の引き上げ

今回のアップデートに対応するかたちで、Google Cloud が管理する Control Plane 側にもいくつかの変更が加えられています。
そのひとつが、先程の kube-system Namespace に起動している Fluent Bit です。

Fluent Bit は Pod のログを Cloud Logging に転送する役割を持っており、従来は fluentbit-gke-... という Pod 名で DaemonSet によって展開されていましたが、今回は Pod 名が fluentbit-gke-256pd-... となっています。
この違いは Node あたりの Pod 数の上限を引き上げたことに関係しているのではと考え、Pod 数の上限をデフォルトの 110 としたクラスタを別途作成し、Fluent Bit の Yaml を比較してみました。
主な差分は以下のとおりで、図の左側が Pod 数の上限をデフォルトの 110 としたクラスタ、右側が Pod 数の上限を 256 としたクラスタに展開されていた Fluent Bit の Yaml です。

fluentbit-gke-256pd-... では、Fluent Bit も Exporter もリソースの Request / Limit が引き上げられている事がわかります。 これは、Node に出力されたコンテナのログを収集する Fluent Bit の消費リソースが、Node 上に起動する Pod 数に大きく影響を受けるためと考えられます。

補足

GKE は Fluent Bit を DaemonSet で展開して各 Node のコンテナのログを Cloud Logging に転送する、という方式でクラスタレベルのロギングを実現しています。
Kubernetesクラスタレベルのロギングを行うためのアーキテクチャには 3 つの選択肢がありますので、気になる方は以下を参照ください。

kubernetes.io

Nodepool に応じた DaemonSet の展開

Node あたりの Pod 数の上限の拡張は Nodepool 毎に設定できるため、今後はひとつのクラスタに複数種類の Pod 数上限の Node が混在する可能性があります。
Fluent Bit は DaemonSet で展開されるため、fluentbit-gke の DaemonSet と fluentbit-gke-256pd の DaemonSet の使い分けが必要になります。
確認してみたところ、GKE は NodeAffinity によって Node 毎に展開する Fluent Bit を制御していることがわかりました。

以下の Yaml の差分がそれを表しています。

matchExpressions の設定を見るに、以下のような設計としているようです。

  • Pod 数上限が 8 ~ 110 の (あるいは明示的に上限をしていない) Node : 従来と同じ fluentbit-gke を展開
  • Pod 数上限が 111 ~ 256 の Node : リソースの Request / Limit を増やした fluentbit-gke-256pd を展開

まとめ

Node の Pod 数上限を 256 まで拡張できるようになったことを確認しました。
実機での確認を通じて、このアップデートに対応して Control Plane にも工夫がみられることがわかりました。