コンテンツにスキップ

リソース定義@Karpenter

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. EC2NodeClass

EC2NodeClass とは

NodePool 内の Node に AWS 固有の仕様を設定する。

Cluster スコープな Kubernetes リソースであるため、Namespace は設定できない。

Terraform の aws_launch_template ブロックと競合する。


amiFamily

AWS AMI の種類を設定する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  # 最適化 Amazon Linux 2 を指定する
  amiFamily: AL2


amiSelectorTerms

EC2 Node の AMI を設定する。

AMI のバージョンを固定したい場合に役立つ。

設定しない場合、Karpenter は最適化 AMI を自動的に選択する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  amiSelectorTerms:
    - name: ami-*****


blockDeviceMappings

プロビジョニングする EC2 Node のブロックデバイスを設定する。

100Gi 以上のルートボリュームのデバイスパス (/dev/xvda) を設定しないと、ボリューム不足で Node をプロビジョニングできず、エラーになってしまう。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  blockDeviceMappings:
    - deviceName: /dev/xvda
      ebs:
        volumeSize: 100Gi
        volumeType: gp3
        encrypted: true


detailedMonitoring

EC2 Node の CloudWatch による監視を設定する。


metadataOptions

EC2 Node のメタデータへのアクセスを制御する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  metadataOptions:
    httpEndpoint: enabled
    httpProtocolIPv6: disabled
    httpPutResponseHopLimit: 2
    httpTokens: required


instanceProfile

IAM ロールの代わりに使用する IAM インスタンスプロファイル名を設定する。

プライベートな EKS Cluster (アウトバウンド通信を禁止している) の場合、IAM ロールの代わりに IAM インスタンスプロファイルを使用する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  instanceProfile: foo-instance-profile


role

IAM プロファイル名の代わりに使用する IAM ロールを設定する。

プライベートな EKS Cluster (アウトバウンド通信を禁止している) の場合、IAM ロールの代わりに IAM インスタンスプロファイルを使用する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  role: foo-node-role


securityGroupSelectorTerms

EC2 Node に紐づけるセキュリティグループを動的に検出するために、クラスターセキュリティグループのリソースを設定する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  securityGroupSelectorTerms:
    - tags:
        Name: foo-private-sg


subnetSelectorTerms

EC2 Node をプロビジョニングするサブネットを動的に検出するために、サブネットのリソースを設定する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  subnetSelectorTerms:
    - tags:
        Name: foo-private-subnet


status

karpenter-controller が EC2 Node を作成するために取得した情報を自動的に設定する。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
status:
  amis:
    - id: ami-*****
      name: foo-ami
      requirements:
        - key: kubernetes.io/arch
          operator: In
          values:
            - arm64
        - key: karpenter.k8s.aws/instance-gpu-count
          operator: DoesNotExist
        - key: karpenter.k8s.aws/instance-accelerator-count
          operator: DoesNotExist
  instanceProfile: foo-cluster-*****
  securityGroups:
    - id: sg-*****
      name: foo-cluster*****
  subnets:
    - id: subnet-*****
      zone: ap-northeast-1c
    - id: subnet-*****
      zone: ap-northeast-1d
    - id: subnet-*****
      zone: ap-northeast-1a


tags

▼ tags

NodePool 配下の EC2 Node、またこれに紐づく AWS リソース (例:EBS ボリュームなど) に挿入するタグを設定する。

なお、NodePool 配下の EC2 Node は起動テンプレートから作成する。ただし、起動テンプレート自体は EC2 Node の作成後に削除される。

▼ デフォルトのタグ

Karpenter が EC2 Node にデフォルトで挿入するタグは上書きしないように、設定しない。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  tags:
    # AWS は Karpenter がプロビジョニングした AWS リソースにタグを挿入する
    aws:ec2:fleet-id: fleet-*****
    aws:ec2launchtemplate:id: lt-*****
    aws:ec2launchtemplate:version: 1
    aws:eks:cluster-name: foo-cluster
    # Karpenter は、カスタムリソースと EC2 の状態を紐づけるためのタグを挿入する
    karpenter.sh/managed-by: foo-cluster
    karpenter.sh/nodeclaim: foo-claim-*****
    karpenter.sh/nodepool: foo-nodepool
    karpenter.k8s.aws/ec2nodeclass: foo-node-class
    karpenter.k8s.aws/cluster: foo-cluster
    # Amazon EKS にとってはセルフマネージド Node になるため、Karpenter はセルフマネージド Node として認識されるようにタグを挿入してくれる
    kubernetes.io/cluster/foo-cluster: owned

▼ ユーザー定義のタグ

EC2 Node に挿入するユーザー定義のタグを設定できる。

