Ollama Kubernetes: Manifiestos y Despliegue Prod
Tabla de contenidos
Parte 3 de 4. Parte 1 | Parte 2 | Parte 3 | Parte 4
Paso 3: Desplegar Ollama con Manifiestos Listos para Producción
Este manifiesto agrupa Deployment, PVC y ConfigMap en un solo archivo que he usado en seis clusters de producción.
apiVersion: v1kind: PersistentVolumeClaimmetadata: name: ollama-models namespace: ollamaspec: accessModes: - ReadWriteOnce resources: requests: storage: 100Gi storageClassName: fast-ssd # Reemplaza con tu StorageClass SSD---apiVersion: v1kind: ConfigMapmetadata: name: ollama-config namespace: ollamadata: OLLAMA_HOST: "0.0.0.0" OLLAMA_PORT: "11434" OLLAMA_NUM_PARALLEL: "4" OLLAMA_MAX_LOADED_MODELS: "2" OLLAMA_KEEP_ALIVE: "30m"---apiVersion: apps/v1kind: Deploymentmetadata: name: ollama namespace: ollama labels: app.kubernetes.io/name: ollama app.kubernetes.io/component: inference-serverspec: replicas: 1 strategy: type: Recreate # Requerido para PVCs RWO selector: matchLabels: app.kubernetes.io/name: ollama template: metadata: labels: app.kubernetes.io/name: ollama spec: nodeSelector: gpu-type: nvidia tolerations: - key: "nvidia.com/gpu" operator: "Equal" value: "true" effect: "NoSchedule" terminationGracePeriodSeconds: 60 containers: - name: ollama image: ollama/ollama:0.5.7 ports: - containerPort: 11434 name: http protocol: TCP envFrom: - configMapRef: name: ollama-config resources: requests: cpu: "4" memory: "16Gi" nvidia.com/gpu: "1" limits: cpu: "8" memory: "64Gi" # 32Gi para modelos 7B-13B, 64Gi para 70B nvidia.com/gpu: "1" volumeMounts: - name: models mountPath: /root/.ollama lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 15"] livenessProbe: httpGet: path: /api/tags port: 11434 initialDelaySeconds: 60 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: /api/tags port: 11434 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false runAsNonRoot: false capabilities: drop: - ALL volumes: - name: models persistentVolumeClaim: claimName: ollama-modelsDecisiones clave validadas en producción:
strategy: Recreate: El PVCReadWriteOnceno puede montarse en dos pods simultáneamente.- Límites de recursos:
64Gisoporta modelos 70B con cuantización.32Gipara modelos 7B-13B. OLLAMA_NUM_PARALLEL: "4": Agrupa solicitudes concurrentes. Incrementa solo si sobra VRAM.lifecycle.preStop+terminationGracePeriodSeconds: 60: Da 15 segundos a inferencias en vuelo antes de SIGKILL.OLLAMA_KEEP_ALIVE: "30m": Mantiene modelos en VRAM 30 minutos tras la última solicitud, reduciendo latencia de arranque en frío.
Aplica el manifiesto:
kubectl apply -f 02-ollama-deployment.yamlEspera a que el pod esté Running:
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=ollama -n ollama --timeout=300sPaso 4: Exponer Ollama con Service e Ingress
Crea un Service ClusterIP para comunicación interna y un Ingress para acceso externo.
apiVersion: v1kind: Servicemetadata: name: ollama namespace: ollama labels: app.kubernetes.io/name: ollamaspec: type: ClusterIP selector: app.kubernetes.io/name: ollama ports: - port: 11434 targetPort: 11434 name: http protocol: TCP---apiVersion: networking.k8s.io/v1kind: Ingressmetadata: name: ollama namespace: ollama annotations: nginx.ingress.kubernetes.io/proxy-body-size: "512m" nginx.ingress.kubernetes.io/proxy-read-timeout: "300" nginx.ingress.kubernetes.io/proxy-send-timeout: "300"spec: ingressClassName: nginx rules: - host: ollama.<your-cluster-domain>.com http: paths: - path: / pathType: Prefix backend: service: name: ollama port: number: 11434Advertencia: Ollama no tiene autenticación integrada. Expón solo con proxy de auth (oauth2-proxy, Authelia) o VPN interna.
Tip:
proxy-body-size: "512m"es crítico si subes modelos personalizados vía API.
Aplica y verifica:
kubectl apply -f 03-service-ingress.yamlkubectl get ingress -n ollamaPaso 5: Verificación: Descargar Modelo y Ejecutar Inferencia
Con el pod ejecutándose, descarga un modelo y prueba la inferencia:
kubectl exec -it deployment/ollama -n ollama -- ollama pull llama3.2Salida esperada:
pulling manifestpulling dde5aa3fc5ff... 100% ▕████████████████▏ 2.0 GBverifying sha256 digestwriting manifestsuccessPrueba inferencia vía port-forward:
kubectl port-forward svc/ollama 11434:11434 -n ollamaEn otra terminal:
curl http://localhost:11434/api/generate -d '{ "model": "llama3.2", "prompt": "Why is Kubernetes the right platform for self-hosted AI?", "stream": false}'Si ves {"done":true,"response":"..."}, tu stack de inferencia local LLM está activo.
Verifica el endpoint compatible con OpenAI:
curl http://localhost:11434/v1/chat/completions -H "Content-Type: application/json" -d '{ "model": "llama3.2", "messages": [{"role": "user", "content": "Hello!"}]}'FAQ
¿Por qué usar strategy: Recreate en lugar de RollingUpdate?
Los PVCs ReadWriteOnce solo se montan en un pod a la vez. Un rolling update crearía un nuevo pod antes de terminar el anterior, y el nuevo fallaría al montar el PVC. Recreate termina el pod anterior primero, luego arranca el nuevo.
¿Qué verifican los liveness y readiness probes?
Ambos golpean /api/tags. Liveness (cada 30s tras 60s de retardo) reinicia el pod si Ollama deja de responder. Readiness (cada 10s tras 10s de retardo) saca el pod del Service hasta que Ollama esté listo. He ajustado estos retardos para considerar el tiempo de carga de modelos.
¿Cómo verifico que la aceleración GPU funciona?
Ejecuta kubectl exec -it deployment/ollama -n ollama -- nvidia-smi dentro del pod. Si ves procesos GPU con el PID de Ollama y la utilización sube a 90-100% durante inferencia, la GPU está activa.
¿Qué hace OLLAMA_KEEP_ALIVE: "30m"?
Mantiene el modelo cargado en VRAM 30 minutos tras la última solicitud. Sin esto, Ollama descarga el modelo inmediatamente después de cada inferencia, añadiendo 5-30 segundos de latencia de arranque en frío. Para chats, recomiendo 30m. Para batch, usa -1 (nunca descargar).
¿Puedo ejecutar múltiples modelos simultáneamente?
Sí, hasta OLLAMA_MAX_LOADED_MODELS: "2". Cada modelo consume VRAM. En un A100 de 80 GB puedes ejecutar dos modelos 7B simultáneamente. Para producción multi-modelo, recomiendo el patrón de un Deployment por modelo en la Parte 4.
Siguientes Pasos
Tu instancia de Ollama funciona en Kubernetes con GPU, almacenamiento persistente e ingress. En la Parte 4 cubro endurecimiento de producción: alternativas a HPA, NetworkPolicies, monitoreo, troubleshooting y cuándo NO usar Kubernetes.