Ana SayfaBlogEvdeki NVIDIA GPU'yu Kubernetes'e Vermek: Proxmox LXC, k3s, GPU Operator ve Time-Slicing
Container & Orchestration

Evdeki NVIDIA GPU'yu Kubernetes'e Vermek: Proxmox LXC, k3s, GPU Operator ve Time-Slicing

Emre Ferit Aslantaş23 Ağustos 202622 dkMakale
proxmox lxc k3s nvidia gpu-operator homelab kubernetes cuda time-slicing

22 Ağustos 2026'da Proxmox EFA kutusunda kurulan lab'ın tek kayıt belgesi. Host driver (1 Ağustos'ta diriltildi, o gece doğrulandı) + ayrı privileged LXC + k3s + NVIDIA GPU Operator + cuda-vectoradd + time-slicing. Aşağıdaki komutlar o gece çalıştırılanlar; çıktılar ölçüldü.

İddia. Host'ta NVIDIA driver varken privileged LXC bind + k3s + Operator (driver.enabled=false) ile nvidia.com/gpu schedule edilir. Time-slicing MIG/vGPU olmadan çalışır.

Değil. NVIDIA'nın desteklediği üretim topolojisi (VFIO VM / bare metal) değil. vGPU değil. MIG değil. LLM serving değil. MX130 kapasite kanıtı değil.

İki yol aynı anda olmaz: host driver + LXC bind veya VFIO ile kartı tek VM'e vermek.

Proxmox host  192.168.1.106
  NVIDIA driver 550.163.01  →  /dev/nvidia0   (kart host'ta kalır)
       │
       ├─ CT100 casaos  10.10.10.100  DNS/monitoring  ← k3s YOK
       ├─ CT102 mcp-hub 10.10.10.102  (RAM 512 MB'ye indirildi)
       └─ CT110 gpu-k3s 10.10.10.110  privileged, nesting=1, onboot=0
              bind /dev/nvidia* + host lib
              k3s v1.36.3+k3s1
              GPU Operator v26.7.0  (driver:false, toolkit:true)
              pod nvidia.com/gpu

SSH (Mac Mini'den; default identity yetmezse):

ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes root@192.168.1.106

Bundan sonra komutlar Proxmox host'ta veya pct exec 110 içinde. Guest için:

pct exec 110 -- bash -lc 'export PATH=/usr/local/bin:$PATH; export KUBECONFIG=/etc/rancher/k3s/k3s.yaml; …'

pct exec non-interactive PATH'te /usr/local/bin yok.


0. Host — GPU driver (1 Ağustos 2026, o gece hazırdı)

O gece driver kurulmadı; 1 Ağustos bakımında diriltilmişti. Lab'ın önkoşulu bu. nvidia-smi host'ta yoksa LXC'ye geçme.

Kök sebep (1 Ağu): DKMS 6.8.4-3-pve için derliydi, çalışan kernel 6.14.11-9-pve. Header yoktu, modül yeni kernele hiç build edilmemişti. nvidia-smi "couldn't communicate with the NVIDIA driver".

uname -r
# 6.14.11-9-pve

apt-get install -y proxmox-headers-$(uname -r) nvidia-driver nvidia-kernel-dkms nvidia-smi
dkms autoinstall -k $(uname -r)
modprobe nvidia
modprobe nvidia_modeset
modprobe nvidia_uvm
nvidia-smi

Kalıcılık /etc/modules-load.d/nvidia.conf:

# NVIDIA modulleri boot ta yuklensin (CT100 passthrough device node lari icin sart)
nvidia
nvidia_modeset
nvidia_uvm

Kernel pin — sistemde 6.17 ve 7.0 da yüklü. Pin kalkarsa 7.0 boot eder, 550 DKMS o kernele build olmaz, GPU yine ölür:

# /etc/default/grub
GRUB_DEFAULT="gnulinux-advanced-…>gnulinux-6.14.11-9-pve-advanced-…"
GRUB_CMDLINE_LINUX_DEFAULT="quiet consoleblank=60"

intel_iommu=on GRUB'da yazılı değil; kernel 6.14 DMAR görünce IOMMU'yu yine açmış. iommu=pt yok.

Nouveau blacklist zaten var (blacklist-nouveau.conf, nvidia-blacklists-nouveau.conf). nvidia-persistenced masked. pve-nvidia-vgpu-helper kurulu — MX130 vGPU yapamaz, paket oksuz.

22 Ağu host doğrulama:

pveversion
# pve-manager/9.2.6/7f8d010005bd72cb (running kernel: 6.14.11-9-pve)

lspci -nnk | grep -A3 -i nvidia
# 01:00.0 3D controller [0302]: NVIDIA Corporation GM108M [GeForce MX130] [10de:174d]
# Kernel driver in use: nvidia

lspci -nnk | grep -A3 "UHD Graphics"
# 00:02.0 VGA [8086:5917] Intel UHD Graphics 620  Kernel driver in use: i915

nvidia-smi --query-gpu=name,compute_cap,memory.total,driver_version --format=csv
# NVIDIA GeForce MX130, 5.0, 2048 MiB, 550.163.01

ls -l /dev/nvidia0 /dev/nvidiactl /dev/nvidia-uvm /dev/nvidia-caps
# nvidia0/ctl  195
# nvidia-uvm   507
# nvidia-caps  510
# /dev/nvidia-modeset YOK

dkms status
# nvidia-current/550.163.01, 6.14.11-9-pve, x86_64: installed

find /sys/kernel/iommu_groups/ -type l | sort
# group 0:  00:02.0  iGPU
# group 10: 01:00.0  NVIDIA  (yalnız — VFIO mümkün)

dmesg | grep IOMMUDMAR: Intel(R) Virtualization Technology for Directed I/O. VFIO modülü yüklü değil. Kart nvidia'da. VFIO bu kutuda açılmadı (7.5 GB RAM, CT100 DNS, kernel pin).

Kutu:

| | 22 Ağu | |---|---| | CPU | i5-8250U 4c/8t, VT-x | | RAM | 7.5 GB, available ~4.6 GB | | Disk | local-lvm %72.4, thin ~43 GB boş, VG 1 GB | | Şablon | ubuntu-24.04-standard_24.04-2_amd64.tar.zst yerelde | | QEMU | 0 |

RAM için idle CT102 (66 MB kullanıyordu):

pct set 102 --memory 512

Ekip kuralı: DNS / monitoring / GPU lab aynı LXC'de olmaz. CT100'e k3s konmadı (2 GB, 680 MB available, swap, AdGuard).


1. CT110 oluştur + GPU bind

pct create 110 local:vztmpl/ubuntu-24.04-standard_24.04-2_amd64.tar.zst \
  --hostname gpu-k3s \
  --memory 3072 \
  --swap 2048 \
  --cores 4 \
  --rootfs local-lvm:16 \
  --net0 name=eth0,bridge=vmbr0,ip=10.10.10.110/24,gw=10.10.10.1,type=veth \
  --unprivileged 0 \
  --features nesting=1,keyctl=1,fuse=1 \
  --ostype ubuntu \
  --onboot 0 \
  --nameserver 10.10.10.100 \
  --searchdomain local \
  --ssh-public-keys /etc/pve/priv/authorized_keys \
  --description "GPU k3s lab - NVIDIA MX130 LXC bind, onboot=0"

Start etmeden /etc/pve/lxc/110.conf sonuna ekle. Major'lar host ls -l /dev/nvidia*'dan (bu kutu 195 / 507 / 510):

# NVIDIA device bind (host driver, shared with CT100)
lxc.cgroup2.devices.allow: c 195:* rwm
lxc.cgroup2.devices.allow: c 507:* rwm
lxc.cgroup2.devices.allow: c 510:* rwm
lxc.cgroup2.devices.allow: c 1:11 rwm
lxc.mount.entry: /dev/nvidia0 dev/nvidia0 none bind,optional,create=file
lxc.mount.entry: /dev/nvidiactl dev/nvidiactl none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm dev/nvidia-uvm none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-uvm-tools dev/nvidia-uvm-tools none bind,optional,create=file
lxc.mount.entry: /dev/nvidia-caps dev/nvidia-caps none bind,optional,create=dir
lxc.mount.entry: /usr/lib/x86_64-linux-gnu/nvidia/current usr/lib/x86_64-linux-gnu/nvidia/current none bind,ro,optional,create=dir
lxc.mount.entry: /usr/lib/nvidia/current usr/lib/nvidia/current none bind,ro,optional,create=dir
lxc.mount.entry: /dev/kmsg dev/kmsg none bind,optional,create=file
# k3s in LXC
lxc.apparmor.profile: unconfined
lxc.cap.drop:
lxc.mount.auto: proc:rw sys:rw

O gece oluşan tam conf:

#GPU k3s lab - NVIDIA MX130 LXC bind, onboot=0
arch: amd64
cores: 4
features: nesting=1,keyctl=1,fuse=1
hostname: gpu-k3s
memory: 3072
nameserver: 10.10.10.100
net0: name=eth0,bridge=vmbr0,gw=10.10.10.1,hwaddr=BC:24:11:66:C4:7B,ip=10.10.10.110/24,type=veth
onboot: 0
ostype: ubuntu
rootfs: local-lvm:vm-110-disk-0,size=16G
searchdomain: local
swap: 2048
# NVIDIA … (yukarıdaki lxc.* satırları)
pct start 110
# uyarı: explicitly configured lxc.apparmor.profile overrides features:fuse, features:nesting
# unconfined daha geniş; k3s kalktı

pct status 110
pct exec 110 -- hostname          # gpu-k3s
pct exec 110 -- ip -4 addr show eth0
# inet 10.10.10.110/24

Cihazlar geldi. İlk nvidia-smi düştü: couldn't find libnvidia-ml.so. Bind'de libnvidia-ml.so.550.163.01 var; guest ldconfig path'i bilmiyor.

Symlink yetmez. Toolkit /usr/bin/nvidia-smi → …/current/nvidia-smi symlink'ini atladı. Baştan kopya:

pct exec 110 -- bash -lc '
echo /usr/lib/x86_64-linux-gnu/nvidia/current > /etc/ld.so.conf.d/nvidia-current.conf
rm -f /usr/bin/nvidia-smi
cp -a /usr/lib/nvidia/current/nvidia-smi /usr/bin/nvidia-smi
ldconfig
ldconfig -p | grep -E "nvidia-ml|libcuda"
nvidia-smi
'

Kapı 1: guest nvidia-smi tablo — Driver 550.163.01, CUDA 12.4, MX130, 0/2048 MiB. Host'ta toolkit kurma; Operator k3s containerd'sine yazar.

IPv4 tercih (AdGuard google.com yalnız AAAA döndü) + paketler:

pct exec 110 -- bash -lc '
grep -q "precedence :ffff:0:0/96  100" /etc/gai.conf \
  || echo "precedence :ffff:0:0/96  100" >> /etc/gai.conf
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y curl ca-certificates jq
'

2. k3s + Helm

pct exec 110 -- bash -lc '
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--write-kubeconfig-mode 644 --disable traefik" sh -
curl -fsSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
grep -q KUBECONFIG /root/.bashrc || cat >> /root/.bashrc << "E2"
export PATH=/usr/local/bin:$PATH
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
E2
'

Ölçülen: k3s v1.36.3+k3s1, go 1.26.5, containerd 2.3.2-k3s2, Helm v3.21.4.

pct exec 110 -- bash -lc '
export PATH=/usr/local/bin:$PATH
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
systemctl is-active k3s
k3s --version
kubectl get nodes -o wide
kubectl get pods -A
'
NAME      STATUS   ROLES           VERSION        INTERNAL-IP    CONTAINER-RUNTIME
gpu-k3s   Ready    control-plane   v1.36.3+k3s1   10.10.10.110   containerd://2.3.2-k3s2

CoreDNS, local-path, metrics-server ~65 s'de Running.

kubectl create ns gpu-operator
kubectl label --overwrite ns gpu-operator pod-security.kubernetes.io/enforce=privileged

Kapı 2: node Ready, sistem pod'ları Running, ns privileged.

containerd path (Operator'a bunlar):

/var/lib/rancher/k3s/agent/etc/containerd/config.toml
/run/k3s/containerd/containerd.sock

3. GPU Operator v26.7.0

Driver host'ta → Operator kurmasın. Toolkit k3s soketine yazsın. MIG/DCGM kapalı.

pct exec 110 -- bash -lc '
export PATH=/usr/local/bin:$PATH
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
helm install gpu-operator nvidia/gpu-operator \
  -n gpu-operator \
  --version=v26.7.0 \
  --set driver.enabled=false \
  --set toolkit.enabled=true \
  --set migManager.enabled=false \
  --set dcgmExporter.enabled=false \
  --set toolkit.env[0].name=CONTAINERD_CONFIG \
  --set toolkit.env[0].value=/var/lib/rancher/k3s/agent/etc/containerd/config.toml \
  --set toolkit.env[1].name=CONTAINERD_SOCKET \
  --set toolkit.env[1].value=/run/k3s/containerd/containerd.sock
'

Yanlış path = host /etc/containerd = GPU runtime yok.

Toolkit 99-nvidia.toml yazıp containerd'ye SIGHUP attı. k3s embedded containerd → API bir kez düştü (127.0.0.1:6443 connection refused). systemd geri kaldırdı. Peak bellek 2.5 GB / 3 GB.

k3s config.toml DO NOT EDIT, import config-v3.toml.d/*.toml. Toolkit ayrıca /etc/containerd/conf.d/ yazar. Persist:

mkdir -p /var/lib/rancher/k3s/agent/etc/containerd/config-v3.toml.d
cp /etc/containerd/conf.d/99-nvidia.toml \
  /var/lib/rancher/k3s/agent/etc/containerd/config-v3.toml.d/99-nvidia.toml

Toolkit nvidia runtime (BinaryName /usr/local/nvidia/toolkit/nvidia-container-runtime) + nvidia-cdi. RuntimeClass: nvidia, nvidia-cdi, nvidia-legacy.

Tuzak: toolkit nvidia-smi bulamıyor

error validating toolkit installation: exec: "nvidia-smi": executable file not found in $PATH
cp -a /usr/lib/nvidia/current/nvidia-smi /usr/bin/nvidia-smi
cp -a /usr/lib/nvidia/current/nvidia-smi /usr/local/nvidia/toolkit/nvidia-smi
chmod 755 /usr/bin/nvidia-smi /usr/local/nvidia/toolkit/nvidia-smi
kubectl rollout restart -n gpu-operator ds/nvidia-container-toolkit-daemonset

Restart SIGHUP ile k3s'i yine düşürebilir; systemctl is-active k3s bekle. Sonra validator nvidia-smi tablosunu pod içinden bastı. driver-validation ve toolkit-validation Completed.

Device plugin:

Starting GRPC server for 'nvidia.com/gpu'
Registered device plugin for 'nvidia.com/gpu' with Kubelet
Capacity:      nvidia.com/gpu: 1
Allocatable:   nvidia.com/gpu: 1
nvidia.com/gpu.present=true
nvidia.com/gpu.family=maxwell
nvidia.com/gpu.compute.major=5
nvidia.com/gpu.compute.minor=0
nvidia.com/gpu.memory=2048

Kapı 3: plugin Running + nvidia.com/gpu: 1. ClusterPolicy ready bu lab'da şart değil.


4. cuda-vectoradd

Operator nvidia-cuda-validator (v26.7.0 imajı) düştü:

Failed to allocate device vector A
(error code CUDA driver version is insufficient for CUDA runtime version)

Scheduler resource yalan değil; validator userspace driver 550 / CUDA 12.4'ten yeni. sm_50 yeni sample hedefi değil. Dokümandaki vectoradd-cuda12.5.0-ubuntu22.04 bu kutuda yanlış test.

apiVersion: v1
kind: Pod
metadata:
  name: cuda-vectoradd
spec:
  restartPolicy: OnFailure
  runtimeClassName: nvidia
  containers:
  - name: cuda-vectoradd
    image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda11.7.1-ubuntu20.04
    resources:
      limits:
        nvidia.com/gpu: 1
kubectl apply -f cuda-vectoradd.yaml
kubectl get pod cuda-vectoradd -w
kubectl logs pod/cuda-vectoradd
kubectl delete pod cuda-vectoradd

Pull 85 MB, ~35 s:

[Vector addition of 50000 elements]
Copy input data from the host memory to the CUDA device
CUDA kernel launch with 196 blocks of 256 threads
Copy output data from the CUDA device to the host memory
Test PASSED
Done

Validator crashloop GPU yer. Kapat:

kubectl label node gpu-k3s nvidia.com/gpu.deploy.operator-validator=false --overwrite
cat > /tmp/val-patch.json << 'EOF'
{"spec":{"validator":{"plugin":{"env":[{"name":"WITH_WORKLOAD","value":"false"}]}}}}
EOF
kubectl patch clusterpolicies.nvidia.com/cluster-policy --type merge --patch-file /tmp/val-patch.json
kubectl delete pod -n gpu-operator -l app=nvidia-cuda-validator

İsteğe bağlı (validator init dosyası; plugin zaten kayıtlıysa):

printf "cuda-ready (driver 550 / sm_50; operator sample too new)\n" \
  > /run/nvidia/validations/cuda-ready

Kapı 4: log'da Test PASSED. Pending / Insufficient nvidia.com/gpu = Kapı 3 bitmemiş. driver version is insufficient = imaj CUDA'sı kartı aşmış.


5. Time-slicing

MIG yok. vGPU yok. Time-slicing = CUDA context interleave, VRAM izolasyonu yok, scheduler nvidia.com/gpu sayısını şişirir.

apiVersion: v1
kind: ConfigMap
metadata:
  name: time-slicing-config-all
  namespace: gpu-operator
data:
  any: |-
    version: v1
    flags:
      migStrategy: none
    sharing:
      timeSlicing:
        renameByDefault: false
        failRequestsGreaterThanOne: false
        resources:
        - name: nvidia.com/gpu
          replicas: 4
kubectl apply -f time-slicing-config-all.yaml
cat > /tmp/ts-patch.json << 'EOF'
{"spec":{"devicePlugin":{"config":{"name":"time-slicing-config-all","default":"any"}}}}
EOF
kubectl patch clusterpolicies.nvidia.com/cluster-policy --type merge --patch-file /tmp/ts-patch.json
kubectl rollout restart -n gpu-operator ds/nvidia-device-plugin-daemonset

Operator ConfigMap'i izlemez; plugin restart şart. ~15 s sonra:

nvidia.com/gpu.count=1
nvidia.com/gpu.replicas=4
nvidia.com/gpu.product=NVIDIA-GeForce-MX130-SHARED
nvidia.com/gpu.sharing-strategy=time-slicing
nvidia.com/gpu: 4
apiVersion: apps/v1
kind: Deployment
metadata:
  name: time-slicing-verification
spec:
  replicas: 5
  selector:
    matchLabels:
      app: tsv
  template:
    metadata:
      labels:
        app: tsv
    spec:
      runtimeClassName: nvidia
      tolerations:
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
      containers:
      - name: cuda-vectoradd
        image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda11.7.1-ubuntu20.04
        command: ["/bin/bash", "-c", "--"]
        args: ["while true; do /cuda-samples/vectorAdd; sleep 2; done"]
        resources:
          limits:
            nvidia.com/gpu: 1

Ölçülen: 4 Running + 1 Pending, deploy 4/5.

0/1 nodes are available: 1 Insufficient nvidia.com/gpu

Dört Running pod döngüde Test PASSED. replicas=4 kapasite çarpanı değil. nvidia.com/gpu: 2 2× compute vermez; failRequestsGreaterThanOne: true admission'da keser.

kubectl delete deploy time-slicing-verification

Kapı 5: -SHARED + replicas=4 + 5 replica'da tam 1 Pending. 5/5 Running = slicing yok veya ikinci GPU.


Bitti listesi

  1. Host: nvidia-smi tablo, Kernel driver in use: nvidia
  2. CT110: nvidia-smi tablo (kopya binary)
  3. kubectl get nodes Ready
  4. nvidia.com/gpu allocatable (önce 1, slicing sonrası 4)
  5. cuda-vectoradd log: Test PASSED
  6. Slicing sonrası 5 replica → 4 Running, 1 Pending
  7. kubectl delete deploy sonrası lab boş
  8. Host nvidia-smi hâlâ host'ta (kart kopmadı)

Durdur / sil

onboot: 0 — host reboot = lab kapalı, DNS ayakta.

pct exec 110 -- bash -lc 'kubectl describe node gpu-k3s | grep nvidia.com/gpu'
pct stop 110
pct destroy 110

CT102 RAM'i 512'de bırakıldı (eski 1024). Geri: pct set 102 --memory 1024.

Host driver, DKMS pin, CT100 bind dokunulmadı.

Sürümler (22 Ağu 2026)

| Parça | Sürüm | |---|---| | PVE | 9.2.6 / kernel 6.14.11-9-pve | | GPU | MX130 sm_50 2048 MiB | | Driver | 550.163.01 / CUDA 12.4 | | LXC | Ubuntu 24.04, CT110, 3G RAM, 16G disk | | k3s | v1.36.3+k3s1 / containerd 2.3.2-k3s2 | | Helm | v3.21.4 | | GPU Operator | v26.7.0 | | Toolkit (Operator) | nvidia-container-toolkit 1.20.0 (operator artifacts) | | Sample | vectoradd-cuda11.7.1-ubuntu20.04 (85 MB) | | Time-slicing | replicas 4, product NVIDIA-GeForce-MX130-SHARED |

Üç cümle

  1. Beş adım LXC'de kapanır. Şart: host driver, privileged bind, driver.enabled=false, k3s containerd path, nvidia-smi gerçek dosya.
  2. Operator ayağa kalktı ≠ CUDA çalıştı. v26.7.0 validator 550/sm_50'de düştü; kapı log'daki Test PASSED.
  3. Time-slicing paylaşım, kapasite değil. 4 replica = 4 pod aynı 2 GB.

Masaüstü 8 GB+ VRAM / 16 GB+ RAM: aynı Helm, tercihen Ubuntu VM + VFIO. Bu kutuda IOMMU hazırdı, RAM değildi.

Haftalık DevOps Bülteni

Yeni tool incelemeleri, karşılaştırmalar ve DevOps trendleri haftada bir kutuna gelsin.