Skip to content

Commit 6c5b587

Browse files
committed
deploy: use NVIDIA GPU Operator instead of manual containerd config
The manual containerd template approach is version-sensitive on K3s 1.35 (auto-detection failed, and a hand-written config-v3 template broke startup). Switch to the NVIDIA GPU Operator via Helm, which configures K3s's containerd at its non-standard paths (CONTAINERD_CONFIG/SOCKET pointing at /var/lib/ rancher/k3s and /run/k3s), registers the nvidia RuntimeClass, and deploys the device plugin. driver.enabled=false keeps Lambda Stack's preinstalled driver. This is the NVIDIA-documented path for K3s and avoids hand-editing containerd.
1 parent b70edbf commit 6c5b587

1 file changed

Lines changed: 47 additions & 38 deletions

File tree

deploy/lambda/setup-k3s-gpu.sh

Lines changed: 47 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,65 @@
11
#!/usr/bin/env bash
22
# Set up single-node K3s with NVIDIA GPU scheduling on a Lambda Cloud instance.
3-
# Lambda Stack preinstalls the NVIDIA driver and Container Toolkit, so this
4-
# script only installs K3s, points containerd at the NVIDIA runtime, registers
5-
# the RuntimeClass, and deploys the device plugin. Run once on a fresh instance.
3+
# Lambda Stack preinstalls the NVIDIA driver, so we keep it (driver.enabled=false)
4+
# and let the NVIDIA GPU Operator manage the container toolkit and configure
5+
# K3s's containerd at its non-standard paths. This is more robust than hand-
6+
# editing the containerd template, which is version-sensitive on K3s. Run once.
67
set -euo pipefail
78

9+
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
10+
811
echo "==> [1/4] Installing K3s (single node)"
912
curl -sfL https://get.k3s.io | sh -
10-
# Make kubectl usable without sudo for the rest of the script.
11-
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
1213
sudo chmod 644 /etc/rancher/k3s/k3s.yaml
13-
kubectl wait --for=condition=Ready node --all --timeout=120s
14-
echo " K3s ready."
14+
# Wait for the node to register AND become Ready (the API may not be up the
15+
# instant the installer returns, so retry instead of failing fast).
16+
for i in $(seq 1 30); do
17+
if kubectl get nodes 2>/dev/null | grep -q ' Ready '; then
18+
echo " K3s node Ready."
19+
break
20+
fi
21+
echo " [$i] waiting for K3s node..."
22+
sleep 4
23+
done
1524

16-
echo "==> [2/4] Configuring K3s containerd for the NVIDIA runtime"
17-
# K3s ships its own containerd. Recent K3s autodetects the NVIDIA runtime when
18-
# the Container Toolkit is present, generating an "nvidia" runtime in its
19-
# containerd config. Restart K3s so detection runs now that the toolkit is here.
20-
sudo systemctl restart k3s
21-
sleep 10
22-
kubectl wait --for=condition=Ready node --all --timeout=120s
23-
# Verify the nvidia runtime was registered in K3s containerd config.
24-
if sudo grep -q 'nvidia' /var/lib/rancher/k3s/agent/etc/containerd/config.toml*; then
25-
echo " NVIDIA runtime detected in K3s containerd config."
26-
else
27-
echo " WARNING: nvidia runtime not found in containerd config; GPU pods may fail."
25+
echo "==> [2/4] Installing Helm"
26+
if ! command -v helm >/dev/null 2>&1; then
27+
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
2828
fi
29+
helm version
2930

30-
echo "==> [3/4] Registering the nvidia RuntimeClass"
31-
kubectl apply -f - <<'RTC'
32-
apiVersion: node.k8s.io/v1
33-
kind: RuntimeClass
34-
metadata:
35-
name: nvidia
36-
handler: nvidia
37-
RTC
38-
echo " RuntimeClass 'nvidia' applied."
39-
40-
echo "==> [4/4] Deploying the NVIDIA device plugin"
41-
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.17.1/deployments/static/nvidia-device-plugin.yml
42-
kubectl -n kube-system rollout status daemonset/nvidia-device-plugin-daemonset --timeout=120s
31+
echo "==> [3/4] Installing the NVIDIA GPU Operator (driver from Lambda Stack)"
32+
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
33+
helm repo update
34+
# driver.enabled=false -> keep Lambda's preinstalled driver.
35+
# The toolkit envs point the operator at K3s's non-standard containerd paths;
36+
# without these the runtime is written to the wrong place and never registers.
37+
helm install --wait gpu-operator nvidia/gpu-operator \
38+
-n gpu-operator --create-namespace \
39+
--set driver.enabled=false \
40+
--set toolkit.env[0].name=CONTAINERD_CONFIG \
41+
--set toolkit.env[0].value=/var/lib/rancher/k3s/agent/etc/containerd/config.toml.tmpl \
42+
--set toolkit.env[1].name=CONTAINERD_SOCKET \
43+
--set toolkit.env[1].value=/run/k3s/containerd/containerd.sock \
44+
--set toolkit.env[2].name=CONTAINERD_RUNTIME_CLASS \
45+
--set toolkit.env[2].value=nvidia \
46+
--set toolkit.env[3].name=CONTAINERD_SET_AS_DEFAULT \
47+
--set-string toolkit.env[3].value=true
48+
echo " GPU Operator installed."
4349

44-
echo "==> Verifying GPU is advertised to the scheduler"
45-
for i in $(seq 1 12); do
50+
echo "==> [4/4] Verifying GPU is advertised to the scheduler"
51+
# The operator's toolkit pod reconfigures containerd and restarts it, so the
52+
# node may briefly go NotReady; allow generous time for nvidia.com/gpu to appear.
53+
for i in $(seq 1 36); do
4654
gpu=$(kubectl get nodes -o jsonpath='{.items[0].status.allocatable.nvidia\.com/gpu}' 2>/dev/null || true)
4755
if [ -n "${gpu:-}" ] && [ "$gpu" != "0" ]; then
4856
echo " Node advertises nvidia.com/gpu=${gpu}. Cluster is GPU-ready."
4957
exit 0
5058
fi
51-
echo " [$i] waiting for GPU to be advertised..."
52-
sleep 5
59+
echo " [$i] waiting for nvidia.com/gpu (operator configuring containerd)..."
60+
sleep 10
5361
done
54-
echo " ERROR: no GPU advertised after 60s. Check device plugin logs:"
55-
echo " kubectl -n kube-system logs daemonset/nvidia-device-plugin-daemonset"
62+
echo " ERROR: no GPU advertised after ~6min. Inspect the operator:"
63+
echo " kubectl -n gpu-operator get pods"
64+
echo " kubectl -n gpu-operator logs -l app=nvidia-container-toolkit-daemonset"
5665
exit 1

0 commit comments

Comments
 (0)