こんにちは、タカサオです!
Kubernetes 1.35 で Pod のインプレースリソースリサイズ が GA になりました。Pod を再起動せずに CPU / メモリを変更できる機能です。
今回は Amazon EKS Auto Mode(Kubernetes 1.36)を使って、実際に動作を検証してみたいと思います!
検証したのは以下の2点です。
-
kubectl patch pod --subresource resizeでインプレースリサイズができること - Deployment の
kubectl apply(resources 変更)はインプレースリサイズにならず、ローリングアップデートになること
検証環境
| 項目 | 内容 |
|---|---|
| Kubernetes バージョン | v1.36.0-eks-75e0327 |
| クラスター | Amazon EKS Auto Mode(ap-northeast-1) |
| ノードタイプ | Bottlerocket (EKS Auto, Standard) / c5a.large |
| containerd | 2.1.7+bottlerocket |
Podインプレースリサイズとは
Kubernetes 1.27 でアルファとして追加されて、1.35 で GA になった機能です(KEP-1287)。
従来は Pod のリソース(CPU/メモリ)を変更するには Pod の再作成が必要でした。Deployment だとローリングアップデートが走り、一時的に Pod 数が増えます。
インプレースリサイズを使うと、Pod を生かしたままリソースを変更できます。
コンテナの resizePolicy フィールドで再起動の有無を制御できます。
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # 再起動なしでリサイズ
- resourceName: memory
restartPolicy: NotRequired # NotRequired か RestartContainer を選べる
検証1: Podへのpatchでインプレースリサイズ
Podマニフェスト
apiVersion: v1
kind: Pod
metadata:
name: resize-test-pod
spec:
containers:
- name: app
image: public.ecr.aws/amazonlinux/amazonlinux:2023
command: ["sleep", "infinity"]
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "200m"
memory: "256Mi"
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired
リサイズ前の状態を確認
$ kubectl get pod resize-test-pod \
-o jsonpath='{.spec.containers[0].resources}' | jq .
{
"limits": {"cpu": "200m", "memory": "256Mi"},
"requests": {"cpu": "100m", "memory": "128Mi"}
}
--subresource resize でパッチ
kubectl patch pod resize-test-pod --subresource resize --type merge \
-p '{
"spec": {
"containers": [{
"name": "app",
"resources": {
"requests": {"cpu": "250m", "memory": "256Mi"},
"limits": {"cpu": "500m", "memory": "512Mi"}
}
}]
}
}'
リサイズ後の状態
$ kubectl get pod resize-test-pod \
-o jsonpath='{.spec.containers[0].resources}' | jq .
{
"limits": {"cpu": "500m", "memory": "512Mi"},
"requests": {"cpu": "250m", "memory": "256Mi"}
}
$ kubectl get pod resize-test-pod \
-o jsonpath='{.status.containerStatuses[0].resources}' | jq .
{
"limits": {"cpu": "500m", "memory": "512Mi"},
"requests": {"cpu": "250m", "memory": "256Mi"}
}
spec と status.containerStatuses[].resources が一致しているのでリサイズ完了です。
RESTARTSが0のまま
NAME READY STATUS RESTARTS AGE
resize-test-pod 1/1 Running 0 50m
再起動なしでリサイズできました!
イベントでも確認できる
ResizeStarted Pod resize started: {"containers":[{"name":"app","resources":...}],"generation":2}
ResizeCompleted Pod resize completed: {"containers":[{"name":"app","resources":...}],"generation":2}
ResizeStarted → ResizeCompleted のイベントが記録されていて、インプレースリサイズが正常に完了したことが分かります。
検証2: Deploymentのapplyはローリングアップデートになる
インプレースリサイズが使えるのは --subresource resize を指定した kubectl patch のみです。Deployment の spec.template の resources を変更して kubectl apply しても、インプレースリサイズは行われません。
変更前のPod一覧(UIDを記録しておく)
NAME UID CPU_REQ
resize-test-deploy-786c4cc4c5-6l2gf 599fbc62-576c-4ccc-b241-3e5635a0f1e8 100m
resize-test-deploy-786c4cc4c5-rtkct c5ed67a0-1b46-4431-95bc-657d159e0077 100m
resourcesを変更してapply
CPU の requests/limits を変更して kubectl apply します。
kubectl apply -f deployment.yaml
ローリングアップデートの様子
Waiting for deployment "resize-test-deploy" rollout to finish: 1 out of 2 new replicas have been updated...
Waiting for deployment "resize-test-deploy" rollout to finish: 1 old replicas are pending termination...
deployment "resize-test-deploy" successfully rolled out
変更後のPod一覧
NAME UID CPU_REQ
resize-test-deploy-59887c9dbc-529h9 18a19c19-bc97-46c2-873b-f28a9e986765 300m
resize-test-deploy-59887c9dbc-ccnxb 1633285a-3e62-4645-ac60-741d7e77c5a6 300m
UID が完全に変わっています。Pod が再作成(ローリングアップデート)されたことの証拠です。
検証結果まとめ
| 操作 | 挙動 | Pod 再起動 |
|---|---|---|
kubectl patch pod --subresource resize |
インプレースリサイズ | なし(RESTARTS=0) |
Deployment の kubectl apply(resources 変更) |
ローリングアップデート(Pod 再作成) | あり(新 Pod が作られる) |
インプレースリサイズは Pod に直接 patch を当てる操作でしか発動しないというのが分かりました。
EKS Auto ModeでハマったIAMの話
今回の検証ではクラスター構築で IAM 周りにハマりました。同じ構成を試す方の参考になればと思って残しておきます。
ハマり1: トラストポリシーに sts:TagSession が必要
EKS Auto Mode はノードを起動する際、クラスターロールを Assume してセッションタグ(eks:eks-cluster-name)を注入します。このタグが AmazonEKSComputePolicy の条件式 ${aws:PrincipalTag/eks:eks-cluster-name} で評価されます。
sts:TagSession がトラストポリシーにないと、EKS がクラスターロールを Assume できず、CreateLaunchTemplate / CreateFleet が一切実行されません。NodeClaim が "User is not authorized" のままになってノードが起動しません。
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": {"Service": "eks.amazonaws.com"},
"Action": ["sts:AssumeRole", "sts:TagSession"]
}]
}
ドキュメントを読み直したら 公式の Cluster IAM role のページ にちゃんと書いてありました。見落としていました。
ハマり2: クラスターロール自体にeksクラスター名タグが必要
AmazonEKSComputePolicy の条件式は ${aws:PrincipalTag/eks:eks-cluster-name} でロール自体のタグを参照しています。タグがないと CreateLaunchTemplate の条件が一致せず拒否されます。
aws iam create-role \
--role-name "$CLUSTER_ROLE_NAME" \
--assume-role-policy-document "$CLUSTER_TRUST" \
--tags Key=eks:eks-cluster-name,Value="$CLUSTER_NAME"
ハマり3: NodeClassのInstanceProfileReadyがFalseのまま
EKS Auto Mode で Karpenter がインスタンスプロファイルを作成しますが、SLR(AWSServiceRoleForAmazonEKS)のポリシー(v25)には iam:AddRoleToInstanceProfile と iam:TagInstanceProfile が含まれていないため、プロファイルへのロールとタグの付与ができません。
手動で対処する必要がありました。
# ノードロールをアタッチ
aws iam add-role-to-instance-profile \
--instance-profile-name "$PROFILE_NAME" \
--role-name "$NODE_ROLE_NAME"
# 必要なタグを付与
aws iam tag-instance-profile \
--instance-profile-name "$PROFILE_NAME" \
--tags \
Key="eks:eks-cluster-name",Value="$CLUSTER_NAME" \
Key="eks:kubernetes-node-class-name",Value="default"
# NodeClass に変更を当てて re-reconcile を促す
kubectl patch nodeclass default --type=merge \
-p '{"spec":{"ephemeralStorage":{"size":"82Gi"}}}'
これはちょっと面倒でした。今後のポリシーアップデートで解消されると良いなと思います。
まとめ
今回は Kubernetes 1.35 GA の Pod インプレースリサイズを EKS Auto Mode で検証してみました。
-
Pod への
--subresource resizepatch → インプレースリサイズ成功、RESTARTS=0 -
Deployment の
kubectl apply(resources 変更) → ローリングアップデート(Pod 再作成)
ステートフルなワークロードや起動コストの高いアプリで使うと効果が大きそうです。EKS Auto Mode の IAM 周りはドキュメントをしっかり読まないとハマるポイントが多かったです。
それではまた!