This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| wiki:ai:nvidia_gpu_operator_installation_and_upgrade [2026/07/20 11:39] – ssuresh | wiki:ai:nvidia_gpu_operator_installation_and_upgrade [2026/07/20 16:53] (current) – ssuresh | ||
|---|---|---|---|
| Line 198: | Line 198: | ||
| - | === Phase 5 — CUDA VectorAdd GPU test === | + | ===== Phase 5 — CUDA VectorAdd GPU test ===== |
| <code -> | <code -> | ||
| Line 224: | Line 224: | ||
| {{: | {{: | ||
| - | ==== Phase 6 — Upgrade the Operator==== | + | ===== Phase 6 — Upgrade the Operator |
| **Concept: ** | **Concept: ** | ||
| Line 282: | Line 282: | ||
| {{: | {{: | ||
| - | PART II — PRODUCTION UPGRADE SIMULATION | + | ===== PART II — PRODUCTION UPGRADE SIMULATION |
| + | Pretend the single EC2 node is a production AI cluster, run a live GPU workload, and walk through what an upgrade does to it — safely, without needing a real driver change. | ||
| + | ====Setup — Simulate GPU Operator Upgrade with Active ML Workloads==== | ||
| + | |||
| + | <code -> | ||
| + | NODE=$(kubectl get nodes -o jsonpath=' | ||
| + | echo $NODE | ||
| + | </ | ||
| + | |||
| + | ==== A — Stand up a " | ||
| + | |||
| + | **A1. Deploy a real GPU workload (gpu-burn — genuine GPU load)** | ||
| + | |||
| + | This runs gpu_burn, which actually stresses the GPU (near 100% utilization) — a far more realistic " | ||
| + | |||
| + | |||
| + | <code -> | ||
| + | cat > gpu-burn.yaml <<' | ||
| + | apiVersion: v1 | ||
| + | kind: Pod | ||
| + | metadata: | ||
| + | name: gpu-burn | ||
| + | spec: | ||
| + | restartPolicy: | ||
| + | containers: | ||
| + | - name: burn | ||
| + | image: nvcr.io/ | ||
| + | command: | ||
| + | - /bin/bash | ||
| + | - -c | ||
| + | - | | ||
| + | apt-get update && \ | ||
| + | apt-get install -y git build-essential && \ | ||
| + | git clone https:// | ||
| + | cd gpu-burn && \ | ||
| + | make && \ | ||
| + | ./gpu_burn 3600 | ||
| + | resources: | ||
| + | limits: | ||
| + | nvidia.com/ | ||
| + | EOF | ||
| + | |||
| + | kubectl apply -f gpu-burn.yaml | ||
| + | kubectl get pod gpu-burn -o wide # wait for Running | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | **A2. Confirm the GPU is in use** | ||
| + | |||
| + | Watch the build + burn progress, then check real GPU load from the driver pod: | ||
| + | |||
| + | <code -> | ||
| + | kubectl logs gpu-burn -f # apt install → clone → make → then GPU burn output; Ctrl+C to stop following | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | {{: | ||
| + | |||
| + | <code -> | ||
| + | DRIVER=$(kubectl get pods -n gpu-operator -l app=nvidia-driver-daemonset -o jsonpath=' | ||
| + | kubectl exec -n gpu-operator $DRIVER -- nvidia-smi | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | Once burning, nvidia-smi shows GPU-Util climbing toward 100%, memory in use, and gpu_burn listed in the Processes section — genuine GPU activity, i.e. a real ML workload stand-in. | ||
| + | |||
| + | ==== B — Understand what an upgrade will do (before touching anything) ==== | ||
| + | |||
| + | **B1. Pre-upgrade check: what's using the GPU?** | ||
| + | |||
| + | <code -> | ||
| + | kubectl get pods -A -o wide | grep -i gpu | ||
| + | kubectl get pods | ||
| + | </ | ||
| + | |||
| + | Always know what will be disrupted before upgrading. | ||
| + | |||
| + | **B2. Inspect the Operator' | ||
| + | |||
| + | <code -> | ||
| + | kubectl get clusterpolicies -o yaml | grep -A 25 " | ||
| + | kubectl get node $NODE -o jsonpath=' | ||
| + | </ | ||
| + | |||
| + | **Pause / resume automatic driver upgrades cluster-wide: | ||
| + | |||
| + | <code -> | ||
| + | # Pause | ||
| + | kubectl patch clusterpolicies/ | ||
| + | -p ' | ||
| + | # Resume | ||
| + | kubectl patch clusterpolicies/ | ||
| + | -p ' | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | ==== C — Simulate the disruptive part of a driver upgrade ==== | ||
| + | |||
| + | **C1. Cordon the node (maintenance mode)** | ||
| + | |||
| + | <code -> | ||
| + | kubectl cordon $NODE | ||
| + | kubectl get node $NODE # STATUS: Ready, | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | {{: | ||
| + | |||
| + | **C2. Drain the node → watch the workload get evicted** | ||
| + | |||
| + | <code -> | ||
| + | kubectl drain $NODE --ignore-daemonsets --delete-emptydir-data --force | ||
| + | kubectl get pods # gpu-burn is gone (evicted) | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | ==== D — Do the actual upgrade & validate ==== | ||
| + | |||
| + | **D1. Uncordon first so the upgrade schedules cleanly** | ||
| + | |||
| + | <code -> | ||
| + | kubectl uncordon $NODE | ||
| + | kubectl get node $NODE # back to Ready | ||
| + | </ | ||
| + | |||
| + | **D2. Upgrade the GPU Operator** | ||
| + | |||
| + | <code -> | ||
| + | helm list -n gpu-operator | ||
| + | helm search repo nvidia/ | ||
| + | </ | ||
| + | |||
| + | If a newer version exists, run the corrected upgrade (Part I, Phase 6.3). If already newest, you performed a real upgrade earlier in the story — the observation below is the point. Watch which pods restart: | ||
| + | |||
| + | <code -> | ||
| + | kubectl get pods -n gpu-operator -w # Ctrl+C when settled | ||
| + | </ | ||
| + | |||
| + | **D3. Validate after upgrade** | ||
| + | |||
| + | <code -> | ||
| + | kubectl get pods -n gpu-operator | ||
| + | kubectl get nodes -o=jsonpath=' | ||
| + | kubectl apply -f cuda-vectoradd.yaml | ||
| + | sleep 25 | ||
| + | kubectl logs cuda-vectoradd | ||
| + | kubectl delete -f cuda-vectoradd.yaml | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | ==== E — Restore & learn the production lesson ==== | ||
| + | |||
| + | **E1. Restore the workload** | ||
| + | |||
| + | <code -> | ||
| + | kubectl apply -f gpu-burn.yaml | ||
| + | kubectl get pods | ||
| + | </ | ||
| + | |||
| + | **E2. Inference with replicas + PodDisruptionBudget (why production has many nodes)** | ||
| + | |||
| + | Free the GPU first so the inference pod can schedule: | ||
| + | |||
| + | <code -> | ||
| + | kubectl delete -f gpu-burn.yaml --ignore-not-found | ||
| + | </ | ||
| + | |||
| + | Deploy an " | ||
| + | |||
| + | <code -> | ||
| + | cat > inference.yaml <<' | ||
| + | apiVersion: apps/v1 | ||
| + | kind: Deployment | ||
| + | metadata: | ||
| + | name: inference | ||
| + | spec: | ||
| + | replicas: 2 | ||
| + | selector: | ||
| + | matchLabels: | ||
| + | template: | ||
| + | metadata: | ||
| + | labels: { app: inference } | ||
| + | spec: | ||
| + | containers: | ||
| + | - name: inference | ||
| + | image: nvcr.io/ | ||
| + | command: [" | ||
| + | resources: | ||
| + | limits: | ||
| + | nvidia.com/ | ||
| + | --- | ||
| + | apiVersion: policy/v1 | ||
| + | kind: PodDisruptionBudget | ||
| + | metadata: | ||
| + | name: inference-pdb | ||
| + | spec: | ||
| + | minAvailable: | ||
| + | selector: | ||
| + | matchLabels: | ||
| + | EOF | ||
| + | |||
| + | kubectl apply -f inference.yaml | ||
| + | kubectl get pods -l app=inference | ||
| + | </ | ||
| + | |||
| + | See the PDB protect the service — try to drain and watch it get blocked: | ||
| + | |||
| + | <code -> | ||
| + | kubectl drain $NODE --ignore-daemonsets --delete-emptydir-data | ||
| + | # Blocked: " | ||
| + | # Press Ctrl+C to stop the attempt | ||
| + | kubectl uncordon $NODE | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | |||
| + | ===== PART III — ROLLBACK PLAN ===== | ||
| + | |||
| + | **Before any upgrade — capture your safety net** | ||
| + | |||
| + | <code -> | ||
| + | helm list -n gpu-operator | ||
| + | helm get values < | ||
| + | helm history < | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | |||
| + | **Roll back the Operator release** | ||
| + | |||
| + | <code -> | ||
| + | helm history < | ||
| + | helm rollback < | ||
| + | # or a specific revision: | ||
| + | helm rollback < | ||
| + | helm rollback < | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | **Simulation cleanup** | ||
| + | |||
| + | <code -> | ||
| + | kubectl delete -f gpu-burn.yaml --ignore-not-found | ||
| + | kubectl delete -f inference.yaml --ignore-not-found | ||
| + | kubectl delete pdb inference-pdb --ignore-not-found | ||
| + | kubectl uncordon $NODE 2>/ | ||
| + | kubectl get pods | ||
| + | </ | ||
| + | |||
| + | {{: | ||
| + | |||
| + | **Cleanup (avoid a surprise bill!)** | ||
| + | |||
| + | * Pause between sessions: EC2 → Stop (compute stops billing; small EBS cost remains; public IP changes on restart unless you use an Elastic IP). | ||
| + | * Done for good: EC2 → Terminate (deletes instance + disk). | ||
| + | * Release any Elastic IP if you allocated one (billed even while unused). | ||