apiVersion: karpenter.k8s.aws/v1beta1
kind: EC2NodeClass
metadata:
  name: foo-node-class
spec:
  tags:
    Env: prd
    ManagedBy: https://github.com/hiroki-hasegawa/foo-karpenter.git
    # Karpenter が管理することがわかりやすいように、接尾辞は "karpenter" とする
    Name: bar-cluster-foo-karpenter
    karpenter.sh/discovery: foo-cluster

▼ IRSA 用 IAM ロールの条件と一致させる

ここで挿入するタグと、AWS IAM ポリシーの条件で指定するタグと一致させる必要がある。

{
  "Statement": [

        {
            "Action": "ec2:RunInstances",
            "Condition": {
                "StringEquals": {
                    # Karpenter の EC2NodeClass で挿入した起動テンプレートのタグを指定する
                    "ec2:ResourceTag/karpenter.sh/discovery": [
                        "foo-cluster",
                    ]
                }
            },
            "Effect": "Allow",
            "Resource": "arn:aws:ec2:*:<アカウントID>:launch-template/*",
            "Sid": ""
        },

  ...

  "Version": "2012-10-17"
  ]
}

もちろん、Karpenter 以外の方法 (例:Terraform など) で挿入したタグを使用してもよい。


userData

プロビジョニングする EC2 Node のユーザーデータを設定する。


02. NodePool

NodePool とは

NodePool 内の Node にクラウドプロバイダーに依らない仕様を設定する。

EC2 Node のグループ (例:Amazon EKS Node グループ、Google Cloud Node プールなど) に合わせて、複数作成するとよい。

Cluster スコープな Kubernetes リソースであるため、Namespace は設定できない。


disruption

▼ consolidationPolicy

Node 統合の条件を設定する。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  disruption:
    consolidationPolicy: WhenUnderutilized

▼ consolidateAfter

EC2 Node から Pod がすべて退避した後に EC2 Node を削除するまでの待機時間を設定する。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  disruption:
    consolidateAfter: 30s

▼ expireAfter

EC2 Node を削除し、再作成するまでの期間を設定する。

EC2 Node を定期的に再作成することにより、最適なスペックを再設定するため、脆弱性抑制やコスト削減につながる。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  disruption:
    expireAfter: 720h


limits

プロビジョニングする EC2 Node が持つハードウェアリソース (CPU、メモリ) の上限を設定する。

Karpenter 配下の EC2 Node のハードウェアリソースがこれを超過した場合に、既存の Node を削除しないと、新しいものをプロビジョニングできない。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  limits:
    cpu: 1000m
    memory: 1024Mi


weight

複数の Provisioner がある場合に、この Provisioner の優先順位の高さを設定する。

デフォルトでは、重みが 0 である。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  weight: 10


02-02. .template.metadata

annotations

EC2 Node に付与するアノテーションを設定する。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    metadata:
      annotations:
        example.com/owner: my-team


02-03. .template.spec

kubelet

kubelet の KubeletConfiguration オプションにパラメーターを渡す。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    spec:
      kubelet:
        clusterDNS:
          - 10.0.1.100
        containerRuntime: containerd
        systemReserved:
          cpu: 100m
          memory: 100Mi
          ephemeral-storage: 1Gi
        kubeReserved:
          cpu: 200m
          memory: 100Mi
          ephemeral-storage: 3Gi
        evictionHard:
          memory.available: 5%
          nodefs.available: 10%
          nodefs.inodesFree: 10%
        evictionSoft:
          memory.available: 500Mi
          nodefs.available: 15%
          nodefs.inodesFree: 15%
        evictionSoftGracePeriod:
          memory.available: 1m
          nodefs.available: 1m30s
          nodefs.inodesFree: 2m
        evictionMaxPodGracePeriod: 60
        imageGCHighThresholdPercent: 85
        imageGCLowThresholdPercent: 80
        cpuCFSQuota: true
        podsPerCore: 2
        maxPods: 20


▼ labels

EC2 Node に付与するラベルを設定する。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    metadata:
      labels:
        # Karpenter の管理する EC2 Node にラベルを挿入する
        node.kubernetes.io/nodetype: foo


nodeClassRef

Provisioner で使用する EC2 NodeClass 名を設定する。

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    spec:
      nodeClassRef:
        name: foo-node-class


requirements

▼ requirements とは

プロビジョニングする EC2 Node のハードウェアリソースを制限する。

制限しなかった項目は、Karpenter がよしなに設定値を選ぶ。

