Infraestructura de servicio de modelos

Despliega y configura endpoints de modelos para IBM Bob on-premises 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 IDE no aprovisiona, aloja ni gestiona la infraestructura de servicio de modelos. Si tu organización ya proporciona endpoints de modelos a través de Red Hat OpenShift Container Platform (OCP) AI, servidores de inferencia basados en GPU, servicios de IA en la nube u otras plataformas de inferencia, procede directamente a Configurar el gateway de inferencia de modelos.

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

OpciónCuándo usarla
OpenShift AI (en clúster, OCI/ModelCar)Modelos air-gapped o autoalojados; Red Hat OpenShift AI ya disponible en el clúster
Endpoints de modelos en nube públicaModelos de frontera a través de AWS Bedrock, Azure OpenAI o Google Vertex AI
Endpoints de modelos en infraestructura privadaModelo servido en servidores GPU separados o un clúster de inferencia dedicado

Despliegue de modelos con OpenShift AI (en clúster, OCI/ModelCar)

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

Requisitos previos:

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

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 no utilizados de Red Hat OpenShift AI.

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 la compatibilidad con ModelCar

La compatibilidad con ModelCar está controlada por 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 está ausente o es false, actualiza el ConfigMap:

# Recuperar el valor actual, combinar el flag y aplicar 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 sobre cómo preparar una imagen OCI con datos del modelo. Para despliegues 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), agrégala. Alternativamente, copia todo el directorio en una instrucción, que es más sencillo pero incluye archivos que vLLM no necesita:

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

Publicar la imagen en un registro privado

Publica la imagen OCI en un registro de contenedores privado accesible desde el clúster:

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

Usa las herramientas que se adapten a tu entorno (podman push, skopeo copy, un pipeline de CI, etc.).

Crear el namespace 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.

Crea el namespace:

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 de 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:

# Adjuntar 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 es usada por 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 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 referencie la imagen del modelo OCI usando un URI de almacenamiento oci://.

Requisitos clave de configuración:

  • Referenciar el ServingRuntime creado anteriormente.
  • Especificar la ubicación de la imagen OCI en storageUri.
  • Configurar los límites de recursos de CPU, memoria y GPU que coincidan con los requisitos del modelo.
  • Montar memoria compartida (/dev/shm) para vLLM.
  • Configurar los argumentos de runtime de vLLM y las variables de entorno.
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"        # truncar líneas de log de vLLM para evitar inundación de logs
        - 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 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

Monitorea el estado del despliegue, el inicio del pod y los logs del runtime:

# Observar el InferenceService alcanzar el estado Ready
oc get inferenceservice <model-name> -n <namespace> -w

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

# Seguir 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 informe 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 del registro ausentes 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 imagen no configurado para ModelCarAsegúrate de que la cuenta de servicio incluye la entrada imagePullSecrets. Consulta el comando oc patch serviceaccount en el paso 3.
El predictor permanece en Init:0/1Descarga de imagen del modelo en cursoConsulta los eventos de oc describe pod para ver el progreso de Pulling/Pulled; el tiempo de descarga 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 de 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 auto-prueba FIPS de OpenSSLLa imagen del contenedor no es compatible con FIPSUsa una imagen vLLM compatible con FIPS.
OutOfMemory / OOMKilledMemoria GPU insuficienteAumenta los recursos GPU, reduce la longitud del contexto o usa un modelo cuantizado.
InferenceService permanece en PendingRecursos del clúster no disponiblesVerifica la disponibilidad de GPU y libera recursos de cargas de trabajo no utilizadas.

Recursos adicionales

Uso de endpoints de modelos en nube pública

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

Requisitos previos:

  • Conectividad HTTPS de salida (puerto 443) desde el clúster de Red Hat OpenShift Container Platform (OCP) al endpoint del servicio en la nube.
  • Claves API válidas, credenciales IAM o credenciales de autenticación equivalentes.

Antes de comenzar:

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 inferencia de modelos.

Uso de 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 OpenShift separados
  • Servidores de inferencia bare-metal
  • Plataformas de IA empresariales

Requisitos previos:

  • 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 comenzar:

Valida lo siguiente:

  • Conectividad de red desde el clúster hasta el 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 inferencia de modelos.

¿Cómo es este tema?