この記事は Scaling Kubernetes with Karpenter: Advanced Scheduling with Pod Affinity and Volume Topology Awareness (記事公開日: 2022 年 7 月 18 日) を翻訳したものです。
この記事は、SUSE の Principal Technical Evangelist、AWS の Container Hero、そして HashiCorp Ambassador であるLukonde Mwila と共同で執筆したものです。
イントロダクション
クラウドネイティブのテクノロジーはますますユビキタスになってきており、Kubernetes はこのムーブメントの最前線にいます。現在、Kubernetes は様々な業種の組織での採用が広がっています。Kubernetes を適切に導入することで、これらの組織のワークロードにおいて、高い可用性、スケーラビリティ、回復力を実現できます。Kubernetes をクラウドコンピューティングの特徴である比類のないスケーラビリティ、弾力性と組み合わせることで、コンテナ化されたアプリケーションの回復力と可用性を強化することができます。
この紹介記事 (日本語翻訳:Karpenter のご紹介 – オープンソースの高性能 Kubernetes Cluster Autoscaler) で詳しく説明していますが、Karpenter の目的は、クラスターのワークロードが必要な時に必要なだけのコンピュートを利用できるようにすることです。
直近のアップデートで Karpenter は、Pod Affinity、Pod Anti-affinity、Pod Topology Spread、Node Affinity、nodeSelector、Resource Requests など、より高度なスケジューリング制約のサポートを追加しています。この記事では特に podAffinity
、podAntiAffinity
、Volume Topology Awareness について掘り下げ、それらが最も適しているユースケースについて詳しく説明します。
前提
この記事のサンプルを実行するためには、Karpenter がインストールされた AWS 上の Kubernetes クラスターが必要です。今回は検証のために Amazon EKS を使用します。Karpenter をアドオンとして、Terraform EKS blueprints を活用することで、 EKS クラスターの構築プロセスを自動化できます。
Pod Affinity と Pod Anti-affinity のスケジューリング
スケジューリング制約の Pod への適用は、Pod と特定の Node、または Pod 間の関係を確立することで実現されます。後者は Inter-Pod Affinity として知られています。Inter-Pod Affinity を使用することで、他の Pod との関係に基づいて、どの Pod をどの Node に配置するかを決定する際のスケジューラーのアプローチに情報を提供するルールを割り当てることができます。Inter-Pod Affinity には、Pod Affinity と Pod Anti-affinity の両方が含まれます。
Node Affinity のように、要件に応じてrequiredDuringSchedulingIgnoredDuringExecution
と preferredDuringSchedulingIgnoredDuringExecution
のルールを使用して実行することができます。その名のとおり required (必須) と preferred (優先) は、スケジューリング制約がどの程度厳密か、あるいは柔軟かを表す言葉です。Pod をスケジューリングする基準が必須のルールとして設定されたら、Kubernetes は Pod がそれを満たす Node に配置されることを保証します。同様に、優先ルールを含む Pod は最も高い優先度にマッチする Node にスケジュールされます。
Pod Affinity: podAffinity
ルールは、ラベルに基づく相互に関連性のある Pod をマッチングするようスケジューラーに通知します。新しい Pod が作成されたら、スケジューラーは新しい Pod のラベルセレクターのラベル指定に一致する Pod が動いている Node の探索を引き受けます。
Pod Anti-affinity: 対照的に podAntiAffinity
ルールは一致するラベルの条件を満たした場合に、同じ Node 上で特定の Pod が実行されることを防ぎます。
これらのルールは様々な場面で役に立ちます。例えば podAffinity
は、同じ AZ あるいは Node 内に Pod を配置し、あらゆる内部的な依存関係をサポートしたり、サービス間のネットワークレイテンシを削減する際に役に立ちます。一方で podAntiAffinity
は、高可用性を目的として、 Pod を AZ あるいは Node に分散することで単一障害点を取り除く際に役に立ちます。このようなユースケースの場合、Pod Anti-affinity のために推奨される Topology Spread Constraints は、ゾーンまたはホスト名にすることができます。これは、クラスターノードの検索範囲を決定する topologyKey プロパティを使って実装することができます。topologyKey は、Node に付与されたラベルのキーです。
podAntiAffinity
の実装の例としては、CoreDNS の Deployment が挙げられます。Deployment リソース は、podAntiAffinity
ポリシーを指定しています。これは、スケジューラーが HA と VPC DNS スロットリングを避けるために、異なる Node で CoreDNS
Pod を起動するからです。Deployment の Pod Anti-affinity の topologyKey
が hostname を指定していることがわかります。さらに podAntiAffinity
を指定すると、排他的な Node 上で Pod あるいは Pod のリソースのセットを隔離することも、一部の Pod が他の Pod のパフォーマンスに干渉するリスクを軽減することもできます。
Karpenter を使うことで、追加のインフラストラクチャの設定をすることなく、ワークロードの規模に応じて、クラスター用にプロビジョニングされた新しいコンピュートが Pod Affinity ルールを満たすようにすることができます。Karpenter はスケジュールされなかった Pod を追跡し、リソースのマニフェストで定義された必須あるいは推奨の Affinity ルールに応じて、コンピュートリソースをプロビジョニングします。
Karpenter と Pod Affinity の例
この例では、同じ AZ (アベイラビリティゾーン) の Node に Pod をスケジューリングすることを必須とする podAffinity
ルールを指定した Deployment リソースを作成します。このプロセスでは、Karpenter はスケジューリングする必要がある Pod の要件を解釈し、それらの Affinity ルールを最適な形で満たすことができる Node をプロビジョニングします。
出発点として、クラスターに Karpenter Provisioner をインストールする必要があります。Provisioner は、設定の詳細とパラメータ (Node Type、ラベル、Taint、タグ、kubelet の構成、Resource Limits、サブネットとセキュリティグループアソシエーションによるクラスターへの接続など) を指定する CRD です。この例で使用される Provisioner マニフェストは以下のとおりです。
apiVersion: karpenter.sh/v1alpha5
kind: Provisioner
metadata:
name: default
spec:
# Requirements that constrain the parameters of provisioned nodes.
# These requirements are combined with pod.spec.affinity.nodeAffinity rules.
# Operators { In, NotIn } are supported to enable including or excluding values
requirements:
- key: "karpenter.sh/capacity-type" # If not included, the webhook for the AWS cloud provider will default to on-demand
operator: In
values: ["spot", "on-demand"]
# Resource limits constrain the total size of the cluster.
# Limits prevent Karpenter from creating new instances once the limit is exceeded.
limits:
resources:
cpu: 1000
memory: 1000Gi
provider:
subnetSelector:
karpenter.sh/discovery: alpha
securityGroupSelector:
karpenter.sh/discovery: alpha
tags:
karpenter.sh/discovery: alpha
ttlSecondsAfterEmpty: 30
ターミナルで kubectl get nodes
コマンドを使用し、クラスターのすべての Node を取得するところから始めます。
これにより、じきにクラスターにデプロイするアプリケーションに対応して Karpenter が新しい Node を起動する前に、すでにある Node の状態を把握することができます。
NAME STATUS ROLES AGE VERSION
ip-10-0-0-126.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-0-193.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-0-35.eu-west-1.compute.internal Ready <none> 47h v1.21.12-eks-5308cf7
ip-10-0-1-12.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-1-73.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-3-30.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
その後、以下のマニフェストを使って Deployment リソースの作成にすすみます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 8
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- inflate
topologyKey: "topology.kubernetes.io/zone"
terminationGracePeriodSeconds: 0
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
resources:
requests:
cpu: 1
Karpenter はスケジュールされてない Pod を検知し、この Deployment の Inter-Pod Affinity の要件を満たす Node をプロビジョニングします。
NAME STATUS ROLES AGE VERSION
ip-10-0-0-126.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-0-193.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-0-35.eu-west-1.compute.internal Ready <none> 2d v1.21.12-eks-5308cf7
ip-10-0-1-12.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-1-233.eu-west-1.compute.internal Ready <none> 32m v1.21.12-eks-5308cf7 // New node
ip-10-0-1-73.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-3-30.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
新しく作成された Node のホスト名は ip-10-0-1-233.eu-west-1.compute.internal
です。
以下は、新しい Node の詳細の一部を抜粋したものです。
Name: ip-10-0-1-233.eu-west-1.compute.internal
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/instance-type=c6i.2xlarge
beta.kubernetes.io/os=linux
failure-domain.beta.kubernetes.io/region=eu-west-1
failure-domain.beta.kubernetes.io/zone=eu-west-1b
karpenter.sh/capacity-type=spot
karpenter.sh/provisioner-name=default
kubernetes.io/arch=amd64
kubernetes.io/hostname=ip-10-0-1-233.eu-west-1.compute.internal
kubernetes.io/os=linux
node.kubernetes.io/instance-type=c6i.2xlarge
topology.ebs.csi.aws.com/zone=eu-west-1b
topology.kubernetes.io/region=eu-west-1
topology.kubernetes.io/zone=eu-west-1b
Annotations: csi.volume.kubernetes.io/nodeid: {"ebs.csi.aws.com":"i-00725be7dfa8ef814"}
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
...
次に、適切なラベル (app=inflate
) を使用して関連する Pod を取得し、Pod がどのようにスケジュールされたかを確認することができます。
kubectl get pods -l app=inflate -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
inflate-588d96b7f7-2lmzb 1/1 Running 0 104s 10.0.1.197 ip-10-0-1-233.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-gv68n 1/1 Running 0 104s 10.0.1.11 ip-10-0-1-233.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-jffqh 1/1 Running 0 104s 10.0.1.248 ip-10-0-1-233.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-ktjrg 1/1 Running 0 104s 10.0.1.81 ip-10-0-1-12.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-mhjrl 1/1 Running 0 104s 10.0.1.133 ip-10-0-1-233.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-vhjl7 1/1 Running 0 104s 10.0.1.21 ip-10-0-1-233.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-zb7l8 1/1 Running 0 104s 10.0.1.18 ip-10-0-1-73.eu-west-1.compute.internal <none> <none>
inflate-588d96b7f7-zz2g4 1/1 Running 0 104s 10.0.1.207 ip-10-0-1-233.eu-west-1.compute.internal <none> <none>
このように、6 つの Pod が新しい Node ip-10-0-1-233.eu-west-1.compute.internal
にスケジュールされており、一方で他の 2 つは podAffinity
ルールの topologyKey
にしたがって同一 AZ (eu-west-1b
) にスケジュールされていることがわかるでしょう。これらの Node はすべて同じ AZ にあるため、同じトポロジーの一部となり、スケジューリングの要件を満たすことができます。
Karpenter と Pod Anti-affinity の例
2 つ目の例では、podAntiAffinity
ルールを適用し、AZ に基づいてクラスター内の異なる Node に Pod を望ましくスケジュールします。前回と同様に、Karpenter は Pod の要件を読み取り、podAntiAffinity
の設定をサポートする Node を起動します。
前の例と同様に、クラスター内のすべての Node を取得するところから始めます。
NAME STATUS ROLES AGE VERSION
ip-10-0-0-126.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-0-193.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-0-35.eu-west-1.compute.internal Ready <none> 47h v1.21.12-eks-5308cf7
ip-10-0-1-12.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-1-73.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
ip-10-0-3-30.eu-west-1.compute.internal Ready <none> 2d2h v1.21.12-eks-5308cf7
その後、Deployment リソースの作成にすすみます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: inflate
spec:
replicas: 8
selector:
matchLabels:
app: inflate
template:
metadata:
labels:
app: inflate
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 50
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- inflate
topologyKey: "topology.kubernetes.io/zone"
terminationGracePeriodSeconds: 0
containers:
- name: inflate
image: public.ecr.aws/eks-distro/kubernetes/pause:3.2
resources:
requests:
cpu: 1
Pod の要件に応じて Karpenter は新しい Node を起動します。
NAME STATUS ROLES AGE VERSION
ip-10-0-0-126.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-0-193.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-0-35.eu-west-1.compute.internal Ready <none> 2d v1.21.12-eks-5308cf7
ip-10-0-1-12.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-1-69.eu-west-1.compute.internal Ready <none> 73s v1.21.12-eks-5308cf7
ip-10-0-1-73.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
ip-10-0-3-30.eu-west-1.compute.internal Ready <none> 2d3h v1.21.12-eks-5308cf7
新しく作成された Node のホスト名は ip-10-0-1-69.eu-west-1.compute.internal
です。
以下は、新しい Node の詳細の一部を抜粋したものです。
Name: ip-10-0-1-69.eu-west-1.compute.internal
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/instance-type=c5.xlarge
beta.kubernetes.io/os=linux
failure-domain.beta.kubernetes.io/region=eu-west-1
failure-domain.beta.kubernetes.io/zone=eu-west-1b
karpenter.sh/capacity-type=spot
karpenter.sh/provisioner-name=default
kubernetes.io/arch=amd64
kubernetes.io/hostname=ip-10-0-1-69.eu-west-1.compute.internal
kubernetes.io/os=linux
node.kubernetes.io/instance-type=c5.xlarge
topology.ebs.csi.aws.com/zone=eu-west-1b
topology.kubernetes.io/region=eu-west-1
topology.kubernetes.io/zone=eu-west-1b
Annotations: csi.volume.kubernetes.io/nodeid: {"ebs.csi.aws.com":"i-0617fbc688949e367"}
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
...
前回と同様に、関連するラベルが付与された Pod を取得します。
kubectl get pods -l app=inflate -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
inflate-54cd576f79-88rt4 1/1 Running 0 101s 10.0.0.128 ip-10-0-0-35.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-bpcc7 1/1 Running 0 101s 10.0.0.49 ip-10-0-0-126.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-jdcfc 1/1 Running 0 101s 10.0.1.247 ip-10-0-1-12.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-nh8zg 1/1 Running 0 101s 10.0.1.120 ip-10-0-1-69.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-qm8dc 1/1 Running 0 101s 10.0.1.236 ip-10-0-1-69.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-vvgkg 1/1 Running 0 101s 10.0.1.18 ip-10-0-1-73.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-vzzjx 1/1 Running 0 101s 10.0.0.123 ip-10-0-0-193.eu-west-1.compute.internal <none> <none>
inflate-54cd576f79-xtwkr 1/1 Running 0 101s 10.0.1.147 ip-10-0-1-69.eu-west-1.compute.internal <none> <none>
3 つの Pod 以外のすべての Pod は、Affinity ルールの指定に従って、選択したリージョン (eu-west-1
) の異なる AZ にまたがって他の Node に分散されます。
次に、Karpenter をもうひとつの高度なスケジューリング技術である Volume Topology Awareness と一緒に使うことを検討します。
Volume Topology を意識したスケジューリング
Volume Topology Awareness 以前は、Node への Pod のスケジューリングと動的なボリュームのプロビジョニングのプロセスは独立していました。ご想像のとおり、ワークロードに予測不可能な結果が生じるという課題をもたらしていました。例えば、Persistent Volume Claim を作成すると、特定のAZ (eu-west-1a
) にボリュームが動的に作成されます。一方でそのボリュームを使用する必要がある Pod が別の AZ (eu-west-1b
) の Node に配置されると、結果的に Pod は起動に失敗します。
永続的なデータを提供するストレージボリュームに依存するステートフルなワークロードにとって、これは特に問題があります。然るべき AZ にストレージボリュームを手動でプロビジョニングすることは、非効率的かつ動的なプロビジョニングとは直感的に異なります。そこで登場するのが Topology Awareness です。
Topology Awareness は、Pod がトポロジーの要件 (今回のケースではストレージボリューム) を満たすよう Node に配置されることを担保することで、動的なプロビジョニングを補完します。Topology Awareness のスケジューリングのゴールは、 Topology リソースとワークロードの連携を提供することです。それによって、より高い信頼性と予測可能な結果を得ることができます。これは kubelet
のコンポーネントであるTopology Manager によって処理されます。つまり Topology Manager は、ステートフルなワークロードと動的に作成された Persistent Volume が正しい AZ に配置されることを担保します。
Volume Topology Awareness を使用するには、 StorageClass の volumeBindingMode
を WaitForFirstConsumer
に設定する必要があります。このプロパティは、Persistent Volume を使用する Pod によって Persistent Volume Claim が作成されるまで、Persistent Volume のプロビジョニングを遅延させます。
スケーリングイベントでは、Karpenter、スケジューラー、Topology Manager がうまく連携して動作します。これらの組み合わせにより、適切なコンピュートリソースをプロビジョニングするプロセスを最適化し、スケジュールされたワークロードを動的に作成された Persistent Volume と一致させます。
これらの技術は複数の AZ でステートフルなワークロードを実行し、信頼性のあるスケールを実現します。クラスター内のアプリケーションやデータベースをゾーンに分散させ、AZ が影響を受けた場合でも単一障害点になるのを防ぐことができます。Elastic Block Store (EBS) が AZ 固有であることを考慮した場合、ワークロードは再接続が成功したときに最初にスケジュールされたのと同じ AZ にプロビジョニングされるよう、nodeAffinity で設定する必要があります。
Karpenter と Volume Topology を考慮した例
この例では、 volumeBindingMode
が WaitForFirstConsumer
に設定されているStorageClass を使用して、20 個のレプリカを持つアプリケーションの StatefulSet を作成し、それぞれに Persistent Volume Claim を設定します。さらに、ワークロードのnodeAffinity は、eu-west-1a
AZ のトポロジーリソースにスケジュールするように指定します。
デフォルトの StorageClass を確認するためには kubectl get storageclass
コマンドを実行します。
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp2 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 3d11h
次に、それぞれの AZ の Node を取得します。
kubectl get nodes -l topology.kubernetes.io/zone=eu-west-1a
を実行すると、以下の出力が得られます。
NAME STATUS ROLES AGE VERSION
ip-10-0-0-126.eu-west-1.compute.internal Ready 4d23h v1.21.12-eks-5308cf7
ip-10-0-0-193.eu-west-1.compute.internal Ready 4d23h v1.21.12-eks-5308cf7
ip-10-0-0-35.eu-west-1.compute.internal Ready 4d21h v1.21.12-eks-5308cf7
一方で、kubectl get nodes -l topology.kubernetes.io/zone=eu-west-1b
を実行すると、以下の出力が得られます。
NAME STATUS ROLES AGE VERSION
ip-10-0-1-12.eu-west-1.compute.internal Ready 4d23h v1.21.12-eks-5308cf7
ip-10-0-1-73.eu-west-1.compute.internal Ready 4d23h v1.21.12-eks-5308cf7
ip-10-0-3-30.eu-west-1.compute.internal Ready 4d23h v1.21.12-eks-5308cf7
Node の構成が決まったら、アプリケーションのための StatefulSet と付随する LoadBalancer Service の作成にすすみます。
apiVersion: v1
kind: Service
metadata:
name: express-nodejs-svc
spec:
selector:
app: express-nodejs
type: LoadBalancer
ports:
- protocol: TCP
port: 8080
targetPort: 8080
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: express-nodejs
spec:
serviceName: express-nodejs-svc
replicas: 20
selector:
matchLabels:
app: express-nodejs
template:
metadata:
labels:
app: express-nodejs
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- eu-west-1a
containers:
- name: express-nodejs
image: lukondefmwila/express-test:1.1.4
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "500m"
ports:
- containerPort: 8080
name: express-nodejs
volumeMounts:
- name: express-nodejs
mountPath: /data
volumeClaimTemplates:
- metadata:
name: express-nodejs
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: gp2
resources:
requests:
storage: 10Gi
アプリケーションがデプロイされた後、Persistent Volume は StatefulSet のレプリカからの要求に応じて動的に作成されます。各々は適切な AZ に作成され、結果的に各 Pod レプリカの作成が完了します。これに併せて、Karpenter はStatefulSet のコンピュート要件を満たすために eu-west-1a
に新しい Node をプロビジョニングします。
ここで kubectl get nodes -l topology.kubernetes.io/zone=eu-west-1a
を実行すると、以下の出力が得られます。
NAME STATUS ROLES AGE VERSION
ip-10-0-0-126.eu-west-1.compute.internal Ready <none> 5d v1.21.12-eks-5308cf7
ip-10-0-0-176.eu-west-1.compute.internal Ready <none> 4m18s v1.21.12-eks-5308cf7
ip-10-0-0-193.eu-west-1.compute.internal Ready <none> 5d v1.21.12-eks-5308cf7
ip-10-0-0-35.eu-west-1.compute.internal Ready <none> 4d21h v1.21.12-eks-5308cf7
ip-10-0-0-4.eu-west-1.compute.internal Ready <none> 6m12s v1.21.12-eks-5308cf7
ip-10-0-0-53.eu-west-1.compute.internal Ready <none> 8m8s v1.21.12-eks-5308cf7
ip-10-0-0-96.eu-west-1.compute.internal Ready <none> 2m28s v1.21.12-eks-5308cf7
このように、Karpenter は以下の追加の Node を起動しました。
- ip-10-0-0-176.eu-west-1.compute.internal
- ip-10-0-0-4.eu-west-1.compute.internal
- ip-10-0-0-53.eu-west-1.compute.internal
- ip-10-0-0-96.eu-west-1.compute.internal
さらに、作成された Persistent Volume Claim、Persistent Volume、Pod を以下のコードで示したような適切なコマンドを実行して確認しました。
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-07ad8f9f-e14f-4760-a908-58d2c48c49ac 10Gi RWO Delete Bound default/express-nodejs-express-nodejs-11 gp2 9m53s
pvc-0c3a949a-aa2f-4244-9988-d650b409698a 10Gi RWO Delete Bound default/express-nodejs-express-nodejs-3 gp2 13m
pvc-32dfc65e-9d10-42ea-a1c1-946f25500766 10Gi RWO Delete Bound default/express-nodejs-express-nodejs-7 gp2 11m
pvc-3cf7afb9-8bf4-4a0c-8064-cc97f0cdcbd5 10Gi RWO Delete Bound default/express-nodejs-express-nodejs-9 gp2 11m
pvc-3d8d0cb8-c5f4-43ad-a3a4-a95922a13c53 10Gi RWO Delete Bound default/express-nodejs-express-nodejs-0 gp2
...
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
express-nodejs-express-nodejs-0 Bound pvc-3d8d0cb8-c5f4-43ad-a3a4-a95922a13c53 10Gi RWO gp2 14m
express-nodejs-express-nodejs-1 Bound pvc-af841cf3-634a-4314-bfd1-a1d6da9d4101 10Gi RWO gp2 13m
express-nodejs-express-nodejs-10 Bound pvc-741c0d72-7311-4063-9d9b-15942f71a9a9 10Gi RWO gp2 10m
express-nodejs-express-nodejs-11 Bound pvc-07ad8f9f-e14f-4760-a908-58d2c48c49ac 10Gi RWO gp2 10m
express-nodejs-express-nodejs-12 Bound pvc-4a91fb0a-778b-42d2-b4b7-33d5d3dc8a87 10Gi RWO gp2 9m45s
...
kubectl get pods -l app=express-nodejs -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
express-nodejs-0 1/1 Running 0 16m 10.0.0.174 ip-10-0-0-193.eu-west-1.compute.internal
express-nodejs-1 1/1 Running 0 16m 10.0.0.30 ip-10-0-0-35.eu-west-1.compute.internal
express-nodejs-10 1/1 Running 0 12m 10.0.0.235 ip-10-0-0-53.eu-west-1.compute.internal
express-nodejs-11 1/1 Running 0 12m 10.0.0.137 ip-10-0-0-53.eu-west-1.compute.internal
express-nodejs-12 1/1 Running 0 12m 10.0.0.161 ip-10-0-0-4.eu-west-1.compute.internal
...
クリーンアップ
追加コストが発生することを避けるために、この記事で紹介したサンプルに関連するプロビジョニングされたインフラストラクチャをすべて削除するようにしてください。
結論
この記事では、Karpenter を使った Kubernetes のスケジューリングについて、特に Inter-Pod Affinity と Volume Topology Awareness の高度なスケジューリング技術をサポートするためのハンズオンアプローチを取り上げました。
Karpenter についてさらに学ぶためには、ドキュメントを参照し、Kubernetes Slack ワークスペースのコミュニティチャンネル #karpenter に参加するとよいでしょう。またこのプロジェクトが気に入ったら、GitHub リポジトリに Star をつけてください。
翻訳はプロフェッショナルサービスの後藤が担当しました。原文はこちらです。