Infraestructura de servicio de modelos

Aprende a desplegar y configurar endpoints de modelos cuando tu entorno no dispone ya de una solución de servicio de modelos.

Antes de poder conectar IBM Bob a un modelo de lenguaje grande (LLM), debes tener acceso a un endpoint de modelo desplegado. Bob no aprovisiona, aloja ni gestiona la infraestructura de servicio de modelos. Si tu organización ya proporciona endpoints de modelos a través de OpenShift AI, servidores de inferencia basados en GPU, servicios de IA en cloud u otras plataformas de inferencia, ve directamente a Configurar el gateway de modelos.

Opciones de despliegue

Elige la opción que mejor se adapte a tu entorno y tus requisitos operativos.

OpciónCuándo usar
OpenShift AI (en clúster, OCI/ModelCar)Modelos air-gapped o autoalojados; RHOAI ya disponible en el clúster
Cloud públicaModelos frontier a través de AWS Bedrock, Azure OpenAI o Google Vertex AI
Infraestructura privadaModelo servido en servidores GPU separados o un clúster de inferencia dedicado

OpenShift AI (en clúster, OCI/ModelCar)

Red Hat OpenShift AI (RHOAI) es la plataforma recomendada para servir modelos en el clúster, incluyendo los despliegues air-gapped. El enfoque preferido para cargar los pesos del modelo es el patrón OCI/ModelCar: los archivos del modelo se incluyen en una imagen OCI bajo /models/ y se envían a un registro privado. Cuando se despliega el InferenceService, KServe inyecta un contenedor init modelcar-init que extrae la imagen y copia los pesos en un volumen compartido en /mnt/models/, desde donde los carga el runtime de servicio (por ejemplo, vLLM). La imagen del modelo se almacena en caché en el nodo tras la primera extracción; los reinicios posteriores en el mismo nodo omiten la descarga por completo.

Prerequisitos:

  • Operador de Red Hat OpenShift AI instalado en el clúster
  • KServe habilitado y configurado
  • Nodos worker con GPU con el operador GPU de NVIDIA (o equivalente) configurado
  • CLI oc autenticada en el clúster de destino con permisos para crear recursos en el namespace de destino
  • Un registro de contenedores privado accesible desde el clúster, con credenciales para enviar imágenes

Configurar Red Hat OpenShift AI

Configura los recursos DataScienceClusterInitialization y DataScienceCluster de la siguiente manera:

  • Deshabilita serviceMesh.
  • Habilita KServe estableciendo managementState: Managed.
  • Configura KServe para usar el modo RawDeployment.
  • Elimina todos los componentes de Red Hat OpenShift AI que no se usen.

Ejemplo de configuración de KServe:

kserve:
  defaultDeploymentMode: RawDeployment
  nim:
    managementState: Managed
  rawDeploymentServiceConfig: Headed
  serving:
    ingressGateway:
      certificate:
        type: OpenshiftDefaultIngress
    managementState: Removed
    name: knative-serving
  managementState: Managed

Habilitar el soporte de ModelCar

El soporte de ModelCar se controla mediante el ConfigMap inferenceservice-config en el namespace redhat-ods-applications. La clave storageInitializer debe contener "enableModelcar": true.

Verifica la configuración actual:

oc get configmap inferenceservice-config \
  -n redhat-ods-applications \
  -o jsonpath='{.data.storageInitializer}'

La salida debe contener:

{
  "enableModelcar": true,
  "cpuModelcar": "10m",
  "memoryModelcar": "15Mi"
}

Si enableModelcar falta o es false, actualiza el ConfigMap:

# Recupera el valor actual, fusiona el flag y aplica el parche
CURRENT=$(oc get configmap inferenceservice-config \
  -n redhat-ods-applications \
  -o jsonpath='{.data.storageInitializer}')
