From dbfd5f7c589450e5403071e6fc5dbd763442d5a2 Mon Sep 17 00:00:00 2001 From: chemavx Date: Thu, 23 Jul 2026 07:39:44 +0000 Subject: [PATCH] =?UTF-8?q?ollama:=20cerrar=20exposici=C3=B3n=20p=C3=BAbli?= =?UTF-8?q?ca=20y=20activar=20la=20iGPU=20v=C3=ADa=20device=20plugin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Ingress con forward-auth de Authentik (la API estaba abierta a internet) - generic-device-plugin entrega card0+renderD128 como squat.ai/gpu con el cgroup de dispositivos bien configurado — lo que el hostPath nunca dio - fuera los 3 hostPath de dispositivos (ya no hacen falta) - OLLAMA_NUM_CTX→OLLAMA_CONTEXT_LENGTH (la real); fuera OLLAMA_METRICS (no existe) Sonda temporal confirmó: con cgroup, Vulkan enumera la Radeon 780M (17 GiB). Co-Authored-By: Claude Opus 4.8 --- ollama/device-plugin.yaml | 71 +++++++++++++++++++++++++++++++++++++++ ollama/ollama.yaml | 59 +++++++++++++------------------- 2 files changed, 94 insertions(+), 36 deletions(-) create mode 100644 ollama/device-plugin.yaml diff --git a/ollama/device-plugin.yaml b/ollama/device-plugin.yaml new file mode 100644 index 0000000..ca19892 --- /dev/null +++ b/ollama/device-plugin.yaml @@ -0,0 +1,71 @@ +# generic-device-plugin (squat.ai) — da acceso REAL a la iGPU sin privileged. +# +# El porqué: montar /dev/dri por hostPath hace visible el dispositivo pero NO +# concede acceso en el cgroup de dispositivos (open() = EPERM aunque seas root). +# Un device plugin es el único camino sano: kubelet reserva el recurso +# (squat.ai/gpu), monta los nodos de dispositivo Y configura el cgroup. +# Diagnosticado el 2026-07-22; sonda privileged temporal confirmó que con +# acceso al cgroup, Vulkan enumera la Radeon 780M (17 GiB VRAM+GTT). +# +# El DaemonSet corre privileged, pero es un componente de infraestructura sin +# Service ni Ingress — no es comparable a exponer ollama privileged. +# Imagen fijada por digest (no hay tags de versión en este proyecto). +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: generic-device-plugin + namespace: ollama + labels: + app: generic-device-plugin +spec: + selector: + matchLabels: + app: generic-device-plugin + template: + metadata: + labels: + app: generic-device-plugin + spec: + # Solo en el nodo con la iGPU (la 780M está en chemavx-k8). + nodeSelector: + kubernetes.io/hostname: chemavx-k8 + priorityClassName: system-node-critical + tolerations: + - operator: Exists + containers: + - name: generic-device-plugin + image: ghcr.io/squat/generic-device-plugin@sha256:dc192e164c69b03f156765793a1be62ca437709ae477b27ca7d8f3dcf5021576 + args: + - --log-level=info + # Un único recurso "gpu" que entrega los dos nodos DRM juntos. + - --device + - | + name: gpu + groups: + - paths: + - path: /dev/dri/card0 + - path: /dev/dri/renderD128 + resources: + requests: + cpu: 10m + memory: 16Mi + limits: + cpu: 50m + memory: 32Mi + ports: + - containerPort: 8080 + name: http + securityContext: + privileged: true + volumeMounts: + - name: device-plugin + mountPath: /var/lib/kubelet/device-plugins + - name: dev + mountPath: /dev + volumes: + - name: device-plugin + hostPath: + path: /var/lib/kubelet/device-plugins + - name: dev + hostPath: + path: /dev diff --git a/ollama/ollama.yaml b/ollama/ollama.yaml index db2e5bc..4dea723 100644 --- a/ollama/ollama.yaml +++ b/ollama/ollama.yaml @@ -1,16 +1,15 @@ # Ollama en chemavx-k8, bajo ArgoCD (selfHeal). # -# 2026-07-22 — DERIVA CORREGIDA. Todo el paso de la iGPU (los 3 hostPath de -# /dev/dri, /dev/kfd y /sys/devices/virtual/kfd, sus montajes, los grupos -# suplementarios 44/109, el securityContext y las 4 variables AMD) estaba puesto -# A MANO en el objeto vivo y NO en este fichero. Sobrevivía sólo por el merge de -# tres vías: `kubectl diff` no lo borraba porque no figura en la -# last-applied-configuration, y ArgoCD lo daba por Synced. Cualquier -# reconstrucción desde git se lo habría llevado en silencio. Ahora está -# declarado: lo que se lee aquí es lo que hay. +# 2026-07-23 — iGPU POR FIN ACTIVA, vía device plugin (device-plugin.yaml). +# El hostPath de /dev/dri hacía visible el dispositivo pero el cgroup de +# dispositivos negaba open() (EPERM): la GPU nunca llegó a usarse. El recurso +# squat.ai/gpu entrega card0+renderD128 con el cgroup bien puesto, y el +# backend Vulkan (la imagen no trae ROCm) enumera la Radeon 780M. +# Ese mismo día se cerró la exposición pública: el Ingress lleva ahora el +# forward-auth de Authentik (mismo middleware que Grafana). # -# Y el motivo de que la GPU no se usara: la imagen no trae ROCm (ver el -# comentario del bloque env). Se activa el backend Vulkan, que sí viene dentro. +# 2026-07-22 — deriva corregida: todo el paso de la iGPU vivía puesto a mano +# en el objeto vivo (merge de tres vías) y no en git. Ahora git es la verdad. --- apiVersion: v1 kind: Namespace @@ -79,13 +78,13 @@ spec: env: - name: OLLAMA_MODELS value: /root/.ollama/models - # El default (131072) reventaba la iGPU con un KV cache enorme. - - name: OLLAMA_NUM_CTX + # Límite de contexto para que el KV cache no reviente la iGPU. + # OJO: la variable real es OLLAMA_CONTEXT_LENGTH; OLLAMA_NUM_CTX + # no existe para el servidor (estuvo meses sin aplicarse). + - name: OLLAMA_CONTEXT_LENGTH value: "8192" - name: OLLAMA_KEEP_ALIVE value: "-1" - - name: OLLAMA_METRICS - value: "1" # --- aceleración por la iGPU (Radeon 780M, Hawk Point) --- # AQUÍ NO VAN HSA_OVERRIDE_GFX_VERSION NI HIP_VISIBLE_DEVICES. # Son de ROCm, y esta imagen no trae ROCm (en /usr/lib/ollama sólo @@ -111,6 +110,9 @@ spec: cpu: "500m" limits: memory: 8Gi + # La iGPU, entregada por el generic-device-plugin + # (device-plugin.yaml): card0 + renderD128 con acceso de cgroup. + squat.ai/gpu: "1" securityContext: privileged: false allowPrivilegeEscalation: false @@ -119,14 +121,6 @@ spec: volumeMounts: - name: ollama-data mountPath: /root/.ollama - # Paso de la iGPU sin privileged: los dispositivos del kernel amdgpu. - - name: dev-dri - mountPath: /dev/dri - - name: dev-kfd - mountPath: /dev/kfd - - name: sys-kfd - mountPath: /sys/devices/virtual/kfd - readOnly: true livenessProbe: httpGet: path: /api/tags @@ -141,8 +135,8 @@ spec: initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 15 - # 44=video, 109=render en chemavx-k8. Sin estos grupos el proceso no - # puede abrir /dev/kfd ni renderD128 aunque estén montados. + # 44=video, 109=render en chemavx-k8: permisos de grupo sobre los nodos + # DRM (crw-rw---- root:render). El acceso de cgroup lo da el device plugin. securityContext: supplementalGroups: [44, 109] seccompProfile: @@ -151,18 +145,6 @@ spec: - name: ollama-data persistentVolumeClaim: claimName: ollama-models - - name: dev-dri - hostPath: - path: /dev/dri - type: Directory - - name: dev-kfd - hostPath: - path: /dev/kfd - type: CharDevice - - name: sys-kfd - hostPath: - path: /sys/devices/virtual/kfd - type: Directory --- apiVersion: v1 @@ -191,6 +173,11 @@ metadata: annotations: cert-manager.io/cluster-issuer: letsencrypt-prod traefik.ingress.kubernetes.io/router.entrypoints: websecure + # Cerrado 2026-07-23: la API estaba expuesta SIN autenticación (cualquiera + # podía usar el LLM o llenarte el disco con /api/pull). Mismo forward-auth + # que Grafana; los consumidores del cluster (researchowl, roswell, los + # vigilantes) van por el Service interno y no pasan por aquí. + traefik.ingress.kubernetes.io/router.middlewares: authentik-authentik-forward-auth@kubernetescrd spec: ingressClassName: traefik rules: