

 **Bantu tingkatkan halaman ini** 

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

Untuk berkontribusi pada panduan pengguna ini, pilih **Edit halaman ini pada GitHub** tautan yang terletak di panel kanan setiap halaman.

Terjemahan disediakan oleh mesin penerjemah. Jika konten terjemahan yang diberikan bertentangan dengan versi bahasa Inggris aslinya, utamakan versi bahasa Inggris.

# Siapkan klaster Amazon EKS untuk AI/ML beban kerja menggunakan CLI
<a name="ml-cluster-setup-cli"></a>

**Tip**  
 [Daftar](https://events.eksworkshop.com/workshops/genai/) untuk AI/ML lokakarya Amazon EKS mendatang.

Bagian ini memandu Anda melalui langkah-langkah untuk membuat infrastruktur yang diperlukan untuk menjalankan beban kerja pelatihan atau inferensi di Amazon EKS melalui perintah CLI. Langkah-langkahnya termasuk membuat cluster EKS, GPU-enabled node dengan Mode Otomatis EKS atau Karpenter, tumpukan pemantauan dengan Prometheus dan Grafana, dan penyimpanan Amazon S3 untuk bobot model.

Lihat dokumentasi untuk [Mode Otomatis EKS](https://docs.aws.amazon.com/eks/latest/userguide/automode.html) dan [Karpenter](https://karpenter.sh/docs/) untuk informasi selengkapnya tentang bagaimana fitur tersebut menyediakan dan menskalakan instans EC2 secara otomatis di kluster EKS.

 **High-level arsitektur dan alur kerja** 

![High-level arsitektur yang menampilkan klaster EKS dengan Karpenter NodeClass dan NodePool, penulisan tumpukan pemantauan Grafana dan Prometheus ke Amazon Managed Service for Prometheus, bucket Amazon S3 untuk bobot model, dan langkah alur kerja bernomor](http://docs.aws.amazon.com/id_id/eks/latest/userguide/images/ml-cluster-setup-architecture.png)


Diagram menunjukkan arsitektur AWS tingkat tinggi untuk pengaturan bagian ini. Langkah-langkah bernomor di sebelah kanan menunjukkan urutan di mana Anda menyelesaikan konfigurasi pada langkah-langkah di bawah ini.

## Prasyarat
<a name="cluster-setup-cli-prerequisites"></a>
+  `kubectl`>= 1,35. Untuk petunjuk penyiapan, lihat[`Siapkan kubectl dan eksctl`](install-kubectl.md).
+  AWS CLI >= 2.27. Untuk petunjuk penyiapan, lihat [Menginstal](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html).
+ Helm >= 3.14. Untuk petunjuk penyiapan, lihat [Setup Helm](helm.md).
+  `jq`. Untuk petunjuk penyiapan, lihat [Unduh jq](https://jqlang.github.io/jq/download/).
+  `eksctl`>= 0.227.0. Untuk petunjuk penyiapan, lihat [Instalasi](https://eksctl.io/installation) dalam `eksctl` dokumentasi.

Verifikasi `eksctl` versi Anda:

```
eksctl version
```

Jika Anda menggunakan versi yang lebih lama dari 0.227.0, ikuti [panduan instalasi eksctl](https://eksctl.io/installation/) untuk meningkatkan ke rilis terbaru.

## Tetapkan variabel lingkungan
<a name="cluster-setup-cli-set-environment-variables"></a>

Jaga agar nama klaster dan AWS Wilayah berikut tetap konsisten di seluruh langkah ini. Mengubahnya dapat menyebabkan perintah berikutnya menargetkan cluster EKS yang salah.

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

Menggunakan semua AZ yang tersedia meningkatkan toleransi kesalahan dan meningkatkan peluang mendapatkan kapasitas GPU:

```
export AZS=$(aws ec2 describe-availability-zones \
  --region ${AWS_REGION} \
  --query "AvailabilityZones[?ZoneId!='use1-az3' && ZoneId!='usw1-az2' && ZoneId!='cac1-az3'].ZoneName" \
  --output text | tr '\t' ',')
echo $AZS
```

**penting**  
Availability Zones `use1-az3``usw1-az2`,, dan `cac1-az3` dikecualikan karena [Amazon EKS tidak mendukung penempatan pesawat kontrol di zona tersebut](https://repost.aws/knowledge-center/eks-cluster-creation-errors). Membuat cluster dengan subnet di salah satu zona ini menghasilkan file`UnsupportedAvailabilityZoneException`.

Keluaran yang diharapkan

```
us-east-2a,us-east-2b,us-east-2c
```

AZ dalam output akan bervariasi per wilayah. Contoh ini menunjukkan AZ yang tersedia untuk `us-east-2` wilayah.

## Buat cluster dan GPU NodePool
<a name="cluster-setup-cli-create-cluster-and-gpu-nodepool"></a>

Bagian ini menyediakan dua jalur untuk membuat kluster dan GPU-enabled node EKS Anda, yang ditunjukkan pada diagram berikut. Pilih hanya satu opsi di seluruh panduan.
+  **Mode Otomatis EKS** — Selain [add-on jaringan inti, penyimpanan, dan penyeimbangan beban,](https://docs.aws.amazon.com/eks/latest/userguide/eks-add-ons.html#addon-consider-auto) Mode Otomatis EKS menyertakan dan mengelola kemampuan berikut untuk beban kerja pelatihan dan inferensi: agen pemantauan simpul EKS, perbaikan node otomatis, snapshotter [SOCI](https://github.com/awslabs/soci-snapshotter) untuk penarikan kontainer cepat, dan kesiapan GPU untuk default. NodeClass Plugin perangkat NVIDIA termasuk dalam AMI yang dipercepat Bottlerocket yang digunakan Mode Otomatis EKS untuk node. GPU-enabled 
+  **Self-managed Karpenter** — Pada cluster EKS tanpa Mode Otomatis EKS, Anda bertanggung jawab untuk menginstal dan mengonfigurasi komponen yang diperlukan untuk beban kerja pelatihan dan inferensi. Ini termasuk add-on jaringan (VPC CNI, CoreDNS, kube-proxy), Karpenter, agen pemantauan node EKS, plugin perangkat NVIDIA, dan snapshotter SOCI untuk penarikan kontainer cepat.

 **Opsi kluster EKS: Mode Otomatis EKS dan Karpenter yang dikelola sendiri** 

![Side-by-side perbandingan dua opsi cluster: cluster Mode Otomatis EKS dengan NodePool, dan kluster standar EKS dengan Karpenter yang dikelola sendiri, CoreDNS, VPC CNI, plugin perangkat NVIDIA, agen Identitas Pod EKS, Agen Pemantauan Node, kube-proxy, dan a dan NodeClass NodePool](http://docs.aws.amazon.com/id_id/eks/latest/userguide/images/ml-cluster-setup-cli-cluster-options.png)


Di setiap langkah berikut, pilih jalur (Mode Otomatis EKS, Karpenter) dan ikuti seluruhnya. Setelah menyelesaikan langkah-langkah untuk jalur yang Anda pilih, Anda akan memiliki cluster EKS dengan GPU yang NodePool siap menjadwalkan beban kerja GPU.

## Langkah 1: Buat klaster
<a name="cluster-setup-cli-create-cluster"></a>

Mulailah dengan membuat kluster EKS Anda dan menginstal komponen cluster yang diperlukan untuk beban kerja GPU.

Dengan Mode Otomatis EKS, satu `eksctl create cluster --enable-auto-mode` perintah menyediakan kluster EKS yang siap untuk beban kerja GPU.

Dengan Karpenter yang dikelola sendiri, `eksctl create cluster` perintah tersebut menyediakan add-on jaringan inti, kemudian langkah-langkah tambahan diperlukan untuk mengaktifkan perbaikan node otomatis melalui gerbang fitur Karpenter, menginstal agen pemantauan node EKS, dan menginstal plugin perangkat NVIDIA.

------
#### [ EKS Auto Mode ]

 **Buat kluster Mode Otomatis EKS** 

```
eksctl create cluster \
  --name=$CLUSTER_NAME \
  --region=$AWS_REGION \
  --enable-auto-mode \
  --version=1.35 \
  --zones=$AZS
```

Perintah ini membutuhkan waktu beberapa menit untuk menyelesaikannya. Setelah selesai, `eksctl` secara otomatis memperbarui file kubeconfig Anda agar berfungsi dengan cluster yang baru disediakan. Verifikasi bahwa cluster beroperasi:

```
kubectl get pods --all-namespaces
```

Keluaran yang diharapkan

```
NAMESPACE     NAME                              READY   STATUS    RESTARTS   AGE
kube-system   metrics-server-55cf976ddd-cz2mw   1/1     Running   0          3m
kube-system   metrics-server-55cf976ddd-wrjvv   1/1     Running   0          3m
```

Dalam Mode Otomatis EKS, VPC CNI, kube-proxy, dan CoreDNS berjalan sebagai komponen terkelola dan tidak muncul sebagai pod. `kube-system`

------
#### [ Self-managed Karpenter ]

 **Otentikasi Helm ke ECR publik** 

 `eksctl`menarik bagan Karpenter Helm dari Amazon Public ECR. Otentikasi sebelum membuat cluster untuk menghindari kesalahan 403 pada langkah instalasi Helm:

```
aws ecr-public get-login-password --region us-east-1 \
  | helm registry login --username AWS --password-stdin public.ecr.aws
```

ECR publik adalah layanan global yang diselenggarakan di`us-east-1`. Gunakan `--region us-east-1` di sini terlepas dari wilayah mana cluster EKS Anda berada.

Output yang diharapkan: `Login Succeeded` 

 **Buat cluster EKS dengan Karpenter** 

Simpan versi Karpenter Anda dalam variabel lingkungan untuk digunakan nanti. Untuk versi Karpenter terbaru, lihat rilis [Karpenter](https://github.com/aws/karpenter-provider-aws/releases) di. GitHub

```
export KARPENTER_VERSION=1.12.0
```

### Konfigurasi cluster YAMB dan `eksctl` membuat cluster
<a name="cluster-setup-cli-step1-karpenter-cluster-yaml"></a>

```
cat << EOF > /tmp/cluster-karpenter.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: ${CLUSTER_NAME}
  region: ${AWS_REGION}
  version: "1.35"
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}

availabilityZones: [$(echo $AZS | sed 's/,/, /g')]

autoModeConfig:
  enabled: false

iam:
  withOIDC: true

karpenter:
  version: "${KARPENTER_VERSION}"
  withSpotInterruptionQueue: true

managedNodeGroups:
  - name: system
    instanceType: m6i.2xlarge
    desiredCapacity: 2
    minSize: 2
    maxSize: 3
    labels:
      node-role: system
    tags:
      karpenter.sh/discovery: ${CLUSTER_NAME}

addons:
  - name: eks-pod-identity-agent
  - name: eks-node-monitoring-agent
EOF

eksctl create cluster -f /tmp/cluster-karpenter.yaml
```

Perintah ini memakan waktu sekitar 15 menit. Ini menciptakan cluster EKS dengan grup node terkelola yang didedikasikan untuk hosting add-on dan pengontrol Karpenter. Karpenter dipasang dengan antrean interupsi Spot diaktifkan sehingga dapat menangani gangguan Spot dan rekomendasi penyeimbangan kembali. `autoModeConfig.enabled: false`Pengaturan membuatnya eksplisit bahwa cluster ini tidak menggunakan Mode Otomatis EKS, sehingga komponen Karpenter yang dipasang di jalur ini bertanggung jawab untuk manajemen node.

Cluster ini juga mendapatkan [Agen Identitas Pod EKS dan agen](https://docs.aws.amazon.com/eks/latest/userguide/pod-identities.html) [pemantauan node EKS](https://docs.aws.amazon.com/eks/latest/userguide/node-health.html) diinstal sebagai add-on EKS. EKS Pod Identity digunakan nanti dalam panduan. Agen pemantauan node EKS berjalan pada setiap node dan membaca log kernel untuk mengatur kondisi node seperti`AcceleratedHardwareReady`,, dan `KernelReady``NetworkingReady`, yang digunakan perbaikan node otomatis Karpenter untuk memutuskan kapan harus mengganti node yang tidak sehat.

Verifikasi bahwa cluster beroperasi:

```
kubectl get pods --all-namespaces
```

Output yang diharapkan meliputi Karpenter, CoreDNS, kube-proxy, aws-node (VPC CNI), Agen Identitas Pod EKS, dan agen pemantauan node EKS.

```
NAMESPACE     NAME                              READY   STATUS    RESTARTS   AGE
karpenter     karpenter-567547464c-s6vkx        1/1     Running   0          3m40s
karpenter     karpenter-567547464c-x7gmw        1/1     Running   0          3m40s
kube-system   aws-node-b6gf2                    2/2     Running   0          12m
kube-system   aws-node-lcphh                    2/2     Running   0          12m
kube-system   coredns-7d4dcbf4fb-ccvrr          1/1     Running   0          16m
kube-system   coredns-7d4dcbf4fb-qbhk2          1/1     Running   0          16m
kube-system   eks-node-monitoring-agent-h79vm   1/1     Running   0          9m45s
kube-system   eks-node-monitoring-agent-tf4dw   1/1     Running   0          9m45s
kube-system   eks-pod-identity-agent-5jbtc      1/1     Running   0          12m
kube-system   eks-pod-identity-agent-rwcrc      1/1     Running   0          12m
kube-system   kube-proxy-p4bmq                  1/1     Running   0          12m
kube-system   kube-proxy-v5nwr                  1/1     Running   0          12m
kube-system   metrics-server-5b966ff79c-hr58p   1/1     Running   0          9m22s
kube-system   metrics-server-5b966ff79c-szs2d   1/1     Running   0          9m22s
```

 **Aktifkan perbaikan node otomatis** 

Mode Otomatis EKS memungkinkan perbaikan node otomatis secara default. Pada Karpenter yang dikelola sendiri, perbaikan node otomatis terjaga keamanannya di belakang gerbang `NodeRepair=true` fitur dan harus diaktifkan secara eksplisit. Perintah berikut menambal penyebaran Karpenter untuk menambahkan gerbang fitur. `NodeRepair=true` Memperbarui env penerapan memicu peluncuran pod Karpenter:

```
kubectl set env deployment/karpenter -n karpenter \
  FEATURE_GATES=NodeRepair=true
```

Keluaran yang diharapkan

```
deployment.apps/karpenter env updated
```

Tunggu pod Karpenter diluncurkan:

```
kubectl rollout status deployment/karpenter -n karpenter
```

 **Instal plugin perangkat NVIDIA** 

 EKS-optimized AL2023 AMI tidak [menyertakan plugin perangkat NVIDIA (tidak seperti](https://github.com/NVIDIA/k8s-device-plugin) AMI Bottlerocket yang digunakan oleh Mode Otomatis EKS). Instal melalui Helm untuk membuat resource GPU dapat digunakan dengan Pod di cluster.

```
helm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update
```

```
cat << 'EOF' > /tmp/nvdp-values.yaml
mofedEnabled: false
nodeSelector:
  amiFamily: al2023
gfd:
  enabled: true
nfd:
  worker:
    tolerations:
      - operator: "Exists"
EOF
```

```
helm install nvidia-device-plugin nvdp/nvidia-device-plugin \
  --namespace kube-system \
  -f /tmp/nvdp-values.yaml
```
+  `mofedEnabled: false`: menonaktifkan cek untuk Mellanox OFED (InfiniBand), yang tidak menggunakan AWS 
+  `nodeSelector.amiFamily: al2023`: mencakup node DaemonSet ke AL2023 saja (Bottlerocket sudah memiliki plugin bawaan)
+  `gfd.enabled: true`: mengaktifkan label Penemuan Fitur GPU (`nvidia.com/gpu.product`,`nvidia.com/gpu.memory`, dll.)

Verifikasi plugin perangkat NVIDIA diinstal. Harapannya adalah tidak ada Pod plugin perangkat hingga GPU NodePool dengan label yang cocok disediakan.

```
kubectl get daemonset nvidia-device-plugin -n kube-system
```

Keluaran yang diharapkan

```
NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR      AGE
nvidia-device-plugin   0         0         0       0            0           amiFamily=al2023   2m5s
```

------

**Awas**  
Untuk Mode Otomatis EKS dan jalur Karpenter yang dikelola sendiri, perbaikan node otomatis berperilaku dengan cara yang sama untuk node yang disediakan oleh. NodePools Perbaikan node otomatis di EKS Auto Mode dan Karpenter adalah metode gangguan *kuat yang memintas* PodDisruptionBudgets, anotasi, dan. `karpenter.sh/do-not-disrupt` `terminationGracePeriod` Perbaikan node otomatis menunggu 10 menit sebelum mengganti node dengan `AcceleratedHardwareReady` kondisi yang disetel ke `False` dan 30 menit untuk [kondisi perbaikan lainnya](https://docs.aws.amazon.com/eks/latest/userguide/node-repair.html).

## Langkah 2: Buat GPU dinamis NodePool
<a name="cluster-setup-cli-create-gpu-nodepool"></a>

Tentukan instans GPU NodePool yang secara dinamis G-family menyediakan instans GPU dengan generasi lebih besar dari 4, menggunakan kapasitas Spot On-Demand sebagai fallback. Jalur Mode Otomatis EKS dan Karpenter keduanya menggunakan NodePool API yang sama dengan satu-satunya perbedaan adalah yang NodeClass ditunjuknya. Dalam Mode Otomatis EKS, bundel `default` NodeClass sudah memilih AMI yang tepat dan mengonfigurasi tarikan paralel SOCI, jadi satu-satunya objek NodePool yang Anda buat. Di Karpenter yang dikelola sendiri, Anda juga memerlukan kustom `EC2NodeClass` yang menyematkan AMI dan menyetel SOCI.

------
#### [ EKS Auto Mode ]

Dalam Mode Otomatis EKS, bundel `default` NodeClass secara otomatis memilih AMI Bottlerocket untuk instance GPU, yang mencakup driver NVIDIA yang sudah diinstal sebelumnya, plugin perangkat NVIDIA, dan tarik paralel SOCI. Anda hanya perlu menerapkan a NodePool yang mereferensikan `default` NodeClass:

```
cat << 'EOF' | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: default
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: eks.amazonaws.com/instance-category
          operator: In
          values: ["g"]
        - key: eks.amazonaws.com/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

[Ini menyediakan NodePool instans G-family GPU dengan generasi lebih besar dari 4 ([G5, G6e](https://aws.amazon.com/ec2/instance-types/g5/)[, G7e, dll](https://aws.amazon.com/ec2/instance-types/g6e/).).](https://aws.amazon.com/ec2/instance-types/g7e/) `nvidia.com/gpu:NoSchedule`Taint memastikan hanya GPU-eligible Pod yang dijadwalkan pada node ini.

------
#### [ Self-managed Karpenter ]

Self-managed Karpenter tidak menyertakan default. NodeClass Pertama-tama Anda membuat `EC2NodeClass` yang menyematkan alias AMI EKS-optimized NVIDIA AL2023, mengaktifkan SOCI `FastImagePull` melalui gerbang fitur, dan `instanceStorePolicy: RAID0` mengonfigurasi untuk memindahkan cache gambar containerd ke NVMe lokal. Kemudian Anda membuat referensi NodePool itu.

 **Buat EC2NodeClass** 

### EC2NodeClass YAMM
<a name="cluster-setup-cli-step2-karpenter-ec2nodeclass-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: gpu-inf
  labels:
    guide: ai-eks-docs
spec:
  role: "eksctl-KarpenterNodeRole-${CLUSTER_NAME}"
  amiSelectorTerms:
    - alias: al2023@latest
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}
  instanceStorePolicy: RAID0
  userData: |
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary="BOUNDARY"

    --BOUNDARY
    Content-Type: application/node.eks.aws

    ---
    apiVersion: node.eks.aws/v1alpha1
    kind: NodeConfig
    spec:
      featureGates:
        FastImagePull: true
      containerd:
        config: |
          [plugins."io.containerd.snapshotter.v1.soci"]
            [plugins."io.containerd.snapshotter.v1.soci".blob]
              max_concurrent_downloads_per_image = 20
              concurrent_download_chunk_size = "16mb"
              max_concurrent_unpacks_per_image = 12
              discard_unpacked_layers = true

    --BOUNDARY--
EOF
```

 `instanceStorePolicy: RAID0`merakit disk NVMe lokal menjadi array. RAID-0 Alias `al2023@latest` AMI menyelesaikan AMI AL2023 EKS-optimized . Ketika Karpenter meluncurkan jenis instans GPU, secara otomatis memilih varian akselerasi AL2023\_X86\_64\_NVIDIA, yang mencakup driver NVIDIA yang sudah diinstal sebelumnya.

Gerbang `FastImagePull` fitur memungkinkan mode tarik paralel snapshotter SOCI, yang mengunduh dan membongkar lapisan gambar secara bersamaan. Ini cocok dengan perilaku Mode Otomatis EKS pada keluarga instance G, P, dan Trn. `containerd.config`Blok menyetel snapshotter SOCI untuk gambar: ECR-hosted 
+  `max_concurrent_downloads_per_image: 20`memungkinkan hingga 20 lapisan unduhan secara paralel per gambar. Defaultnya adalah 3 di Bottlerocket dan 20 di AL2023. Nilai yang disarankan untuk ECR.
+  `concurrent_download_chunk_size: "16mb"`membagi setiap lapisan menjadi potongan 16 MB yang diunduh secara paralel melalui permintaan rentang HTTP. Direkomendasikan untuk pendaftar yang mendukung jangkauan GET (ECR tidak).
+  `max_concurrent_unpacks_per_image: 12`membongkar hingga 12 lapisan sekaligus. Defaultnya adalah 1 di Bottlerocket dan 12 di AL2023.
+  `discard_unpacked_layers: true`menghapus gumpalan lapisan terkompresi setelah membongkar untuk menghemat ruang disk.

[Untuk opsi penyetelan SOCI lainnya (unduhan bersamaan per gambar, ukuran potongan, dll.), Lihat cetak biru Karpenter SOCI.](https://github.com/aws-samples/karpenter-blueprints/tree/main/blueprints/soci-snapshotter)

Validasi: EC2NodeClass

```
kubectl get ec2nodeclass gpu-inf
```

Output yang diharapkan:`READY True`. Jika`False`, jalankan `kubectl describe ec2nodeclass gpu-inf` dan periksa kondisi untuk tag subnet atau grup keamanan yang hilang.

 **Buat GPU NodePool** 

### NodePool YAMM
<a name="cluster-setup-cli-step2-karpenter-nodepool-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
        amiFamily: al2023
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: gpu-inf
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["g"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

`amiFamily: al2023`Label pada template node adalah apa yang DaemonSet digunakan plugin perangkat NVIDIA untuk memilih node ini.

------

Validasi yang NodePool telah dibuat:

```
kubectl get nodepool gpu-inf
```

Keluaran yang diharapkan

```
NAME      NODECLASS   NODES   READY   AGE
gpu-inf   default     0       True    8s
```

Di jalur Karpenter yang dikelola sendiri, kolom NODECLASS menunjukkan alih-alih. `gpu-inf` `default`

## Langkah 3: Uji dengan sampel Pod
<a name="cluster-setup-cli-test-with-a-sample-pod"></a>

Uji NodePool pengaturan GPU Anda dengan `nvidia-smi` Pod.

```
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nvidia-smi
  labels:
    guide: ai-eks-docs
spec:
  tolerations:
    - key: "nvidia.com/gpu"
      operator: "Exists"
      effect: "NoSchedule"
  containers:
    - name: nvidia-smi
      image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
      command: ["nvidia-smi"]
      resources:
        limits:
          nvidia.com/gpu: 1
  restartPolicy: OnFailure
EOF
```

Verifikasi bahwa Pod sudah dijadwalkan dan diselesaikan dengan sukses.

```
kubectl get pods
```

Keluaran yang diharapkan

```
NAME         READY   STATUS      RESTARTS   AGE
nvidia-smi   0/1     Completed   0          67s
```

STATUS: Selesai berarti perintah nvidia-smi berjalan dan keluar. Periksa log Pod untuk melihat GPU terdeteksi oleh node.

```
kubectl logs nvidia-smi
```

Keluaran yang diharapkan

```
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.126.09             Driver Version: 580.126.09     CUDA Version: 13.0     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA RTX PRO 6000 Blac...    On  |   00000000:2B:00.0 Off |                    0 |
| N/A   30C    P0             81W /  600W |       0MiB /  97887MiB |      0%      Default |
|                                         |                        |             Disabled |
+-----------------------------------------+------------------------+----------------------+
```

Output menunjukkan model GPU, versi driver, versi CUDA, dan memori yang tersedia. Dalam contoh ini, Karpenter menyediakan instance G7e yang memiliki GPU NVIDIA RTX PRO 6000 Blackwell dengan memori 96 GB. 30C adalah suhu GPU saat ini dan P0 berarti GPU berada dalam kondisi kinerja tertinggi (idle tapi siap). 81W/600W menunjukkan penarikan daya saat ini vs kapasitas daya maks, dan 0MiB/97887MiB menunjukkan memori GPU saat ini yang digunakan vs total yang tersedia. Karena Pod baru saja menjalankan nvidia-smi dan keluar, tidak ada beban kerja yang menggunakan GPU sehingga memori berada pada 0 dan daya saat idle. Versi driver GPU NVIDIA (580.126.09) berasal dari Bottlerocket AMI, sedangkan versi CUDA (13.0) berasal dari gambar kontainer. Model dan memori GPU akan bervariasi tergantung pada jenis instance yang dipilih Karpenter. Instans G5 memiliki GPU NVIDIA A10G (24 GB), instans G6e memiliki GPU NVIDIA L40S (48 GB), dan instance G7e memiliki GPU NVIDIA RTX PRO 6000 (96 GB).

Untuk memahami bagaimana Karpenter dan penjadwal Kubernetes berkoordinasi untuk menyediakan sebuah node dan menempatkan Pod, periksa peristiwa siklus hidup Pod:

```
kubectl describe po nvidia-smi
```

Keluaran yang diharapkan

```
Events:
  Type     Reason                  Age   From                   Message
  ----     ------                  ----  ----                   -------
  Warning  FailedScheduling        60s   default-scheduler      0/2 nodes are available: 2 node(s) had untolerated taint(s). no new claims to deallocate, preemption: 0/2 nodes are available: 2 Preemption is not helpful for scheduling.
  Normal   Nominated               59s   eks-auto-mode/compute  Pod should schedule on: nodeclaim/gpu-inf-vxcnj
  Normal   Scheduled               24s   default-scheduler      Successfully assigned default/nvidia-smi to i-0fb17a09bc4203164
  Warning  FailedCreatePodSandBox  21s   kubelet                Failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox "7f85e25b220c8fb245187758dbbbc8efb3d40f3e49e13054404880daf4c3b2f0": plugin type="aws-cni" name="aws-cni" failed (add): add cmd: failed to setup network policy
  Normal   Pulling                  7s   kubelet                spec.containers{nvidia-smi}: Pulling image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal"
  Normal   Pulled                   5s   kubelet                spec.containers{nvidia-smi}: Successfully pulled image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" in 1.237s (1.237s including waiting). Image size: 37442701 bytes.
  Normal   Created                  5s   kubelet                spec.containers{nvidia-smi}: Container created
  Normal   Started                  5s   kubelet                spec.containers{nvidia-smi}: Container started
```

Peristiwa ini menunjukkan urutan penjadwalan Pod: Pod awalnya gagal menjadwalkan karena tidak ada node GPU yang ada (FailedScheduling), Karpenter menominasikan new NodeClaim (Nominated), scheduler menetapkan Pod setelah node siap (Terjadwal), dan kemudian gambar kontainer ditarik dan dimulai. EKS Auto Mode dilengkapi dengan parallel pull SOCI (Seekable OCI) yang dipasang dan dikonfigurasi di luar kotak pada instance G, P, dan Trn. Perhatikan karena tarikan paralel SOCI, gambar kontainer ditarik dari ECR dalam waktu kurang dari 2 detik (1,237 detik).

A NodeClaim adalah permintaan Karpenter menciptakan untuk menyediakan node tertentu. Ini menunjukkan jenis instance, tipe kapasitas, AZ, dan apakah node siap.

```
kubectl get nodeclaims
```

 NodeClaim Output yang diharapkan:

```
NAME            TYPE          CAPACITY    ZONE         NODE                  READY   AGE
gpu-inf-xxxxx   g7e.2xlarge   spot        us-east-2a   i-0xxxxxxxxxxxx       True    2m
```

Jenis instans dan AZ akan bervariasi. Setiap G-family instance dengan generasi> 4 memenuhi syarat.

`FailedCreatePodSandBox`Peringatan di `kubectl describe pod nvidia-smi` bersifat sementara dan diharapkan. VPC CNI menginisialisasi secara asinkron setelah node bergabung, dan kubelet mencoba ulang secara otomatis. Jika Pod tetap berada di dalam`ContainerCreating`, periksa peristiwa node dengan`kubectl describe node <node-name>`.

**Tip**  
Jika tidak ada node yang muncul, periksa Kesalahan Kapasitas Tidak Cukup:  

```
kubectl get events | grep InsufficientCapacityError
```
Karpenter menyimpan penawaran yang tidak tersedia selama 3 menit. Memperluas jenis instans dan AZ yang diizinkan di Anda NodePool meningkatkan kemungkinan kapasitas pendaratan.

**catatan**  
Instans spot yang diluncurkan oleh Karpenter tidak akan muncul di konsol Permintaan Spot EC2. Karpenter menggunakan API EC2 [https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateFleet.html)dengan. `type: instant` Instans muncul di konsol Instans EC2 dengan siklus hidup. `spot`

## Langkah 4: Tambahkan kapasitas cadangan ke NodePool (opsional)
<a name="cluster-setup-cli-attach-odcr"></a>

Untuk menggunakan kapasitas cadangan terlebih dahulu dengan Spot/On-Demand fallback, buat ODCR dan pasang ke Anda NodeClass, lalu perbarui dinamika NodePool dari Langkah 2 untuk juga memungkinkan kapasitas. `reserved` Panggilan API reservasi sama untuk kedua jalur; NodeClass lampiran berbeda karena Mode Otomatis EKS dan Karpenter yang dikelola sendiri menggunakan jenis yang berbeda. NodeClass 

**Awas**  
Perintah berikut menghasilkan biaya untuk jenis instans yang dicadangkan hingga Anda membatalkannya`aws ec2 cancel-capacity-reservation --capacity-reservation-id <id>`.

Buat reservasi kapasitas:

```
CR_AZ="us-east-2a"
INSTANCE_TYPE="g6e.4xlarge"

aws ec2 create-capacity-reservation \
  --instance-type $INSTANCE_TYPE \
  --instance-platform Linux/UNIX \
  --availability-zone "$CR_AZ" \
  --instance-count 1 \
  --instance-match-criteria open \
  --end-date-type unlimited
```

Jika Anda mendapatkan `InsufficientInstanceCapacity` kesalahan, ubah `CR_AZ` ke AZ yang berbeda dan coba lagi.

Cari ID reservasi kapasitas dan simpan dalam variabel shell untuk langkah-langkah berikut:

```
CAPACITY_RESERVATION_ID=$(aws ec2 describe-capacity-reservations \
  --filters "Name=state,Values=active" "Name=instance-type,Values=${INSTANCE_TYPE}" \
  --query 'CapacityReservations[0].CapacityReservationId' \
  --output text \
  --region ${AWS_REGION})
echo "Capacity reservation ID: ${CAPACITY_RESERVATION_ID}"
```

Kemudian terapkan NodeClass dan NodePool perubahan untuk jalur Anda:

------
#### [ EKS Auto Mode ]

Dalam Mode Otomatis EKS, bundel `default` NodeClass hanya baca, jadi buat kustom NodeClass yang mereferensikan reservasi, lalu perbarui NodePool untuk menunjuk ke NodeClass dan tambahkan `reserved` kapasitas ke daftar. `capacity-type`

### Kustom NodeClass YAMM
<a name="cluster-setup-cli-step4-automode-nodeclass-yaml"></a>

```
NODE_ROLE=$(kubectl get nodeclass default -o jsonpath='{.spec.role}')

cat << EOF | kubectl apply -f -
apiVersion: eks.amazonaws.com/v1
kind: NodeClass
metadata:
  name: gpu-inf
  labels:
    guide: ai-eks-docs
spec:
  role: "$NODE_ROLE"
  subnetSelectorTerms:
    - tags:
        alpha.eksctl.io/cluster-name: "$CLUSTER_NAME"
        kubernetes.io/role/internal-elb: "1"
  securityGroupSelectorTerms:
    - tags:
        aws:eks:cluster-name: "$CLUSTER_NAME"
  capacityReservationSelectorTerms:
    - id: "$CAPACITY_RESERVATION_ID"
EOF
```

`kubernetes.io/role/internal-elb: "1"`Tag memastikan node diluncurkan di subnet pribadi saja.

Perbarui NodePool untuk menggunakan ODCR-backed NodeClass dan sertakan `reserved` sebagai tipe kapasitas:

### NodePool YAMB yang Diperbarui
<a name="cluster-setup-cli-step4-automode-nodepool-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
    spec:
      nodeClassRef:
        group: eks.amazonaws.com
        kind: NodeClass
        name: gpu-inf
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand", "reserved"]
        - key: eks.amazonaws.com/instance-category
          operator: In
          values: ["g"]
        - key: eks.amazonaws.com/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

------
#### [ Self-managed Karpenter ]

Untuk Karpenter yang dikelola sendiri, terapkan kembali yang `EC2NodeClass` Anda buat di Langkah 2 dengan ditambahkan. `capacityReservationSelectorTerms` Nama dan bentuk bidang cocok dengan Mode Otomatis EKS yang `NodeClass` ditampilkan di tab lainnya.

### EC2NodeClass YAMB yang Diperbarui
<a name="cluster-setup-cli-step4-karpenter-nodeclass-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
  name: gpu-inf
  labels:
    guide: ai-eks-docs
spec:
  role: "eksctl-KarpenterNodeRole-${CLUSTER_NAME}"
  amiSelectorTerms:
    - alias: al2023@latest
  subnetSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  securityGroupSelectorTerms:
    - tags:
        karpenter.sh/discovery: ${CLUSTER_NAME}
  tags:
    karpenter.sh/discovery: ${CLUSTER_NAME}
  instanceStorePolicy: RAID0
  capacityReservationSelectorTerms:
    - id: "$CAPACITY_RESERVATION_ID"
  userData: |
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary="BOUNDARY"

    --BOUNDARY
    Content-Type: application/node.eks.aws

    ---
    apiVersion: node.eks.aws/v1alpha1
    kind: NodeConfig
    spec:
      featureGates:
        FastImagePull: true
      containerd:
        config: |
          [plugins."io.containerd.snapshotter.v1.soci"]
            [plugins."io.containerd.snapshotter.v1.soci".blob]
              max_concurrent_downloads_per_image = 20
              concurrent_download_chunk_size = "16mb"
              max_concurrent_unpacks_per_image = 12
              discard_unpacked_layers = true

    --BOUNDARY--
EOF
```

Satu-satunya perubahan dari Langkah 2 adalah `capacityReservationSelectorTerms` bidang baru. Semua bidang lainnya tetap sama.

Perbarui NodePool untuk menyertakan `reserved` sebagai tipe kapasitas:

### NodePool YAMB yang Diperbarui
<a name="cluster-setup-cli-step4-karpenter-nodepool-yaml"></a>

```
cat << EOF | kubectl apply -f -
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: gpu-inf
spec:
  template:
    metadata:
      labels:
        guide: ai-eks-docs
        amiFamily: al2023
    spec:
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: gpu-inf
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand", "reserved"]
        - key: karpenter.k8s.aws/instance-category
          operator: In
          values: ["g"]
        - key: karpenter.k8s.aws/instance-generation
          operator: Gt
          values: ["4"]
        - key: kubernetes.io/arch
          operator: In
          values: ["amd64"]
  limits:
    cpu: 1000
    memory: 5000Gi
EOF
```

------

Karpenter memperlakukan `reserved` sebagai opsi yang paling hemat biaya dan meluncurkannya terlebih dahulu. Setelah reservasi penuh, itu jatuh kembali ke Spot atau On-Demand.

### Verifikasi prioritas yang dicadangkan dan Spot fallback
<a name="cluster-setup-cli-step4-validate"></a>

Setelah menerapkan perubahan, validasi bahwa Karpenter memprioritaskan kapasitas cadangan dan kembali ke Spot atau. On-Demand Menerapkan Deployment 2-replika yang meminta 1 GPU per Pod. ODCR adalah untuk 1 instance, jadi Pod pertama memicu Karpenter untuk meluncurkan node reserved. Pod kedua tidak bisa muat pada node reserved dan memicu Karpenter untuk meluncurkan node lain dari Spot atau kapasitas. On-Demand 

```
cat << 'EOF' | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: gpu-overflow-test
  labels:
    guide: ai-eks-docs
spec:
  replicas: 2
  selector:
    matchLabels:
      app: gpu-overflow-test
  template:
    metadata:
      labels:
        app: gpu-overflow-test
        guide: ai-eks-docs
    spec:
      tolerations:
        - key: nvidia.com/gpu
          operator: Exists
          effect: NoSchedule
      containers:
        - name: nvidia-smi
          image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal
          command: ["sh", "-c", "nvidia-smi && sleep infinity"]
          resources:
            limits:
              nvidia.com/gpu: 1
EOF
```

Berbeda dengan Pod `nvidia-smi` uji dari Langkah 3 yang berjalan dan keluar, Deployment ini membuat Pod tetap berjalan (`sleep infinity`) sehingga mereka menahan GPU dan tidak melepaskan node.

Verifikasi Pod yang dijadwalkan pada node yang berbeda:

```
kubectl get pods -l app=gpu-overflow-test -o wide
```

Keluaran yang diharapkan

```
NAME                                 READY   STATUS    RESTARTS   AGE     IP                NODE                  NOMINATED NODE   READINESS GATES
gpu-overflow-test-59b97944fb-lq56c   1/1     Running   0          2m42s   192.168.186.240   i-057692590480155da   <none>           <none>
gpu-overflow-test-59b97944fb-z4zcx   1/1     Running   0          2m42s   192.168.130.64    i-0521ecd1849fa0578   <none>           <none>
```

Kedua pod berjalan, masing-masing pada node yang berbeda.

Periksa NodeClaims untuk melihat jenis kapasitas:

```
kubectl get nodeclaims
```

Keluaran yang diharapkan

```
NAME            TYPE          CAPACITY    ZONE         NODE                  READY   AGE
gpu-inf-shg5w   g6e.xlarge    reserved    us-east-2a   i-0ea91fdeef65b8cb6   True    2m2s
gpu-inf-ssnqf   g7e.2xlarge   spot        us-east-2b   i-00ccf7ce65cf3f6ca   True    112s
```

Node cadangan diluncurkan terlebih dahulu, diikuti oleh Spot atau On-Demand node setelah reservasi penuh.

Bersihkan penerapan pengujian:

```
kubectl delete deployment gpu-overflow-test
```

## Memantau
<a name="cluster-setup-cli-monitoring"></a>

Instal tumpukan pemantauan yang mengumpulkan metrik cluster, node, dan GPU ke Amazon Managed Service for Prometheus (AMP), dan visualisasikan dengan Grafana. Bagan Helm kube-prometheus-stack menerapkan Prometheus untuk mengikis dan menulis metrik jarak jauh ke AMP, ditambah Grafana yang dikelola sendiri untuk dasbor. Eksportir NVIDIA DCGM menambahkan GPU-specific metrik (pemanfaatan, memori, suhu, daya, NVLink, aktivitas tensor).

Prometheus, Grafana, dan operator mendarat di node non-GPU secara default karena node GPU membawa noda. `nvidia.com/gpu:NoSchedule` Node-exporter dan Eksportir DCGM keduanya berjalan pada node GPU sehingga kami dapat mengikis metrik host dan GPU di seluruh armada.

Jika Anda membuka terminal baru, atur nama cluster dan wilayah:

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

### Membuat ruang kerja AMP
<a name="_create_the_amp_workspace"></a>

Membuat ruang kerja AMP untuk menyimpan metrik:

```
aws amp create-workspace \
  --alias "amp-ws-${CLUSTER_NAME}" \
  --region ${AWS_REGION}
```

Dapatkan ID ruang kerja:

```
AMP_WORKSPACE_ID=$(aws amp list-workspaces \
  --alias "amp-ws-${CLUSTER_NAME}" \
  --query 'workspaces[0].workspaceId' \
  --output text \
  --region ${AWS_REGION})

echo "AMP Workspace ID: ${AMP_WORKSPACE_ID}"
```

Dapatkan titik akhir penulisan jarak jauh:

```
AMP_ENDPOINT=$(aws amp describe-workspace \
  --workspace-id ${AMP_WORKSPACE_ID} \
  --query 'workspace.prometheusEndpoint' \
  --output text \
  --region ${AWS_REGION})

echo "AMP Endpoint: ${AMP_ENDPOINT}"
```

### Membuat kebijakan IAM dan asosiasi Identitas Pod EKS
<a name="_create_iam_policy_and_eks_pod_identity_associations"></a>

Buat kebijakan IAM yang memungkinkan Prometheus menulis metrik dari jarak jauh dan Grafana untuk menanyainya:

```
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

AMP_POLICY_ARN=$(aws iam create-policy \
  --policy-name "${CLUSTER_NAME}-amp-grafana-policy" \
  --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Sid\": \"AllowAMPReadWrite\", \"Effect\": \"Allow\", \"Action\": [\"aps:ListWorkspaces\", \"aps:DescribeWorkspace\", \"aps:GetMetricMetadata\", \"aps:GetSeries\", \"aps:QueryMetrics\", \"aps:RemoteWrite\", \"aps:GetLabels\"], \"Resource\": \"arn:aws:aps:${AWS_REGION}:${ACCOUNT_ID}:workspace/*\"}, {\"Sid\": \"AllowCloudWatchMetrics\", \"Effect\": \"Allow\", \"Action\": [\"cloudwatch:DescribeAlarmsForMetric\", \"cloudwatch:ListMetrics\", \"cloudwatch:GetMetricData\", \"cloudwatch:GetMetricStatistics\"], \"Resource\": \"*\"}]}" \
  --query 'Policy.Arn' \
  --output text)

echo "AMP Policy ARN: ${AMP_POLICY_ARN}"
```

Buat namespace pemantauan dan akun layanan untuk Prometheus dan Grafana:

```
kubectl create namespace monitoring
kubectl create serviceaccount amp-iamproxy-ingest-service-account -n monitoring
kubectl create serviceaccount grafana-sa -n monitoring
```

Buat Asosiasi Identitas Pod EKS untuk menautkan akun layanan ke kebijakan IAM:

```
eksctl create podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name amp-iamproxy-ingest-service-account \
  --role-name "${CLUSTER_NAME}-amp-ingest-role" \
  --permission-policy-arns ${AMP_POLICY_ARN} \
  --region ${AWS_REGION}

eksctl create podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name grafana-sa \
  --role-name "${CLUSTER_NAME}-grafana-role" \
  --permission-policy-arns ${AMP_POLICY_ARN} \
  --region ${AWS_REGION}
```

Verifikasi kedua asosiasi Identitas Pod EKS telah dibuat:

```
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
```

Output yang diharapkan harus mencakup keduanya `amp-iamproxy-ingest-service-account` dan `grafana-sa` di `monitoring` namespace.

### Instal kube-prometheus-stack
<a name="_install_kube_prometheus_stack"></a>

Tambahkan repo Helm:

```
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
```

File nilai ini menghilangkan NodeSelector untuk Prometheus, Grafana, dan operator: noda node GPU menjauhkan mereka dari node `nvidia.com/gpu:NoSchedule` GPU, sehingga mereka mendarat di sistem atau kumpulan tujuan umum secara default. Node-exporter menggunakan toleransi wildcard sehingga berjalan di setiap node — termasuk node GPU — untuk mengumpulkan metrik di seluruh armada.

Buat file nilai:

#### file nilai kube-prometheus-stack
<a name="cluster-setup-cli-monitoring-kube-prometheus-values"></a>

```
cat << EOF > /tmp/kube-prometheus-values.yaml
prometheus:
  serviceAccount:
    create: false
    name: amp-iamproxy-ingest-service-account
  prometheusSpec:
    serviceAccountName: amp-iamproxy-ingest-service-account
    remoteWrite:
      - url: "${AMP_ENDPOINT}api/v1/remote_write"
        sigv4:
          region: "${AWS_REGION}"
        queueConfig:
          maxSamplesPerSend: 1000
          maxShards: 200
          capacity: 2500
    retention: 5h
    scrapeInterval: 30s
    evaluationInterval: 30s
    podMonitorSelectorNilUsesHelmValues: false
    serviceMonitorSelectorNilUsesHelmValues: false

alertmanager:
  enabled: false

grafana:
  enabled: true
  serviceAccount:
    create: false
    name: grafana-sa
  grafana.ini:
    auth.sigv4:
      enabled: true
  sidecar:
    datasources:
      defaultDatasourceEnabled: false
  plugins:
    - grafana-amazonprometheus-datasource
  additionalDataSources:
    - name: Amazon-Managed-Prometheus
      type: grafana-amazonprometheus-datasource
      access: proxy
      url: "${AMP_ENDPOINT}"
      isDefault: true
      jsonData:
        sigV4Auth: true
        defaultRegion: "${AWS_REGION}"
        sigV4Region: "${AWS_REGION}"
      editable: true
  dashboardProviders:
    dashboardproviders.yaml:
      apiVersion: 1
      providers:
        - name: default
          orgId: 1
          folder: 'GPU Monitoring'
          type: file
          disableDeletion: false
          editable: true
          options:
            path: /var/lib/grafana/dashboards/default
  dashboards:
    default:
      nvidia-dcgm:
        gnetId: 25261
        revision: 1
        datasource:
          - name: DS_PROMETHEUS
            value: Amazon-Managed-Prometheus
      vllm:
        gnetId: 25263
        revision: 1
        datasource:
          - name: DS_PROMETHEUS
            value: Amazon-Managed-Prometheus

prometheus-node-exporter:
  tolerations:
    - operator: Exists
EOF
```

Validasi variabel diisi dengan benar:

```
grep -E "url:|region:|tolerations:" /tmp/kube-prometheus-values.yaml
```

Anda akan melihat URL titik akhir AMP lengkap (dimulai dengan`https://aps-workspaces…​`), wilayah Anda, dan baris pengekspor simpul`tolerations:`. Jika ada yang kosong, ekspor ulang variabel dan buat ulang file.

Instal bagan:

```
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  -f /tmp/kube-prometheus-values.yaml
```

Verifikasi pod sedang berjalan:

```
kubectl get pods -n monitoring
```

Keluaran yang diharapkan

```
NAME                                                       READY   STATUS    RESTARTS   AGE
kube-prometheus-stack-grafana-7c58f54f77-rftrj             3/3     Running   0          4m
kube-prometheus-stack-kube-state-metrics-d68dcbc84-5smxq   1/1     Running   0          4m
kube-prometheus-stack-operator-5895df479f-ttm47            1/1     Running   0          4m
kube-prometheus-stack-prometheus-node-exporter-t9q7s       1/1     Running   0          4m
kube-prometheus-stack-prometheus-node-exporter-x6vfb       1/1     Running   0          4m
prometheus-kube-prometheus-stack-prometheus-0              2/2     Running   0          4m
```

Tumpukan menyebarkan komponen-komponen berikut:
+  **Prometheus** StatefulSet (): menggores metrik dan menulisnya dari jarak jauh ke AMP
+  **Grafana**: dasbor dan visualisasi, dikonfigurasi sebelumnya dengan sumber data AMP
+  **kube-state-metrics: menghasilkan metrik** tentang status objek Kubernetes (status Pod, sumber daya, status) requests/limits NodeClaim 
+  **node-eksportir** (DaemonSet, satu per node): mengumpulkan metrik tingkat host (CPU, memori, disk, jaringan)
+  **operator**: mengelola sumber daya kustom Prometheus dan Alertmanager

Alertmanager dinonaktifkan dalam pengaturan ini.

### Akses Grafana
<a name="_access_grafana"></a>

Buka terminal terpisah dan port-forward untuk mengakses Grafana:

```
kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n monitoring
```

Buka [http://localhost:3000](http://localhost:3000) di browser Anda. Masuk dengan nama pengguna `admin` dan kata sandi dari perintah berikut:

```
kubectl --namespace monitoring get secrets kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo
```

Untuk memverifikasi, pipa metrik berfungsi dari ujung ke ujung:

1. Arahkan ke **Koneksi > Sumber data** dan konfirmasi `Amazon-Managed-Prometheus` terdaftar sebagai sumber data default.

    **Validasi sumber data AMP di Grafana**   
![Halaman Koneksi Grafana ditampilkan Amazon-Managed-Prometheus terdaftar sebagai sumber data default](http://docs.aws.amazon.com/id_id/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-ds-validate.png)

1. Arahkan ke **Drilldown > Metrics** dan cari metrik. `up` Anda akan melihat hasil dari target scrape cluster Anda.

    **Validasi `up` metrik di Grafana**   
![Halaman Grafana Drilldown Metrics menampilkan metrik naik dengan bilah status hijau yang menunjukkan target gesekan aktif](http://docs.aws.amazon.com/id_id/eks/latest/userguide/images/ml-cluster-setup-cli-prometheus-metrics-validate.png)

Jika `up` menunjukkan hasil, pipeline (cluster → Prometheus → AMP → Grafana) berfungsi.

### Terapkan Eksportir DCGM untuk metrik GPU
<a name="_deploy_the_dcgm_exporter_for_gpu_metrics"></a>

Kube-prometheus-stack mengumpulkan metrik CPU dan memori tingkat node tetapi bukan metrik GPU. Eksportir NVIDIA DCGM menambahkan pemanfaatan GPU, penggunaan memori, suhu, penarikan daya, bandwidth NVLink, dan aktivitas tensor.

```
helm repo add gpu-helm-charts https://nvidia.github.io/dcgm-exporter/helm-charts
helm repo update
```

Tetapkan kunci pemilih node GPU untuk jalur Anda. Mode Otomatis EKS dan Karpenter yang dikelola sendiri menggunakan kunci label yang berbeda untuk produsen GPU.

------
#### [ EKS Auto Mode ]

```
GPU_NODE_SELECTOR_KEY="eks.amazonaws.com/instance-gpu-manufacturer"
```

------
#### [ Self-managed Karpenter ]

```
GPU_NODE_SELECTOR_KEY="karpenter.k8s.aws/instance-gpu-manufacturer"
```

------

Buat file nilai eksportir DCGM:

#### berkas nilai dcgm-eksportir
<a name="cluster-setup-cli-monitoring-dcgm-values"></a>

```
cat << EOF > /tmp/dcgm-exporter-values.yaml
resources:
  requests:
    memory: "512Mi"
    cpu: "100m"
  limits:
    memory: "1Gi"
    cpu: "500m"

serviceMonitor:
  enabled: true
  additionalLabels:
    release: kube-prometheus-stack

nodeSelector:
  ${GPU_NODE_SELECTOR_KEY}: nvidia

tolerations:
  - key: "nvidia.com/gpu"
    operator: "Exists"
    effect: "NoSchedule"

customMetrics: |
  # Clocks
  DCGM_FI_DEV_SM_CLOCK,  gauge, SM clock frequency (in MHz).
  DCGM_FI_DEV_MEM_CLOCK, gauge, Memory clock frequency (in MHz).
  # Temperature
  DCGM_FI_DEV_MEMORY_TEMP, gauge, Memory temperature (in C).
  DCGM_FI_DEV_GPU_TEMP,    gauge, GPU temperature (in C).
  # Power
  DCGM_FI_DEV_POWER_USAGE,              gauge, Power draw (in W).
  DCGM_FI_DEV_TOTAL_ENERGY_CONSUMPTION, counter, Total energy consumption since boot (in mJ).
  # PCIe
  DCGM_FI_PROF_PCIE_TX_BYTES,  counter, Number of bytes transmitted through PCIe TX (in KB) via NVML.
  DCGM_FI_PROF_PCIE_RX_BYTES,  counter, Number of bytes received through PCIe RX (in KB) via NVML.
  DCGM_FI_DEV_PCIE_REPLAY_COUNTER, counter, Total number of PCIe retries.
  # Utilization (the sample period varies depending on the product)
  DCGM_FI_DEV_GPU_UTIL,      gauge, GPU utilization (in %).
  DCGM_FI_DEV_MEM_COPY_UTIL, gauge, Memory utilization (in %).
  DCGM_FI_DEV_ENC_UTIL,      gauge, Encoder utilization (in %).
  DCGM_FI_DEV_DEC_UTIL,      gauge, Decoder utilization (in %).
  # Errors and violations
  DCGM_FI_DEV_XID_ERRORS,            gauge, Value of the last XID error encountered.
  DCGM_EXP_XID_ERRORS_COUNT,         gauge, Value of count of XID errors encountered.
  DCGM_FI_DEV_POWER_VIOLATION,       counter, Throttling duration due to power constraints (in us).
  DCGM_FI_DEV_THERMAL_VIOLATION,     counter, Throttling duration due to thermal constraints (in us).
  DCGM_FI_DEV_SYNC_BOOST_VIOLATION,  counter, Throttling duration due to sync-boost constraints (in us).
  DCGM_FI_DEV_BOARD_LIMIT_VIOLATION, counter, Throttling duration due to board limit constraints (in us).
  DCGM_FI_DEV_LOW_UTIL_VIOLATION,    counter, Throttling duration due to low utilization (in us).
  DCGM_FI_DEV_RELIABILITY_VIOLATION, counter, Throttling duration due to reliability constraints (in us).
  # Memory usage
  DCGM_FI_DEV_FB_FREE, gauge, Framebuffer memory free (in MiB).
  DCGM_FI_DEV_FB_USED, gauge, Framebuffer memory used (in MiB).
  # Retired pages
  DCGM_FI_DEV_RETIRED_SBE,     counter, Total number of retired pages due to single-bit errors.
  DCGM_FI_DEV_RETIRED_DBE,     counter, Total number of retired pages due to double-bit errors.
  DCGM_FI_DEV_RETIRED_PENDING, counter, Total number of pages pending retirement.
  # NVLink
  DCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL, counter, Total number of NVLink bandwidth counters for all lanes.
  DCGM_FI_PROF_NVLINK_TX_BYTES,       counter, The rate of data transmitted over NVLink not including protocol headers in bytes per second.
  DCGM_FI_PROF_NVLINK_RX_BYTES,       counter, The rate of data received over NVLink not including protocol headers in bytes per second.
  # DCP metrics
  DCGM_FI_PROF_GR_ENGINE_ACTIVE,   gauge, Ratio of time the graphics engine is active (in %).
  DCGM_FI_PROF_SM_ACTIVE,          gauge, The ratio of cycles an SM has at least 1 warp assigned (in %).
  DCGM_FI_PROF_SM_OCCUPANCY,       gauge, The ratio of number of warps resident on an SM (in %).
  DCGM_FI_PROF_PIPE_TENSOR_ACTIVE, gauge, Ratio of cycles the tensor (HMMA) pipe is active (in %).
  DCGM_FI_PROF_DRAM_ACTIVE,        gauge, Ratio of cycles the device memory interface is active sending or receiving data (in %).
  DCGM_FI_DEV_CLOCK_THROTTLE_REASONS, gauge, Current clock throttle reasons (bitmask of DCGM_CLOCKS_THROTTLE_REASON_*).
  DCGM_FI_DEV_GPU_NVLINK_ERRORS,      gauge, Identifies a GPU NVLink error type returned by DCGM_FI_DEV_GPU_NVLINK_ERRORS.
  ## NVLink
  DCGM_FI_DEV_NVLINK_BANDWIDTH_L0, counter, The number of bytes of active NVLink rx or tx data including both header and payload.
  ## Remapped rows
  DCGM_FI_DEV_UNCORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for uncorrectable errors.
  DCGM_FI_DEV_CORRECTABLE_REMAPPED_ROWS, counter, Number of remapped rows for correctable errors.
  DCGM_FI_DEV_ROW_REMAP_FAILURE, gauge, whether remapping of rows has failed.
  ## Profiling metrics
  DCGM_FI_PROF_PIPE_FP64_ACTIVE, gauge, Ratio of cycles the fp64 pipes are active (in %).
  DCGM_FI_PROF_PIPE_FP32_ACTIVE, gauge, Ratio of cycles the fp32 pipes are active (in %).
  DCGM_FI_PROF_PIPE_FP16_ACTIVE, gauge, Ratio of cycles the fp16 pipes are active (in %).
  # ECC
  DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, counter, Total number of single-bit volatile ECC errors.
  DCGM_FI_DEV_ECC_DBE_VOL_TOTAL, counter, Total number of double-bit volatile ECC errors.
EOF
```

`customMetrics`Bidang ini mengesampingkan set metrik default eksportir DCGM dengan yang diperluas yang mencakup bandwidth NVLink, aktivitas tensor, throughput PCIe, kesalahan ECC, dan pelambatan termal. Untuk beban kerja inferensi, ini membantu Anda memahami apakah unit komputasi GPU sepenuhnya digunakan, apakah GPU menganggur di antara permintaan karena ukuran batch yang rendah, apakah transfer data antara CPU dan GPU merupakan hambatan, apakah pelambatan termal menyebabkan lonjakan latensi, dan berapa banyak ruang kepala memori GPU yang tersisa untuk batch yang lebih besar.

Instal eksportir DCGM:

```
helm install dcgm-exporter gpu-helm-charts/dcgm-exporter \
  --namespace monitoring \
  -f /tmp/dcgm-exporter-values.yaml
```

`tolerations`Izinkan eksportir untuk berjalan pada GPU-tainted node yang Anda sediakan di Langkah 2. `serviceMonitor`Dengan `release: kube-prometheus-stack` label memastikan Prometheus menemukan dan menggoresnya secara otomatis.

Verifikasi eksportir DCGM: DaemonSet

```
kubectl get daemonset dcgm-exporter -n monitoring
```

Setelah node GPU berjalan, Anda akan melihat satu Pod siap. Untuk memvalidasi metrik DCGM, navigasikan ke **Drilldown > Metrics** di Grafana dan cari. `DCGM_`

 **Validasi metrik DCGM di Grafana** 

![Halaman Grafana Drilldown Metrics difilter oleh DCGM_ menampilkan metrik GPU termasuk DCGM_FI_DEV_ECC_SBE_VOL_TOTAL, DCGM_FI_DEV_ENC_UTIL, DCGM_FI_DEV_DEV_USED](http://docs.aws.amazon.com/id_id/eks/latest/userguide/images/ml-cluster-setup-cli-dcgm-metrics-validate.png)


Untuk melihat dasbor, navigasikan ke Dasbor> **Pemantauan GPU > Dasbor Eksportir NVIDIA DCGM**.

 **Dasbor Eksportir NVIDIA DCGM di Grafana** 

![Grafana NVIDIA DCGM Exporter Dashboard menampilkan Pemanfaatan GPU, Suhu Rata-rata GPU, GPU Framebuffer Mem Digunakan, dan panel Total Daya GPU](http://docs.aws.amazon.com/id_id/eks/latest/userguide/images/ml-cluster-setup-cli-dcgm-dashboard.png)


## Model bobot ember S3
<a name="cluster-setup-cli-model-bucket"></a>

Buat bucket Amazon S3 untuk menyimpan bobot model dan konfigurasikan Asosiasi Identitas Pod EKS sehingga pod beban kerja dapat membaca dan menulis padanya.

Jika Anda membuka terminal baru, atur nama cluster dan wilayah:

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

### Buat ember S3
<a name="_create_the_s3_bucket"></a>

Buat bucket dengan akhiran acak untuk menghindari tabrakan nama:

```
BUCKET_SUFFIX=$(head -c 4 /dev/urandom | od -An -tx1 | tr -d ' \n')
MODEL_BUCKET="${CLUSTER_NAME}-models-${BUCKET_SUFFIX}"

aws s3 mb s3://${MODEL_BUCKET} --region ${AWS_REGION}
```

Bucket S3 yang dibuat setelah Januari 2023 memiliki enkripsi sisi server (AES256) dan pemblokiran akses publik diaktifkan secara default.

### Konfigurasikan EKS Pod Identity untuk akses S3
<a name="_configure_eks_pod_identity_for_s3_access"></a>

Buat `model-storage-sa` ServiceAccount di `default` namespace, kebijakan IAM yang dicakup ke bucket model, dan Asosiasi Identitas Pod EKS yang menautkannya. Pod beban kerja yang disetel `serviceAccountName: model-storage-sa` akan dapat membaca dan menulis ke bucket.

```
kubectl create serviceaccount model-storage-sa
```

Buat kebijakan IAM:

```
POLICY_ARN=$(aws iam create-policy \
  --policy-name "${CLUSTER_NAME}-model-storage-policy" \
  --policy-document "{\"Version\": \"2012-10-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": [\"s3:GetObject\", \"s3:PutObject\", \"s3:ListBucket\", \"s3:DeleteObject\"], \"Resource\": [\"arn:aws:s3:::${MODEL_BUCKET}\", \"arn:aws:s3:::${MODEL_BUCKET}/*\"]}]}" \
  --query 'Policy.Arn' \
  --output text)

echo "Policy ARN: ${POLICY_ARN}"
```

**catatan**  
Kebijakan ini memberikan `s3:DeleteObject` dan `s3:PutObject` untuk langkah validasi. Untuk pod inferensi produksi yang hanya membaca bobot model, hapus `s3:PutObject` dan ikuti `s3:DeleteObject` least-privilege.

Buat Asosiasi Identitas Pod EKS. `eksctl`membuat peran IAM dengan kebijakan kepercayaan yang benar dan menautkannya ke ServiceAccount:

```
eksctl create podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace default \
  --service-account-name model-storage-sa \
  --role-name "${CLUSTER_NAME}-model-storage-role" \
  --permission-policy-arns ${POLICY_ARN} \
  --region ${AWS_REGION}
```

Verifikasi asosiasi:

```
eksctl get podidentityassociation --cluster ${CLUSTER_NAME} --region ${AWS_REGION}
```

Output harus menyertakan `model-storage-sa` asosiasi di `default` namespace.

#### Validasi akses S3 dari Pod
<a name="cluster-setup-cli-s3-validate"></a>

Jalankan Pod satu kali dengan image AWS CLI, menggunakan `model-storage-sa` ServiceAccount, untuk mengonfirmasi EKS Pod Identity tersambung dan akses S3 berfungsi:

```
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: s3-test
  labels:
    guide: ai-eks-docs
spec:
  serviceAccountName: model-storage-sa
  containers:
    - name: aws-cli
      image: public.ecr.aws/aws-cli/aws-cli:2.27.0
      command:
        - sh
        - -c
        - |
          echo "=== Caller Identity ==="
          aws sts get-caller-identity
          echo ""
          echo "=== S3 Write Test ==="
          echo "pod identity works" | aws s3 cp - s3://${MODEL_BUCKET}/test.txt
          echo ""
          echo "=== S3 List Test ==="
          aws s3 ls s3://${MODEL_BUCKET}/
          echo ""
          echo "=== S3 Delete Test ==="
          aws s3 rm s3://${MODEL_BUCKET}/test.txt
  restartPolicy: Never
EOF
```

Tunggu sampai Pod selesai dan periksa log:

```
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/s3-test --timeout=300s
kubectl logs s3-test
```

Keluaran yang diharapkan

```
=== Caller Identity ===
{
    "UserId": "AROA...:eks-ai-eks-docs-model-s-...",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/ai-eks-docs-model-storage-role/eks-ai-eks-docs-model-s-..."
}

=== S3 Write Test ===
upload: - to s3://ai-eks-docs-models-01234567/test.txt

=== S3 List Test ===
2026-05-04 12:00:00         19 test.txt

=== S3 Delete Test ===
delete: s3://ai-eks-docs-models-01234567/test.txt
```

Identitas penelepon mengonfirmasi bahwa Pod mengambil `${CLUSTER_NAME}-model-storage-role` peran melalui EKS Pod Identity. Perintah S3 mengkonfirmasi akses baca dan tulis.

Bersihkan Pod uji:

```
kubectl delete pod s3-test
```

## Langkah selanjutnya
<a name="cluster-setup-cli-next-steps"></a>

Dengan klaster Anda siap, Anda dapat melanjutkan ke [Load & Serve Model](ml-inference-load-serve-model.md) untuk menerapkan model bahasa besar dan berinteraksi dengan titik akhir inferensi.

## Pembersihan
<a name="cluster-setup-cli-cleanup"></a>

**Tip**  
Jika Anda berencana untuk melanjutkan dengan bagian selanjutnya dari panduan ini, lewati pembersihan penuh. Jalankan hanya ketika Anda selesai.

```
export CLUSTER_NAME=ai-eks-docs
export AWS_REGION=us-east-2
```

```
kubectl delete pod nvidia-smi --ignore-not-found
kubectl delete deployment gpu-overflow-test --ignore-not-found
```

### Batalkan Reservasi Kapasitas
<a name="cluster-setup-cli-cleanup-cancel-reservation"></a>

Jika Anda membuat ODCR, batalkan terlebih dahulu:

```
INSTANCE_TYPE="g6e.4xlarge"
CAPACITY_RESERVATION_ID=$(aws ec2 describe-capacity-reservations \
  --filters "Name=state,Values=active" "Name=instance-type,Values=${INSTANCE_TYPE}" \
  --query 'CapacityReservations[0].CapacityReservationId' \
  --output text \
  --region ${AWS_REGION})
aws ec2 cancel-capacity-reservation --capacity-reservation-id ${CAPACITY_RESERVATION_ID}
```

**penting**  
Membatalkan reservasi tidak menghentikan instans yang sedang berjalan. Mereka melanjutkan dengan On-Demand tarif standar sampai dihentikan. Hapus penerapan terlebih dahulu untuk menguras node yang dicadangkan sebelum membatalkan.

### Bersihkan pemantauan
<a name="cluster-setup-cli-cleanup-monitoring"></a>

Cari kebijakan IAM ARN:

```
AMP_POLICY_ARN=$(aws iam list-policies \
  --scope Local \
  --query "Policies[?PolicyName=='${CLUSTER_NAME}-amp-grafana-policy'].Arn" \
  --output text)
echo "AMP Policy ARN: ${AMP_POLICY_ARN}"
```

Cari ID ruang kerja AMP:

```
AMP_WORKSPACE_ID=$(aws amp list-workspaces \
  --alias "amp-ws-${CLUSTER_NAME}" \
  --query 'workspaces[0].workspaceId' \
  --output text \
  --region ${AWS_REGION})
echo "AMP Workspace ID: ${AMP_WORKSPACE_ID}"
```

Copot pemasangan rilis Helm eksportir DCGM:

```
helm uninstall dcgm-exporter -n monitoring
```

Copot pemasangan rilis Helm kube-prometheus-stack:

```
helm uninstall kube-prometheus-stack -n monitoring
```

Hapus asosiasi Identitas Pod EKS untuk akun layanan konsumsi Prometheus:

```
eksctl delete podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name amp-iamproxy-ingest-service-account \
  --region ${AWS_REGION}
```

Hapus asosiasi Identitas Pod EKS untuk akun layanan Grafana:

```
eksctl delete podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace monitoring \
  --service-account-name grafana-sa \
  --region ${AWS_REGION}
```

Hapus kebijakan IAM yang digunakan oleh Prometheus dan Grafana:

```
aws iam delete-policy --policy-arn ${AMP_POLICY_ARN}
```

Menghapus ruang kerja AMP:

```
aws amp delete-workspace --workspace-id ${AMP_WORKSPACE_ID} --region ${AWS_REGION}
```

Hapus namespace pemantauan:

```
kubectl delete namespace monitoring
```

### Bersihkan model bobot S3 bucket
<a name="cluster-setup-cli-cleanup-model-bucket"></a>

Cari nama bucket model:

```
MODEL_BUCKET=$(aws s3api list-buckets \
  --query "Buckets[?starts_with(Name, '${CLUSTER_NAME}-models-')].Name | [0]" \
  --output text)
echo "Model bucket: ${MODEL_BUCKET}"
```

Cari kebijakan IAM ARN:

```
POLICY_ARN=$(aws iam list-policies \
  --scope Local \
  --query "Policies[?PolicyName=='${CLUSTER_NAME}-model-storage-policy'].Arn" \
  --output text)
echo "Policy ARN: ${POLICY_ARN}"
```

Hapus bucket model S3 dan semua objeknya:

```
aws s3 rb s3://${MODEL_BUCKET} --force
```

Hapus asosiasi Identitas Pod EKS:

```
eksctl delete podidentityassociation \
  --cluster ${CLUSTER_NAME} \
  --namespace default \
  --service-account-name model-storage-sa \
  --region ${AWS_REGION}
```

Hapus kebijakan IAM:

```
aws iam delete-policy --policy-arn ${POLICY_ARN}
```

Hapus Kubernetes ServiceAccount:

```
kubectl delete serviceaccount model-storage-sa
```

### Hapus Sumber Daya yang Tersisa dan Cluster
<a name="cluster-setup-cli-cleanup-delete-resources"></a>

```
kubectl delete nodepool gpu-inf --ignore-not-found
kubectl delete nodeclass gpu-inf --ignore-not-found
kubectl delete ec2nodeclass gpu-inf --ignore-not-found
eksctl delete cluster --name=$CLUSTER_NAME --region=$AWS_REGION
```