コンテンツにスキップ

リソース定義@Karpenter

はじめに

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


01. EC2NodeClass

EC2NodeClassとは

NodePool内の各EC2 Nodeの仕様を設定する。

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のブロックデバイスを設定する。


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
    # AWS 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とは

KapenterでプロビジョニングするEC2 Nodeをグループ単位で設定する。

EC2 Nodeのグループ (例:AWS 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

Karpenterがプロビジョニング可能なEC2 Nodeをハードウェアリソース合計量で設定する。

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
            - on-demand

*実装例*

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

割り込み処理を有効にする場合に、AWS SQSの名前を設定する。

別途、AWS SQSを作成し、KarpenterにAWS SQSへの権限を付与しておく必要がある。

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

AWS 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