

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Kubernetes データプレーン
<a name="scale-data-plane"></a>

EC2 インスタンスタイプの選択は、複数のワークロードを持つクラスターでお客様が直面する最も難しい決定の 1 つである可能性があります。すべてのソリューションを one-size-fitsことはできません。スケーリングコンピューティングの一般的な落とし穴を回避するのに役立つヒントをいくつか紹介します。

## 自動ノード自動スケーリング
<a name="_automatic_node_autoscaling"></a>

負荷を減らし、Kubernetes と深く統合するノードの自動スケーリングを使用することをお勧めします。[マネージド型ノードグループ](https://docs.aws.amazon.com/eks/latest/userguide/managed-node-groups.html)と [Karpenter](https://karpenter.sh/) は、大規模なクラスターに推奨されます。

マネージド型ノードグループは、Amazon EC2 Auto Scaling グループの柔軟性と、マネージド型アップグレードと設定の利点を提供します。[Kubernetes Cluster Autoscaler ](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler)を使用してスケーリングでき、さまざまなコンピューティングニーズを持つクラスターの一般的なオプションです。

Karpenter は、AWS によって作成されたオープンソースのワークロードネイティブノードオートスケーラーです。ノードグループを管理せずに、リソース (GPU など) のワークロード要件とテイントと許容範囲 (ゾーンスプレッドなど) に基づいてクラスター内のノードをスケーリングします。ノードは EC2 から直接作成されるため、デフォルトのノードグループクォータである 1 グループあたり 450 ノードが回避され、運用オーバーヘッドが少なく、インスタンス選択の柔軟性が向上します。可能な場合は Karpenter を使用することをお勧めします。

## さまざまな EC2 インスタンスタイプを使用する
<a name="_use_many_different_ec2_instance_types"></a>

各 AWS リージョンでは、インスタンスタイプごとに使用できるインスタンスの数に制限があります。1 つのインスタンスタイプのみを使用するクラスターを作成し、そのリージョンの容量を超えてノード数をスケールすると、使用可能なインスタンスがないというエラーが表示されます。この問題を回避するには、クラスターで使用できるインスタンスのタイプを任意に制限しないでください。

Karpenter は、デフォルトで互換性のあるインスタンスタイプの幅広いセットを使用し、保留中のワークロード要件、可用性、コストに基づいてプロビジョニング時にインスタンスを選択します。[NodePools](https://karpenter.sh/docs/concepts/nodepools/#instance-types) の `karpenter.k8s.aws/instance-category`キーで使用されるインスタンスタイプのリストを拡張できます。

Kubernetes Cluster Autoscaler では、ノードグループを一貫してスケーリングできるように、同じサイズにする必要があります。CPU とメモリのサイズに基づいて複数のグループを作成し、個別にスケーリングする必要があります。[ec2-instance-selector](https://github.com/aws/amazon-ec2-instance-selector) を使用して、ノードグループ用に同じサイズのインスタンスを識別します。

```
ec2-instance-selector --service eks --vcpus-min 8 --memory-min 16
a1.2xlarge
a1.4xlarge
a1.metal
c4.4xlarge
c4.8xlarge
c5.12xlarge
c5.18xlarge
c5.24xlarge
c5.2xlarge
c5.4xlarge
c5.9xlarge
c5.metal
```

## API サーバーの負荷を軽減するためにより大きなノードを優先する
<a name="_prefer_larger_nodes_to_reduce_api_server_load"></a>

使用するインスタンスタイプを決定する場合、Kubernetes コントロールプレーンの負荷が少なくなります。kubelets と DaemonSets の実行が少なくなるためです。ただし、大きなノードは小さなノードのように完全には使用できない場合があります。ノードサイズは、ワークロードの可用性とスケール要件に基づいて評価する必要があります。

3 つの u-24tb1.metal インスタンス (24 TB のメモリと 448 コア) を持つクラスターには 3 つの kubelets があり、デフォルトでノードあたり 110 ポッドに制限されます。ポッドがそれぞれ 4 つのコアを使用している場合、これは想定されている可能性があります (4 つのコア x 110 = 440 コア/ノード）。3 ノードクラスターでは、1 つのインスタンスの停止がクラスターの 1/3 に影響を与える可能性があるため、インスタンスインシデントを処理する機能は低くなります。Kubernetes スケジューラがワークロードを適切に配置できるように、ワークロードにノード要件とポッドスプレッドを指定する必要があります。

ワークロードは、必要なリソースと、テイント、許容範囲、[PodTopologySpread](https://kubernetes.io/blog/2020/05/introducing-podtopologyspread/) を介して必要な可用性を定義する必要があります。コントロールプレーンの負荷を軽減し、運用を削減し、コストを削減するには、完全に利用できる最大のノードを好み、可用性の目標を達成する必要があります。

リソースが利用可能な場合、Kubernetes スケジューラは自動的にアベイラビリティーゾーンとホスト間でワークロードを分散しようとします。使用可能な容量がない場合、Kubernetes Cluster Autoscaler は各アベイラビリティーゾーンにノードを均等に追加しようとします。Karpenter は、ワークロードが他の要件を指定しない限り、可能な限り迅速かつ安価にノードを追加しようとします。

スケジューラと新しいノードを使用してワークロードをアベイラビリティーゾーンに分散させるには、topologySpreadConstraints を使用する必要があります。

```
spec:
  topologySpreadConstraints:
    - maxSkew: 3
      topologyKey: "topology.kubernetes.io/zone"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment
    - maxSkew: 2
      topologyKey: "kubernetes.io/hostname"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment
```

## ワークロードのパフォーマンスを一定にするために同様のノードサイズを使用する
<a name="_use_similar_node_sizes_for_consistent_workload_performance"></a>

ワークロードは、一貫したパフォーマンスと予測可能なスケーリングを可能にするために実行する必要があるノードのサイズを定義する必要があります。500m CPU をリクエストするワークロードは、4 コアのインスタンスと 16 コアのインスタンスで動作が異なります。T シリーズインスタンスなどのバースト CPU CPUs。

ワークロードの一貫したパフォーマンスを確保するために、ワークロードは[サポートされている Karpenter ラベル](https://karpenter.sh/docs/concepts/scheduling/#labels)を使用して特定のインスタンスサイズをターゲットにできます。

```
kind: deployment
...
spec:
  template:
    spec:
    containers:
    nodeSelector:
      karpenter.k8s.aws/instance-size: 8xlarge
```

Kubernetes Cluster Autoscaler を使用してクラスターでスケジュールされているワークロードは、ラベルマッチングに基づいてノードセレクタとノードグループを一致させる必要があります。

```
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/nodegroup
            operator: In
            values:
            - 8-core-node-group    # match your node group name
```

## コンピューティングリソースを効率的に使用する
<a name="_use_compute_resources_efficiently"></a>

コンピューティングリソースには、EC2 インスタンスとアベイラビリティーゾーンが含まれます。コンピューティングリソースを効果的に使用すると、スケーラビリティ、可用性、パフォーマンスが向上し、総コストが削減されます。複数のアプリケーションを使用する Auto Scaling 環境では、効率的なリソース使用量を予測することは非常に困難です。[Karpenter](https://karpenter.sh/) は、ワークロードのニーズに基づいてインスタンスをオンデマンドでプロビジョニングし、使用率と柔軟性を最大化するために作成されました。

Karpenter を使用すると、ワークロードはまずノードグループを作成したり、特定のノードのラベルテイントを設定したりすることなく、必要なコンピューティングリソースのタイプを宣言できます。詳細については、[Karpenter のベストプラクティス](https://docs.aws.amazon.com/eks/latest/best-practices/karpenter.html)を参照してください。Karpenter プロビジョナーで[統合](https://docs.aws.amazon.com/eks/latest/best-practices/karpenter.html#_scheduling_pods)を有効にして、使用率の低いノードを置き換えることを検討してください。

## Amazon マシンイメージ (AMI) の更新を自動化する
<a name="_automate_amazon_machine_image_ami_updates"></a>

ワーカーノードコンポーネントを最新の状態に保つことで、Kubernetes API と互換性のある最新のセキュリティパッチと機能を確保できます。kubelet の更新は Kubernetes 機能の最も重要なコンポーネントですが、OS、カーネル、およびローカルにインストールされたアプリケーションパッチを自動化すると、スケーリングに伴うメンテナンスが軽減されます。

ノードイメージには、最新の [Amazon EKS 最適化 Amazon Linux 2](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html) または [Amazon EKS 最適化 Bottlerocket AMI ](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html)を使用することをお勧めします。Karpenter は、[利用可能な最新の AMI](https://karpenter.sh/docs/concepts/nodepools/#instance-types) を自動的に使用して、クラスター内に新しいノードをプロビジョニングします。マネージド型ノードグループはノードグループの更新中に AMI [を更新します](https://docs.aws.amazon.com/eks/latest/userguide/update-managed-node-group.html)が、ノードのプロビジョニング時に AMI ID は更新されません。

Managed Node Groups の場合、Auto Scaling Group (ASG) 起動テンプレートをパッチリリースに使用できる新しい AMI IDs で更新する必要があります。AMI マイナーバージョン (1.23.5 から 1.24.3 など) は、[ノードグループのアップグレード](https://docs.aws.amazon.com/eks/latest/userguide/update-managed-node-group.html)として EKS コンソールと API で使用できます。パッチリリースバージョン (1.23.5 から 1.23.6 など) は、ノードグループのアップグレードとして表示されません。AMI パッチリリースでノードグループを最新の状態に保つ場合は、新しい起動テンプレートバージョンを作成し、ノードグループにインスタンスを新しい AMI リリースに置き換えさせる必要があります。

利用可能な最新の AMI は[、このページ](https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami.html)から検索することも、AWS CLI を使用することもできます。

```
aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.24/amazon-linux-2/recommended/image_id \
  --query "Parameter.Value" \
  --output text
```

## コンテナに複数の EBS ボリュームを使用する
<a name="_use_multiple_ebs_volumes_for_containers"></a>

EBS ボリュームには、ボリュームのタイプ (gp3 など) とディスクのサイズに基づいて入出力 (I/O) クォータがあります。アプリケーションがホストと単一の EBS ルートボリュームを共有する場合、ホスト全体のディスククォータを使い果たし、他のアプリケーションが使用可能な容量を待機する可能性があります。アプリケーションは、オーバーレイパーティションにファイルを書き込んだり、ホストからローカルボリュームをマウントしたり、使用するログ記録エージェントに応じて標準出力 (STDOUT) にログアウトしたりすると、ディスクに書き込みます。

ディスク I/O の枯渇を回避するには、2 番目のボリュームをコンテナ状態フォルダ (/run/containerd など) にマウントし、ワークロードストレージに個別の EBS ボリュームを使用し、不要なローカルログ記録を無効にする必要があります。

[eksctl](https://eksctl.io/) を使用して EC2 インスタンスに 2 番目のボリュームをマウントするには、この設定でノードグループを使用できます。

```
managedNodeGroups:
  - name: al2-workers
    amiFamily: AmazonLinux2
    desiredCapacity: 2
    volumeSize: 80
    additionalVolumes:
      - volumeName: '/dev/sdz'
        volumeSize: 100
    preBootstrapCommands:
    - |
      "systemctl stop containerd"
      "mkfs -t ext4 /dev/nvme1n1"
      "rm -rf /var/lib/containerd/*"
      "mount /dev/nvme1n1 /var/lib/containerd/"
      "systemctl start containerd"
```

terraform を使用してノードグループをプロビジョニングする場合は、[「Terraform の EKS 設計図](https://aws-ia.github.io/terraform-aws-eks-blueprints/patterns/stateful/#eks-managed-nodegroup-w-multiple-volumes)」の例を参照してください。Karpenter を使用してノードをプロビジョニングする場合は、ノードのユーザーデータ[https://karpenter.sh/docs/concepts/nodeclasses/#specblockdevicemappings](https://karpenter.sh/docs/concepts/nodeclasses/#specblockdevicemappings)で を使用してボリュームを追加できます。

EBS ボリュームをポッドに直接マウントするには、[AWS EBS CSI ドライバー](https://github.com/kubernetes-sigs/aws-ebs-csi-driver)を使用し、ストレージクラスでボリュームを消費する必要があります。

```
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: public.ecr.aws/docker/library/nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim
```

## ワークロードで EBS ボリュームを使用する場合、EBS アタッチ制限が低いインスタンスを避ける
<a name="_avoid_instances_with_low_ebs_attach_limits_if_workloads_use_ebs_volumes"></a>

EBS は、ワークロードに永続的ストレージを持たせる最も簡単な方法の 1 つですが、スケーラビリティにも制限があります。各インスタンスタイプには、ア[タッチできる EBS ボリュームの最大数があります](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/volume_limits.html)。ワークロードは、実行するインスタンスタイプを宣言し、Kubernetes テイントを持つ 1 つのインスタンスでレプリカの数を制限する必要があります。

## ディスクへの不要なログ記録を無効にする
<a name="_disable_unnecessary_logging_to_disk"></a>

本番環境でデバッグログ記録を使用してアプリケーションを実行せず、ディスクへの読み取りと書き込みを頻繁に行うログ記録を無効にすることで、不要なローカルログ記録を回避できます。Journald は、ログバッファをメモリに保持し、定期的にディスクにフラッシュするローカルログ記録サービスです。Journald は、すべての行をディスクにすぐにログに記録する syslog よりも優先されます。syslog を無効にすると、必要なストレージの合計量も減り、複雑なログローテーションルールが不要になります。syslog を無効にするには、次のスニペットを cloud-init 設定に追加します。

```
runcmd:
  - [ systemctl, disable, --now, syslog.service ]
```

## OS 更新速度が必要なときにインスタンスにパッチを適用する
<a name="_patch_instances_in_place_when_os_update_speed_is_a_necessity"></a>

**重要**  
インスタンスのパッチ適用は、必要な場合にのみ行う必要があります。Amazon では、インフラストラクチャをイミュータブルとして扱い、アプリケーションと同じように低い環境を通じて昇格される更新を徹底的にテストすることをお勧めします。このセクションは、それが不可能な場合に適用されます。

コンテナ化されたワークロードを中断することなく、既存の Linux ホストにパッケージをインストールするには数秒かかります。パッケージは、インスタンスを接続、ドレイン、または置き換えることなくインストールおよび検証できます。

インスタンスを置き換えるには、まず新しい AMIs を作成、検証、配布する必要があります。インスタンスには代わりのインスタンスを作成し、古いインスタンスを接続およびドレインする必要があります。次に、新しいインスタンスでワークロードを作成し、検証して、パッチを適用する必要があるすべてのインスタンスに対して繰り返す必要があります。ワークロードを中断することなくインスタンスを安全に置き換えるには、数時間、数日、数週間かかります。

Amazon では、自動化された宣言型システムから構築、テスト、昇格されるイミュータブルなインフラストラクチャの使用を推奨していますが、システムへの迅速なパッチ適用が必要な場合は、新しい AMIs が利用可能になったときにシステムへのパッチ適用と置き換えを行う必要があります。パッチ適用とシステムの置き換えには大きな時間差があるため、必要に応じて [AWS Systems Manager Patch Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/systems-manager-patch.html) を使用してパッチ適用ノードを自動化することをお勧めします。

ノードにパッチを適用すると、AMI の更新後にセキュリティ更新をすばやくロールアウトし、定期的にインスタンスを置き換えることができます。[Flatcar Container Linux](https://flatcar-linux.org/) や [Bottlerocket OS](https://github.com/bottlerocket-os/bottlerocket) などの読み取り専用ルートファイルシステムでオペレーティングシステムを使用している場合は、それらのオペレーティングシステムで動作する更新演算子を使用することをお勧めします。[Flatcar Linux 更新演算子](https://github.com/flatcar/flatcar-linux-update-operator)と [Bottlerocket 更新演算子](https://github.com/bottlerocket-os/bottlerocket-update-operator)はインスタンスを再起動して、ノードを自動的に最新の状態に保ちます。