Karpenterお試し
なにもの
Cluster Autoscalerの代替になりえるコントローラー
実行前に用意するもの
AWSリソースへのタグ付け karpenter.sh/discovery: クラスター名 (任意のkey: valueにも変えられるかも)
EKSクラスター
サブネット(ワーカーノードが使用するもの)
セキュリティグループ(ワーカーノードが使用するもの)
IAMロール(Karpenterが起動するノード用)
マネージドノードグループ用のロール使いまわしでも権限的に支障はない
インスタンスプロファイル(Karpenterが起動するノード用)
aws-authへの追加
IAMロール(Karpenterが起動するノード用)を新たに設けた場合
追加内容はマネージドノードグループ用ロールと同じでよい
code:yaml
- "groups":
- "system:bootstrappers"
- "system:nodes"
"rolearn": "arn:aws:iam::123412341234:role/karpenter-worker-role"
"username": "system:node:{{EC2PrivateDNSName}}"
起動テンプレート
なくてもよいが事前に作っておいて「これを使え」とKarpenterに指示することもできる
実行
とりあえずインストールするためのhelmfile.yaml
code:helmfile.yaml
repositories:
- name: karpenter
releases:
- name: karpenter
namespace: karpenter
createNamespace: true
chart: karpenter/karpenter
values:
- serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123412341234:role/karpenter
- clusterName: my-cluster
- aws:
defaultInstanceProfile: KarpenterNodeInstanceProfile
つかいかた
kind: Provisionerリソースを定義
どんなノードを立ててほしいのか、要望を書いたドキュメントのようなもの
Namespacedリソースだが、同一Namespace内のPodにしか反応しないわけではない
code:yaml
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
# ノードに付けたいラベル
labels:
node-type: karpenter
# ノードの要件
requirements:
- key: node.kubernetes.io/instance-type
operator: In
- key: karpenter.sh/capacity-type
operator: In
# ノードの総資源量(台あたりではない)
limits:
resources:
cpu: "1000"
provider:
subnetSelector:
karpenter.sh/discovery: tsue1
securityGroupSelector:
karpenter.sh/discovery: tsue1
# 空になったノードをx秒後に終了
ttlSecondsAfterEmpty: 30
勝手が違う点
生まれるノード
EKSの観点からいうと “self-managed node” にあたる。
ただのEC2インスタンスで、ノードグループにもオートスケーリンググループにも所属しない。
→"groupless"
https://www.youtube.com/watch?v=43g8uPohTgc
ノードの更新
Karpenterノードには「更新」という概念は直接的には存在しない。
kubectl delete nodeで削除すると、インスタンスも終了する。ノードが減って一部のPodがPendingになると、また新しいノードが起動される。このときProvisionerでAMIを固定していなければ新しいAMIが利用されて、実質的には更新される。
ttlSecondsUntilExpired が設定されたProvisionerによって起動したノードは、有効期限が来ると削除される。このときノードが足りない状態になると新しいノードが起動されて、実質的には更新される。
起動したノードは起動しっぱなし
Podのスケジューリングが詰まっているとき、Provisionerリソースの要望にしたがってノードを起動するが、ユーザーの入力やTTLによって削除するべきタイミングが来るまではなにもしない。
ノードの起動後にProvisionerのspecが変更されても、起動済みのノードをそれに合わせるために変更・終了(再作成)したりはしない。
どれくらい速いのか(超簡易)
スケール対象のPodが入る既存ノードがない状態で開始
Deploymentのレプリカを0->3にスケールさせる
1台に1Pod入るサイズなので3台必要
PodがすべてRunningになるまでの時間
code:deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 0
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
terminationGracePeriodSeconds: 0
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
resources:
requests:
cpu: "1"
nodeSelector:
node-type: karpenter
Cluster Autoscaler
約2分
Karpenter
約1分
その他見て取れたこと
Cluster Autoscalerの場合、default-schedulerがPodを配置するのを待つ分遅れる
NodeがReadyになるまではPending、Readyになってから配置されContainerCreating→Running
Karpenterの場合、default-schedulerの配置に任せず、NodeがReadyになる前からPodをNodeに割り当てる
kube-proxyなどと同じタイミングでContainerCreatingになり始める(datadog-agentより早い)
監視の観点などから望ましくない(早すぎて監視から漏れる)可能性もある