PATCHED=$(echo "$CURRENT" | python3 -c "
import json, sys
d = json.load(sys.stdin)
d['enableModelcar'] = True
print(json.dumps(d))
")
oc patch configmap inferenceservice-config \
  -n redhat-ods-applications \
  --type merge \
  -p "{\"data\":{\"storageInitializer\":$(echo $PATCHED | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')}}"

Reinicia el controlador de KServe para aplicar el cambio:

oc rollout restart deployment kserve-controller-manager -n redhat-ods-applications
oc rollout status deployment kserve-controller-manager -n redhat-ods-applications

Empaquetar los archivos del modelo en una imagen OCI

Descarga los pesos del modelo desde Hugging Face y empaquétalos en una imagen OCI. La imagen debe tener todos los archivos del modelo bajo el directorio /models. Para más información, consulta la documentación de KServe. Para despliegues con vLLM, incluye los fragmentos del modelo safetensors y excluye los archivos de checkpoint heredados como .bin, .pt y original/*.

Ejemplo de Dockerfile:

FROM busybox:latest

# Pesos del modelo — fragmentos safetensors e índice
COPY <model-name>/model-*.safetensors         /models/
COPY <model-name>/model.safetensors.index.json /models/

# Configuración del modelo
COPY <model-name>/config.json             /models/
COPY <model-name>/generation_config.json  /models/

# Tokenizador
COPY <model-name>/tokenizer.json           /models/
COPY <model-name>/tokenizer_config.json    /models/
COPY <model-name>/special_tokens_map.json  /models/

Si el modelo incluye una plantilla de chat (por ejemplo, chat_template.jinja), añádela. Como alternativa, copia el directorio completo en una sola instrucción — más sencillo, pero incluye archivos que vLLM no necesita:

FROM busybox:latest
COPY <model-name>/ /models/

Enviar la imagen a un registro privado

Envía la imagen OCI a un registro de contenedores privado accesible desde el clúster:

<registry>/<project>/<model-name>:latest

Puedes usar cualquier herramienta de gestión de imágenes compatible, incluyendo:

  • Podman
  • Skopeo
  • Pipelines de CI/CD
  • Herramientas específicas del registro

Crear el namespace de destino y el secreto de extracción de imágenes

Crea el namespace del proyecto y configura las credenciales para extraer la imagen del modelo:

oc new-project <namespace>

Crea el secreto de extracción del registro:

# Secreto de extracción para que KServe pueda extraer la imagen del modelo desde tu registro privado
oc create secret docker-registry model-registry-secret \
  --docker-server=<registry> \
  --docker-username=<username> \
  --docker-password=<password-or-token> \
  -n <namespace>

Crea una cuenta de servicio:

# Cuenta de servicio usada por el predictor de KServe
oc create sa model-puller-sa -n <namespace>

Asocia el secreto de extracción con la cuenta de servicio:

# Vincula el secreto de extracción — ambos comandos son necesarios:
# oc secrets link cubre el uso general de secretos;
# imagePullSecrets es necesario específicamente para el contenedor init ModelCar de KServe
oc secrets link model-puller-sa model-registry-secret --for=pull -n <namespace>
oc patch serviceaccount model-puller-sa -n <namespace> \
  -p '{"imagePullSecrets": [{"name": "model-registry-secret"}]}'
Nota:

Ambos comandos son necesarios. La entrada imagePullSecrets la usa el contenedor de inicialización ModelCar durante la recuperación de la imagen del modelo.

Crear un ServingRuntime

Despliega un ServingRuntime basado en vLLM en el namespace de destino:

apiVersion: serving.kserve.io/v1alpha1
kind: ServingRuntime
metadata:
  name: vllm-runtime
  namespace: <namespace>
spec:
  multiModel: false
  supportedModelFormats:
    - name: pytorch
      autoSelect: true
  containers:
    - name: kserve-container
      image: vllm/vllm-openai:<version>
      ports:
        - containerPort: 3000
          protocol: TCP
      livenessProbe:
        httpGet:
          path: /health
          port: 3000
        periodSeconds: 30
        timeoutSeconds: 5
        failureThreshold: 3
      readinessProbe:
        httpGet:
          path: /health
          port: 3000
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 3
      startupProbe:
        httpGet:
          path: /health
          port: 3000
        periodSeconds: 10
        timeoutSeconds: 5
        failureThreshold: 60

Aplica la configuración del runtime:

oc apply -n <namespace> -f serving-runtime-vllm.yaml

Desplegar el InferenceService

Crea un InferenceService que haga referencia a la imagen del modelo OCI usando un URI de almacenamiento oci://.

Requisitos clave de configuración:

  • Referencia el ServingRuntime creado anteriormente.
  • Especifica la ubicación de la imagen OCI en storageUri.
  • Configura los límites de recursos de CPU, memoria y GPU que coincidan con los requisitos del modelo.
  • Monta la memoria compartida (/dev/shm) para vLLM.
  • Configura los argumentos de runtime de vLLM y las variables de entorno.

Ejemplo:

apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
  name: <model-name>
  annotations:
    serving.kserve.io/autoscalerClass: external
    serving.kserve.io/deploymentMode: RawDeployment
spec:
  predictor:
    affinity:
      nodeAffinity:
        requiredDuringSchedulingIgnoredDuringExecution:
          nodeSelectorTerms:
            - matchExpressions:
                - key: kubernetes.io/arch
                  operator: In
                  values:
                    - amd64
    tolerations:
      - key: nvidia.com/gpu
        operator: Exists
        effect: NoSchedule
    volumes:
      - name: shm
        emptyDir:
          medium: Memory
          sizeLimit: 64Gi
    model:
      modelFormat:
        name: pytorch
      runtime: vllm-runtime
      storageUri: "oci://<registry>/<namespace-or-project>/<model-name>:latest"
      resources:
        requests:
          cpu: "<cpu-request>"          # p. ej. "8"
        limits:
          cpu: "<cpu-limit>"            # p. ej. "16"
          memory: <memory-limit>        # p. ej. 96Gi — ajusta a los requisitos de VRAM del modelo
          nvidia.com/gpu: "<gpu-count>" # p. ej. "1"
      volumeMounts:
        - name: shm
          mountPath: /dev/shm
      args:
        - /mnt/models/
        - --served-model-name=<model-name>
        - --port=3000
        - --enable-auto-tool-choice
        - --tool-call-parser=openai
      env:
        - name: HOME
          value: /tmp
        - name: MAX_LOG_LEN
          value: "100"        # trunca las líneas de log de vLLM para evitar flooding
        - name: HF_HUB_CACHE
          value: /tmp
        - name: TRITON_CACHE_DIR
          value: /tmp
        - name: XDG_CACHE_HOME
          value: /tmp
        - name: HF_HOME
          value: /tmp/hf_home
        - name: NUM_GPUS
          value: "<gpu-count>" # debe coincidir con el límite de nvidia.com/gpu anterior
        - name: CUDA_VISIBLE_DEVICES
          value: "<gpu-indices>" # p. ej. "0" para una GPU; "0,1" para dos
        - name: VLLM_WORKER_MULTIPROC_METHOD
          value: spawn
        - name: LOGNAME
          value: vllm
        - name: USER
          value: vllm

Aplica el manifiesto del InferenceService:

oc apply -n <namespace> -f isvc-<model-name>.yaml

Verificar el despliegue

Monitoriza el estado del despliegue, el inicio de los pods y los logs del runtime:

# Observa cómo el InferenceService alcanza el estado Ready
oc get inferenceservice <model-name> -n <namespace> -w

# Observa el inicio del pod predictor
oc get pods -n <namespace> -w

# Sigue los logs del predictor (la carga del modelo puede tardar varios minutos una vez en Running)
oc logs -f deployment/<model-name>-predictor -n <namespace>

Cuando el InferenceService reporte READY: True, valida el endpoint.

Verifica el registro del modelo y envía una solicitud de inferencia de prueba:

POD=$(oc get pods -n <namespace> \
  -l app=isvc.<model-name>-predictor \
  -o jsonpath='{.items[0].metadata.name}')

oc exec -n <namespace> "$POD" -c kserve-container -- \
  curl -fsS http://127.0.0.1:3000/v1/models

oc exec -n <namespace> "$POD" -c kserve-container -- \
  curl -fsS http://127.0.0.1:3000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "<model-name>",
    "messages": [{"role": "user", "content": "Hello"}],
    "max_tokens": 50
  }'

Solución de problemas

ProblemaPosible causaResolución
ErrImagePullCredenciales de registro faltantes o inválidasConfirma que model-registry-secret existe, tiene credenciales válidas y está vinculado a model-puller-sa usando tanto oc secrets link como el parche imagePullSecrets.
ImagePullBackOffSecreto de extracción de imágenes no configurado para ModelCarAsegúrate de que la cuenta de servicio incluye la configuración imagePullSecrets. Ejecuta oc patch serviceaccount model-puller-sa -n <namespace> -p '{"imagePullSecrets": [{"name": "model-registry-secret"}]}'
El predictor permanece en Init:0/1Descarga de la imagen del modelo en progresoComprueba los eventos de oc describe pod para el progreso de Pulling/Pulled; el tiempo de extracción escala con el tamaño de la imagen y el ancho de banda del registro.
El predictor permanece en Init:0/1 indefinidamenteArchivos del modelo no encontradosVerifica que los archivos del modelo estén almacenados bajo /models en la imagen OCI.
Engine core initialization failedTiempo de espera agotado en la compilación CUDA inicialEl primer inicio puede tardar más mientras se generan las cachés. Reinicia y vuelve a intentarlo.
La carga del modelo fallaFormato de archivo del modelo no compatibleUsa archivos safetensors de Hugging Face y excluye los checkpoints heredados.
Errores de autocomprobación FIPS de OpenSSLLa imagen del contenedor no es compatible con FIPSUsa una imagen de vLLM compatible con FIPS.
OutOfMemory / OOMKilledMemoria GPU insuficienteAumenta los recursos GPU, reduce la longitud del contexto o usa un modelo cuantizado.
El InferenceService permanece en PendingRecursos del clúster no disponiblesVerifica la disponibilidad de GPU y libera recursos de las cargas de trabajo no utilizadas.

Para más información, consulta:

Endpoints de modelos en cloud pública

Usa esta opción cuando los modelos están alojados por un proveedor cloud, como IBM watsonx, AWS Bedrock, Azure OpenAI o Google Vertex AI.

Prerequisitos:

  • Conectividad HTTPS saliente (puerto 443) desde el clúster de OpenShift al endpoint del servicio cloud.
  • Claves API, credenciales IAM o credenciales de autenticación equivalentes válidas.

Antes de configurar IBM Bob

Asegúrate de que:

  • El despliegue del modelo está aprovisionado y activo.
  • Las credenciales de autenticación están generadas y almacenadas de forma segura.
  • Se han completado los requisitos de red o acceso específicos del proveedor.

Una vez que el endpoint esté disponible, procede a Configurar el gateway de modelos.

Endpoints de modelos en infraestructura privada

Usa esta opción cuando los modelos están alojados en infraestructura gestionada por el cliente fuera del clúster de IBM Bob, como:

  • Servidores GPU dedicados
  • Clústeres de OpenShift separados
  • Servidores de inferencia bare-metal
  • Plataformas de IA empresariales

Prerequisitos:

  • El endpoint del modelo expone una API compatible con OpenAI.
  • Existe conectividad HTTPS entre el clúster de IBM Bob y el endpoint.
  • Las credenciales de autenticación están disponibles como secretos de Kubernetes.

Antes de configurar IBM Bob

Valida lo siguiente:

  • Conectividad de red desde el clúster al endpoint.
  • Configuración TLS o TLS mutuo, si es necesario.
  • Las políticas de red y los firewalls permiten el acceso.
  • La autenticación del endpoint funciona correctamente.

Una vez verificadas la conectividad y la autenticación, procede a Configurar el gateway de modelos.

¿Cómo es este tema?