*実装例*

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    spec:
      requirements:
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values:
            - c
            - m
            - r
        - key: karpenter.k8s.aws/instance-cpu
          operator: In
          values:
            - 4
            - 8
            - 16
            - 32
        - key: karpenter.k8s.aws/instance-hypervisor
          operator: In
          values:
            - nitro
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values:
            - 2
        - key: topology.kubernetes.io/zone
          operator: In
          values:
            - us-west-2a
            - us-west-2b
        - key: kubernetes.io/arch
          operator: In
          values:
            - arm64
            - amd64
        - key: karpenter.sh/capacity-type
          operator: In
          values:
            # スポットインスタンス
            - spot

*実装例*

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    spec:
      requirements:
        - key: kubernetes.io/arch
          operator: In
          # ARM 製より AMD 製に対応したベースイメージのほうが多いので、AMD 製を指定する
          values:
            - amd64
        - key: karpenter.k8s.aws/instance-family
          operator: In
          # ハードウェアリソース要求量が瞬間的に増える場合、T 系を指定する
          values:
            - t3
        - key: karpenter.k8s.aws/instance-size
          operator: In
          values:
            - medium
            - large
            - xlarge
          # オンデマンドインスタンスを指定する
        - key: kubernetes.io/os
          operator: In
          values:
            - linux
        - key: karpenter.sh/capacity-type
          operator: In
          values:
            # オンデマンドインスタンス
            - on-demand

▼ 指定できるキー名


startupTaints

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    spec:
      startupTaints:
        - key: example.com/another-taint
          effect: NoSchedule


taints

apiVersion: karpenter.sh/v1beta1
kind: NodePool
metadata:
  name: foo-nodepool
spec:
  template:
    spec:
      taints:
        - key: example.com/special-taint
          effect: NoSchedule



03. グローバル設定用 ConfigMap

aws.interruptionQueueName

SQSにあるイベントを監視する場合に使用する。

たとえば、EventBridgeからSQSにスポットインスタンス停止イベントを通知しておき、これをKarpenterで監視する。

スポットインスタンスの停止前に、新しいNodeを起動できるようになる。

apiVersion: v1
kind: ConfigMap
metadata:
  name: karpenter-global-settings
  namespace: karpenter
data:
  aws.interruptionQueueName: foo-queue


aws.clusterName

apiVersion: v1
kind: ConfigMap
metadata:
  name: karpenter-global-settings
  namespace: karpenter
data:
  aws.clusterName: foo-cluster


aws.clusterEndpoint

Amazon EKS Cluster の kube-apiserver の URL を設定する。

apiVersion: v1
kind: ConfigMap
metadata:
  name: karpenter-global-settings
  namespace: karpenter
data:
  aws.clusterEndpoint: https://*****.gr7.ap-northeast-1.eks.amazonaws.com


batchMaxDuration

apiVersion: v1
kind: ConfigMap
metadata:
  name: karpenter-global-settings
  namespace: karpenter
data:
  batchMaxDuration: 10s


batchIdleDuration

apiVersion: v1
kind: ConfigMap
metadata:
  name: karpenter-global-settings
  namespace: karpenter
data:
  batchIdleDuration: 1s


04. ロギング設定用の ConfigMap

zap-logger-config

ロギングを設定する。

zap パッケージを使用しているため、設定値の種類は zap パッケージのものである。

apiVersion: v1
kind: ConfigMap
metadata:
  name: config-logging
data:
  zap-logger-config: |
    {
      "level": "debug",
      "development": "false",
      "disableStacktrace": "true",
      "disableCaller": "true",
      "sampling": {
        "initial": 100,
        "thereafter": 100
      },
      "outputPaths": ["stdout"],
      "errorOutputPaths": ["stderr"],
      # 見やすいログ形式にする
      "encoding": "console",
      "encoderConfig": {
        "timeKey": "time",
        "levelKey": "level",
        "nameKey": "logger",
        "callerKey": "caller",
        "messageKey": "message",
        "stacktraceKey": "stacktrace",
        "levelEncoder": "capital",
        "timeEncoder": "iso8601"
      }
    }


loglevel.controller

記入中...

apiVersion: v1
kind: ConfigMap
metadata:
  name: config-logging
data:
  loglevel.controller: debug


loglevel.webhook

記入中...

apiVersion: v1
kind: ConfigMap
metadata:
  name: config-logging
data:
  loglevel.webhook: error


05. Pod の .metadata.annotations キー

karpenter.sh/do-not-disrupt

長時間実行する Pod の場合、完了前に Karpenter が Node を終了しないようにする必要がある。

karpenter.sh/do-not-disrupt キーを設定すると、Pod の終了を待機できる。

apiVersion: apps/v1
kind: Deployment
spec:
  template:
    metadata:
      annotations:
        karpenter.sh/do-not-disrupt: true