Guide de l'utilisateur des LLM open-weight sur GDC sous air gap

Ce guide de déploiement fournit des instructions détaillées sur l'exécution de grands modèles de langage (LLM) de pointe à l'aide de logiciels Open Source (OSS) dans des environnements Google Distributed Cloud (GDC) air-gapped. Plus précisément, ce guide présente toutes les étapes nécessaires pour exécuter les dernières versions des modèles Gemma, DeepSeek et Llama, tout en présentant les procédures courantes pour diffuser d'autres LLM disponibles publiquement. Nous utiliserons des backends de diffusion conteneurisés, tels que vLLM et Ollama, qui couvrent un large éventail de fonctionnalités, différents niveaux de configuration et une facilité de déploiement.

Résumé du contenu

Ce guide explique en détail le déploiement et le fonctionnement des grands modèles de langage (LLM) Open Source dans les environnements Google Distributed Cloud (GDC) air-gapped.

Objectifs et infrastructure de base

  • Objectif : instructions détaillées pour exécuter des LLM de pointe, y compris Gemma 3 (multimodal), DeepSeek-R1 et Llama (3.1/3.2) à l'aide de backends optimisés tels que vLLM et Ollama.
  • Version minimale : version 1.15.x* du logiciel GDC sous air gap.
  • Configuration matérielle requise : au minimum 1 GPU NVIDIA A100. Un stockage hautes performances (PVC de 500 Gio ou plus) est recommandé pour optimiser les temps de chargement des pondérations de modèle, qui passent de 30 minutes à moins de 5 minutes.

Composants de déploiement

Composant Description
Backends de LLM vLLM (diffusion à haut débit avec PagedAttention) et Ollama (gestion locale simplifiée et compatibilité multimodale)
Modèles LLM disponibles publiquement, y compris les familles Gemma, DeepSeek et Llama
Accélérateurs Compatible avec les GPU NVIDIA A100 complets ou les tranches GPU multi-instances (MIG) en fonction de l'empreinte VRAM du modèle
Services GDC Utilise GDC Container Service, Load Balancer (ELB/ILB), Harbor Container Registry

Procédures opérationnelles clés

  • Gestion des modèles : le backend LLM gère le chargement et le déchargement des modèles en fonction de l'utilisation. vLLM épingle les modèles en mémoire pour une latence faible et constante, tandis qu'Ollama permet le chargement de modèles dynamiques, mais les décharge automatiquement après 30 minutes d'inactivité.
  • Personnalisation : les utilisateurs peuvent importer les LLM de leur choix en les extrayant d'Internet, en créant de nouvelles images Docker et en les important dans le registre Harbor local.

Prérequis

Version

  • GDC sous air gap version 1.15.1 ou ultérieure.

Composants

  • Cluster utilisateur créé avec des ressources suffisantes (CPU, mémoire, GPU).
  • Un GPU NVIDIA A100 minimum est requis.
  • L'instance Harbor est disponible et accessible.
  • Les CLI kubectl et gdcloud sont configurées pour accéder au cluster d'utilisateur.
  • Le client Docker est installé et configuré pour envoyer des données à Harbor.
  • Les autorisations IAM nécessaires sont accordées (par exemple, Administrateur de l'espace de noms, Développeur de cluster).
  • Un compte Hugging Face et une authentification configurés si vous utilisez des modèles avec accès restreint.

Capacité nécessaire

Ressource Capacité
Processeur 8 vCPU
Mémoire vive 32 Gio
Stockage éphémère 16 Gio
GPU 1 GPU NVIDIA A100
Volume persistant *500 Gio et plus

Ces ressources matérielles sont nécessaires pour que les backends de diffusion exécutent des LLM avec accélération GPU. Par exemple, un type de machine a2-ultragpu-1g-gdc fournirait suffisamment de ressources.

Schéma complet

Diagramme de diffusion de LLM open-weight de haut niveau.

Ce schéma représente un utilisateur qui consomme des API exposées par deux backends LLM, vLLM et Ollama, pour obtenir des réponses d'inférence à partir de modèles Open Source, tels que Gemma, Llama et DeepSeek. Selon la taille du modèle, mesurée en milliards de paramètres, chaque LLM peut avoir besoin d'un GPU complet ou d'une partie de celui-ci pour s'exécuter.

Diagramme des limites de service et de sécurité pour un déploiement de LLM

Cette solution repose sur les services suivants, qui sont déjà inclus dans la pile logicielle GDC sous air gap :

  • Service de conteneurs GDC : pour exécuter tous les processus et les mettre à l'échelle à l'aide du AHP.
  • Équilibreur de charge GDC : il utilise un service Kubernetes pour desservir tous les backends de cette solution et rendre les LLM accessibles depuis le réseau client. Il est appelé ELB, qui signifie "External Load Balancer" (Équilibreur de charge externe). À l'inverse, le client peut choisir de conserver les LLM accessibles uniquement depuis un cluster d'utilisateur. Cela peut être utile lorsqu'un agent interne demande des inférences dans sa solution. On parle alors d'ILB, qui signifie Internal Load Balancer (équilibreur de charge interne).
  • CI/CD GDC : Harbor Container Registry pour stocker les backends LLM et les pondérations de modèle.
  • Pile d'observabilité GDC : permet de collecter et de rechercher les journaux de backend, et de fournir des tableaux de bord.

En termes de sécurité, l'accès au déploiement du LLM dépend des utilisateurs qui peuvent accéder au service d'équilibreur de charge qui expose les backends de diffusion du LLM, lesquels s'exécutent en tant que pods dans un projet ou un espace de noms Kubernetes.

Diagramme de l'architecture des limites de service et de sécurité.

Déploiement

Prérequis

Installez les outils suivants sur une station de travail connectée à votre environnement GDC sous air gap :

  1. docker
  2. kubectl
  3. gdcloud CLI

Ce document contient tous les fichiers de code source et de configuration dont vous avez besoin pour déployer des LLM.

Créer un secret pour extraire des images de Harbor

Pour configurer un secret d'extraction d'image pour une charge de travail de conteneur dans GDC sous air gap, vous devez créer un secret Kubernetes docker-registry contenant les identifiants permettant d'accéder à votre projet Harbor privé. Ce secret est ensuite référencé dans votre spécification de déploiement.

Vous devez utiliser un compte robot Harbor pour accéder de manière programmatique aux images dans les projets Harbor privés.

Pour configurer le secret d'extraction d'image, procédez comme suit :

Créez un compte robot Harbor :

  • Accédez à l'UI de votre instance Harbor.
  • Accédez à votre projet Harbor.
  • Sélectionnez l'onglet Comptes robot.
  • Cliquez sur + NOUVEAU COMPTE ROBOT.
  • Donnez-lui un nom (par exemple, oss-llm-puller) et accordez-lui les autorisations nécessaires (au moins l'accès "pull") jusqu'à une heure d'expiration.
  • Stockez de manière sécurisée le nom du compte robot (par exemple, robot$oss-llm-puller) et le jeton secret fourni.

Authentifiez Docker auprès de Harbor :

Sur votre machine sur laquelle Docker est installé et qui a accès au réseau du registre Harbor, connectez-vous à l'aide des identifiants du compte robot :

export INSTANCE_URL="your-harbor-instance-url"
# for example, harbor1-project1.org1.zone1.google.gdc.com

export ROBOT_NAME="your-robot-account-name"
# for example, robot\$oss-llm-puller (note how we escape the $ character)

export ROBOT_SECRET="your-robot-account-secret"

docker login ${INSTANCE_URL} --username ${ROBOT_NAME} --password ${ROBOT_SECRET}

# Sample output:

WARNING! Using --password via the CLI is insecure. Use --password-stdin.

WARNING! Your credentials are stored unencrypted in '$HOME/.docker/config.json'.
Configure a credential helper to remove this warning. See
https://docs.docker.com/go/credential-store/

Login Succeeded

Comme indiqué dans l'exemple de résultat, cette commande met à jour votre fichier de configuration Docker local ($HOME/.docker/config.json) avec les informations d'authentification. Le fichier config.json se présente comme suit :

{
    "auths": {
        "harbor1-project1.org1.zone1.google.gdc.com": {
            "auth": "...omitted..."
        }
    }
}

Si vous avez utilisé votre client Docker pour vous connecter à d'autres registres par le passé, vous verrez plus d'entrées dans "auths".

Créez le secret Kubernetes pour l'extraction d'images :

Utilisez kubectl pour créer un secret de type docker-registry dans l'espace de noms de votre projet, à l'aide du fichier de configuration Docker mis à jour à l'étape précédente :

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS certificate}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

export SECRET_NAME="oss-llm-pull-secret" # You can choose another name
export NAMESPACE="your-project-namespace"
# Assuming default Docker config path. Adjust if necessary.
export DOCKER_CONFIG_PATH="$HOME/.docker/config.json"

kubectl create secret docker-registry ${SECRET_NAME} \
      --from-file=.dockerconfigjson=${DOCKER_CONFIG_PATH} \
      -n ${NAMESPACE}

Vous ferez référence à ce secret plus tard dans la spécification de votre conteneur backend LLM en incluant le champ imagePullSecrets.

En suivant ces étapes, votre cluster Kubernetes utilisera désormais les identifiants fournis pour extraire une image de conteneur de votre registre Harbor privé dans votre environnement GDC sous air gap. Ces étapes sont également incluses dans la documentation du produit.

Configurer le déploiement du LLM

Vous avez le choix entre deux options pour le backend LLM :

  • vLLM
  • Ollama

Vous pouvez en choisir un ou déployer les deux. Chaque backend peut exécuter un ou plusieurs LLM, par exemple :

  • Gemma 3
  • DeepSeek
  • Llama
  • Autres LLM

La section 1 explique comment déployer vLLM, tandis que la section 2 montre comment installer Ollama.

1. Déployer vLLM comme backend LLM

Obtenir l'image Docker vLLM

En général, vLLM est utilisé pour mettre en service des modèles téléchargés depuis HuggingFace, comme nous le montrerons dans ce déploiement de LLM. Certains modèles sont soumis à un accès restreint. Cela signifie que les utilisateurs doivent demander explicitement l'accès à leurs fichiers et contenus sur le Hugging Face Hub ou l'accepter avant de pouvoir les télécharger ou les utiliser.

Connectez-vous à votre instance Harbor à l'aide de Docker, comme expliqué dans la documentation. Sur une machine ayant accès à Internet, extrayez l'image Docker vLLM, puis transférez-la vers votre projet Harbor :

# Pull and Tag vLLM (v0.13.0 recommended for stability)
docker pull vllm/vllm-openai:v0.13.0
docker tag vllm/vllm-openai:v0.13.0 HARBOR_URL/PROJECT/vllm-openai:v0.13.0
docker push HARBOR_URL/PROJECT/vllm-openai:v0.13.0

Remplacez les éléments suivants :

  • HARBOR_URL : URL de l'instance Harbor.
  • PROJECT : nom du projet Harbor.

La version de vLLM utilisée pour ce guide de déploiement est la suivante : v0.13.0

Stocker les pondérations de votre modèle LLM dans un PVC

Ouvrez un nouveau terminal et créez un dossier dans lequel vous enregistrerez vos fichiers de déploiement vLLM :

mkdir vllm-deployment
cd vllm-deployment

Créez ensuite un fichier YAML (par exemple, model-pvc.yaml) pour déclarer une PersistentVolumeClaim (PVC) à l'aide des primitives Kubernetes standards :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: model-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 500Gi
  storageClassName: standard-rwo
  volumeMode: Filesystem

Connectez-vous à votre cluster GDC sous air gap et appliquez le PVC :

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS cert}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

# Apply the PVC manifest
kubectl apply -f model-pvc.yaml

Téléchargez les pondérations du modèle depuis Hugging Face :

# Log in to Hugging Face
hf auth login

# Download weights for Gemma 3 (for example, 4B instruction-tuned)
hf download google/gemma-3-4b-it

Exemple de résultat :

Fetching 9 files: 100%| 9/9 [00:00<00:00, 19.34it/s]
Downloading (…)7f58a/.gitattributes: 100%| 1.62k/1.62k [00:00<00:00, 7.82MB/s]
Downloading (…)del-00002-of-00002.safetensors: 100%| 3.75G/3.75G [00:46<00:00, 81.3MB/s]
Downloading (…)del-00001-of-00002.safetensors: 100%| 4.90G/4.90G [00:54<00:00, 90.1MB/s]
Downloading (…)-3-4b-it/README.md: 100%| 23.3k/23.3k [00:00<00:00, 48.0MB/s]
Downloading (…)8a/model.safetensors.index.json: 100%| 26.3k/26.3k [00:00<00:00, 39.5MB/s]
Downloading (…)f58a/config.json: 100%| 908/908 [00:00<00:00, 4.41MB/s]
Downloading (…)generation_config.json: 100%| 210/210 [00:00<00:00, 936kB/s]
Downloading (…)tokenizer.json: 100%| 33.1M/33.1M [00:01<00:00, 17.6MB/s]
/Users/rashjab/.cache/huggingface/hub/models--google--gemma-3-4b-it/snapshots/952ec8ffca3adadfd00c6d71b40280ebdbb7f58a

Comme vous pouvez le voir dans l'exemple de sortie, la taille du modèle sur le disque est de 8,64 Go, ce qui correspond au PVC de 500 Gio que nous avons défini précédemment. Assurez-vous toujours que c'est le cas pour tout modèle que vous choisissez de charger dans le volume persistant (PV). Par exemple, un modèle de 15 Go utilisant un PVC de 500 Gio pour atteindre 1 500 IOPS réduit considérablement le temps de chargement des poids, qui passe d'environ 30 minutes à moins de 5 minutes.

Remplissez le PV en copiant les fichiers de modèle dans son volume. Cela implique souvent :

  • Créer un pod "d'assistance" temporaire qui monte le PV.
  • Utilisez kubectl cp pour copier les fichiers de modèle de votre station de travail dans le volume monté du pod d'assistance.
  • Exemple de pod d'assistance :

helper-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: model-uploader
spec:
  containers:
  - name: uploader
    image: HARBOR_URL/PROJECT/busybox:latest
    command: ["sleep", "3600"]
    volumeMounts:
    - name: model-data
      mountPath: /data
  imagePullSecrets:
  - name: oss-llm-pull-secret
  volumes:
  - name: model-data
    persistentVolumeClaim:
      claimName: model-pvc

Remplacez les éléments suivants :

  • HARBOR_URL : URL de l'instance Harbor.
  • PROJECT : nom du projet Harbor.
  • oss-llm-pull-secret : si vous avez choisi un autre nom de secret de récupération d'image.
  • model-pvc par le nom que vous avez donné à votre PVC.

Transférez l'image Docker d'assistance (busybox) :

docker pull busybox:latest
docker tag busybox HARBOR_URL/PROJECT/busybox:latest
docker push HARBOR_URL/PROJECT/busybox:latest

Remplacez les éléments suivants :

  • HARBOR_URL : URL de l'instance Harbor.
  • PROJECT : nom du projet Harbor.

Appliquez le fichier helper-pod.yaml et copiez les pondérations du modèle dans le PV :

kubectl apply -f helper-pod.yaml

# Wait for the pod to be Running
kubectl cp ~/.cache/huggingface/hub/ NAMESPACE/model-uploader:/data/

# After copying, delete the helper pod
kubectl delete pod model-uploader

Déployer le backend vLLM

Créez le fichier de déploiement pour que vLLM exécute le serveur de modèle. L'exemple suivant déploie le modèle gemma-3-4b-it.

vllm-gemma-3-4b-it-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: gemma-3-4b-it
  labels:
    app: gemma-3-4b-it
spec:
  replicas: 1
  selector:
    matchLabels:
      app: gemma-3-4b-it
  template:
    metadata:
      labels:
        app: gemma-3-4b-it
    spec:
      volumes:
      - name: cache-volume
        persistentVolumeClaim:
          claimName: model-pvc # change with the name you gave initially to your PVC
      # vLLM needs to access the host's shared memory for tensor parallel inference.
      - name: shm
        emptyDir:
          medium: Memory
          sizeLimit: "16Gi"
      containers:
      - name: gemma-3-4b-it
        image: HARBOR_URL/PROJECT/vllm-openai:v0.13.0
        command: ["python3"]
        args: [
          "-m",
          "vllm.entrypoints.openai.api_server",
          "--model",
          "google/gemma-3-4b-it", # Use the repo ID
          "--max-model-len",
          "32768",
          "--enforce-eager"
        ]
        env:
        - name: HF_HUB_OFFLINE
          value: "1"
        - name: HF_HOME
          value: "/model" # Tells vLLM to look for models in /model/hub
        # --- PERFORMANCE & STABILITY OPTIMIZATIONS ---
        - name: NCCL_P2P_DISABLE
          value: "1" # Prevents initialization hangs on P2P checks
        - name: NCCL_IB_DISABLE
          value: "1" # Prevents initialization hangs on InfiniBand checks
        # --- FIPS BYPASS ---
        - name: BORINGSSL_FIPS
          value: "0"
        - name: OPENSSL_FIPS
          value: "0"
        - name: OPENSSL_CONF
          value: "/dev/null"
        - name: FIPS_SIG
          value: "off"
        ports:
        - containerPort: 8000
        securityContext:
          privileged: true
          runAsUser: 0
        resources:
          limits:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
            cpu: "8"       # Increased to handle model weight verification
            memory: "64Gi"  # Increased to ensure headroom for weight loading
          requests:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
            cpu: "8"
            memory: "32Gi"
        volumeMounts:
        - name: cache-volume
          mountPath: /model
        - name: shm
          mountPath: /dev/shm
      imagePullSecrets:
      - name: oss-llm-pull-secret

Remplacez les éléments suivants :

  • HARBOR_URL : URL de l'instance Harbor.
  • PROJECT : nom du projet Harbor.
  • oss-llm-pull-secret : nom que vous avez attribué lors de la création du secret de récupération d'image.
  • claimName : nom que vous avez donné à votre première création de PVC.

Ensuite, créez un fichier de service Kubernetes pour exposer les API de backend vLLM :

vllm-gemma-3-4b-it-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: gemma-3-4b-it
  namespace: NAMESPACE
spec:
  ports:
  - name: http-gemma-3-4b-it
    port: 80
    protocol: TCP
    targetPort: 8000
  selector:
    app: gemma-3-4b-it
  sessionAffinity: None
  type: LoadBalancer

Appliquez les configurations de déploiement et de service :

kubectl apply -f vllm-gemma-3-4b-it-deployment.yaml
kubectl apply -f vllm-gemma-3-4b-it-service.yaml

Vérifier et tester le déploiement vLLM

  1. Vérifiez l'état du pod :

    kubectl get pods
    

    Attendez que le pod soit à l'état Running.

  2. Vérifiez le service :

    kubectl get service
    

    Exemple de résultat :

    # NAME          TYPE         CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
    # gemma-3-4b-it LoadBalancer 10.201.136.62  136.125.37.198   80:30109/TCP   3d1h
    

    Notez le EXTERNAL-IP du service vLLM (par exemple, 136.125.37.198) à partir de la sortie précédente. Vous pouvez également l'imprimer avec :

    kubectl get service gemma-3-4b-it \
    -o jsonpath='{.status.loadBalancer.ingress[*].ip}'
    
  3. Affichez les journaux :

    kubectl logs YOUR_VLLM_POD
    

    Recherchez les messages indiquant que le serveur a démarré et que le modèle est chargé (par exemple, INFO: Application startup complete.). Comme il n'y a pas de téléchargement Hugging Face, l'opération devrait être rapide si les fichiers se trouvent sur le PVC avec une capacité de volume persistant élevée.

  4. Testez l'inférence avec curl :

    Une fois que vous avez vérifié que le pod vLLM est en cours d'exécution et que vous disposez de l'adresse IP externe du service, vous pouvez envoyer une requête d'inférence à l'aide de curl. Étant donné que vLLM fournit une API compatible avec OpenAI, vous pouvez utiliser le point de terminaison /v1/chat/completions :

    curl http://EXTERNAL_IP/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "google/gemma-3-4b-it",
        "messages": [
          {"role": "user", "content": "What is Google Distributed Cloud air-gapped?"}
        ],
        "max_tokens": 100
      }'
    

    Remplacez EXTERNAL_IP par l'adresse IP externe du service vLLM.

2. Déployer Ollama comme backend LLM

Ollama est un framework populaire permettant d'exécuter des LLM Open Source localement et dans des environnements conteneurisés. Il simplifie l'exécution du modèle en gérant les téléchargements de pondérations, la quantification et l'accélération du GPU. Il inclut une API REST intégrée pour générer des complétions, des réponses de chat et des embeddings.

Contrairement à d'autres moteurs de diffusion, Ollama gère l'exécution des modèles de manière dynamique :

  • Chargement dynamique des modèles : lorsqu'une requête pour un modèle spécifique est reçue, Ollama charge les pondérations en mémoire (VRAM GPU ou RAM système) à la demande.
  • Déchargement en cas d'inactivité : si aucune requête d'inférence n'est reçue pour un modèle pendant 30 minutes (configurable avec OLLAMA_KEEP_ALIVE), Ollama le décharge de la mémoire pour libérer des ressources matérielles pour d'autres charges de travail.
  • Un seul modèle actif par instance : Ollama traite les requêtes pour un seul modèle actif à la fois par instance de serveur. Si plusieurs modèles sont appelés en parallèle, Ollama met les requêtes en file d'attente et échange les modèles de manière séquentielle, ce qui peut entraîner une latence. Pour diffuser plusieurs modèles simultanément sans les échanger, vous devez déployer des instances Ollama distinctes pour chaque modèle.

Télécharger les pondérations du modèle et créer une image Docker

Contrairement à vLLM, qui peut charger des poids directement à partir d'un volume persistant, Ollama s'attend généralement à ce que les modèles soient stockés dans son format de répertoire interne (~/.ollama/models).

Dans un environnement isolé, où les conteneurs d'exécution ne peuvent pas télécharger de modèles depuis l'Internet public, vous devez pré-empaqueter les pondérations du modèle dans l'image de conteneur elle-même lors de la phase de compilation. Cette approche garantit que le conteneur est entièrement autonome et prêt à être diffusé immédiatement après le déploiement, sans nécessiter d'accès au réseau externe.

Créez un dossier pour le déploiement Ollama :

mkdir ollama-gemma3
cd ollama-gemma3

Créez un Dockerfile avec le contenu suivant :

# Use a standard Linux base image
FROM ubuntu

# Install necessary dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
    curl \
    ca-certificates \
    zstd \
    && rm -rf /var/lib/apt/lists/*

# Install Ollama
# This uses Ollama's official installation script, which adds Ollama to /usr/local/bin
RUN curl -fsSL https://ollama.com/install.sh -o install.sh && \
    chmod +x install.sh && \
    ./install.sh && \
    rm install.sh

# Set environment variables for Ollama (optional, but a good practice)
# ENV OLLAMA_HOST="0.0.0.0"

# If you want to customize the model storage path within the container, set OLLAMA_MODELS, for example:
# ENV OLLAMA_MODELS="/usr/local/ollama/models"
# The default OLLAMA_MODELS is /root/.ollama
# Then, ensure you create and populate that directory.

# --- Download Gemma 3 model weights ---
# This step starts Ollama server in the background, pulls the model,
# and then kills the server to allow the Docker build to continue.
# This approach works around the Docker RUN command limitations for services.

RUN ollama serve & \
    # Give the Ollama server a moment to start up
    # Use --retry and --retry-connrefused to handle startup delays
    curl --retry 10 --retry-connrefused -s http://localhost:11434 || true && \
    # Pull the Gemma 3 model weights
    ollama pull gemma3:latest && \
    # Stop the background Ollama server process cleanly
    pkill ollama || true

# Expose Ollama's default port
EXPOSE 11434

# Command to run Ollama server when the container starts
CMD ["ollama", "serve"]

Si vous souhaitez essayer un autre LLM Open Source, tel qu'un modèle des familles Llama 3.2 ou DeepSeek-R1, modifiez cette commande Ollama dans le Dockerfile précédent :

ollama pull gemma3:latest

Par exemple, si vous souhaitez extraire Llama 3.2 avec 3 milliards de paramètres, utilisez la commande suivante :

ollama pull llama3.2:3b

Si vous préférez utiliser DeepSeek-R1 avec 8 milliards de paramètres, utilisez cette commande :

ollama pull deepseek-r1:8b

Vous pouvez également télécharger plusieurs LLM et conteneuriser leurs pondérations de modèle. Ollama pourra alors basculer entre les modèles lorsque vous demanderez des inférences par différents modèles préchargés. Par exemple, vous pouvez ajouter les modèles Gemma et Llama à votre image Docker. Rappelez-vous que dans un environnement isolé, un backend Ollama n'a pas accès à la bibliothèque Ollama pour télécharger un modèle à tout moment.

N'oubliez pas de vérifier et d'accepter les conditions d'utilisation et la licence de chaque modèle avant de les exécuter dans vos applications. La bibliothèque Ollama contient de nombreux LLM. Vous n'aurez besoin d'une connexion Internet que pour télécharger les pondérations du modèle lors de la création de l'image Docker du backend LLM.

Créez l'image Docker et transmettez-la à Harbor.

Connectez-vous à votre instance Harbor à l'aide de Docker, comme expliqué dans la documentation. Créez l'image Docker Gemma 3 et importez-la dans votre dépôt Harbor :

docker build -t ollama-gemma3 .
docker tag ollama-gemma3 HARBOR_URL/PROJECT/ollama-gemma3:latest
docker push HARBOR_URL/PROJECT/ollama-gemma3:latest

Remplacez les éléments suivants :

  • HARBOR_URL : URL de l'instance Harbor.
  • PROJECT : nom du projet Harbor.

Version d'Ollama utilisée pour ce guide de déploiement : 0.14.1

Préparer un déploiement et un service Kubernetes

Créez un fichier nommé ollama-gemma3.yaml pour définir le déploiement du backend Ollama et sa configuration d'équilibrage de charge afin de l'exposer en tant que service :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ollama-gemma3
  namespace: osd-dev
  labels:
    app: ollama-gemma3
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ollama-gemma3
  template:
    metadata:
      labels:
        app: ollama-gemma3
    spec:
      containers:
      - name: ollama-gemma3
        image: rashjab-mhs-rashjab-test2.gdc1.us-west6-a.staging.gpcdemolabs.com/rashjab-repo/ollama-gemma3:latest
        env:
        # This is the crucial fix: Tell Ollama to listen on all network interfaces
        - name: OLLAMA_HOST
          value: "0.0.0.0"
        imagePullPolicy: Always
        ports:
        - containerPort: 11434
        securityContext:
          privileged: true
          runAsUser: 0
        resources:
          limits:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
          requests:
            nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1
      imagePullSecrets:
      - name: oss-llm-pull-secret
---
apiVersion: v1
kind: Service
metadata:
  name: ollama-gemma3
  namespace: osd-dev
spec:
  type: LoadBalancer
  selector:
    app: ollama-gemma3
  ports:
  - name: ollama-gemma3-port
    port: 11434
    protocol: TCP
    targetPort: 11434

Remplacez les éléments suivants :

  • HARBOR_URL : URL de l'instance Harbor.
  • PROJECT : nom du projet Harbor.
  • oss-llm-pull-secret : si vous avez choisi un autre nom de secret de récupération d'image.

Vérifier l'allocation de GPU

GDC sous air gap est compatible avec les GPU multi-instances (MIG) NVIDIA. Vous pouvez consulter ses différents profils MIG dans la documentation publique. Si vous déployez de petits LLM, il est conseillé de vérifier leur taille (en mémoire) et de partitionner vos GPU en conséquence. Le schéma de partitionnement d'un pool de nœuds est défini dans sa ressource personnalisée Cluster. Pour savoir comment appliquer un schéma de partitionnement de GPU, consultez Ajouter un pool de nœuds. Si vous êtes un opérateur d'application, consultez votre administrateur de plate-forme concernant les accélérateurs installés et disponibles dans votre projet / cluster. Pour en savoir plus sur la configuration d'un conteneur pour utiliser les ressources GPU et sur la vérification de l'allocation des ressources GPU, consultez la documentation.

La précision par défaut du modèle Gemma 3 4B est de 16 bits. Selon ce tableau publié par Google, la mémoire GPU requise pour ce LLM est de 6,4 Go, avec une précision BF16 (16 bits).

Dans le ollama-gemma3.yaml précédent, nous avons associé une tranche de GPU de 10 Go (NVIDIA A100) au conteneur, car cette quantité de mémoire VRAM est suffisante pour charger et exécuter le modèle Gemma 3 4B, comme indiqué ci-dessous :

ollama-gemma3.yaml

... omitted ...

        resources:
          limits:
            nvidia.com/mig-1g.10gb-NVIDIA_A100_80GB_PCIE: 1
          requests:
            nvidia.com/mig-1g.10gb-NVIDIA_A100_80GB_PCIE: 1

... omitted ...

Déployer le backend Ollama et l'exposer en tant que service

Connectez-vous à votre cluster et définissez le contexte sur l'espace de noms de votre projet :

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS certificate}

gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

Appliquez le fichier manifeste Ollama :

kubectl apply -f ollama-gemma3.yaml

Assurez-vous que le pod Ollama est en cours d'exécution et que le service associé est en place :

kubectl get pods

Exemple de résultat :

# NAME                             READY   STATUS    RESTARTS   AGE
# ollama-gemma3-6fc6fff74b-9qtpf   1/1     Running   0          1h
kubectl get service

Exemple de résultat :

# NAME             TYPE          CLUSTER-IP    EXTERNAL-IP    PORT(S)          AGE
# ollama-gemma3   LoadBalancer  172.0.0.1     10.0.0.1       11434:31822/TCP  1d

Notez le EXTERNAL-IP du service Ollama (par exemple, 10.0.0.1) à partir du résultat précédent. Vous pouvez également l'imprimer avec :

kubectl get service ollama-gemma3 \
-o jsonpath='{.status.loadBalancer.ingress[*].ip}'

Avant de vérifier qu'Ollama Gemma 3 fonctionne, vous devez appliquer une règle de réseau, par exemple :

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-ollama-ingress
  namespace: osd-dev
spec:
  subject:
    subjectType: UserWorkload
  policyType: Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0 # Allows traffic from any IP. Restrict this for production.
    ports:
    - protocol: TCP
      port: 11434

Appliquez la règle de réseau :

kubectl apply -f ollama-netpol.yaml

Vérifiez et testez le déploiement Ollama :

  1. Vérifiez si Ollama est en cours d'exécution :

    curl http://EXTERNAL_IP:11434
    

    Réponse attendue : "Ollama is running" (Ollama est en cours d'exécution)

  2. Envoyez une requête de complétion :

    curl -X POST http://EXTERNAL_IP:11434/v1/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "gemma3:latest",
        "prompt": "Google Distributed Cloud air-gapped is a",
        "max_tokens": 128,
        "temperature": 0.90
      }'
    

Demander des inférences

Maintenant que vos backends LLM (vLLM et Ollama) sont déployés et accessibles via leurs services LoadBalancer respectifs, vous pouvez commencer à les utiliser pour l'inférence.

Selon votre cas d'utilisation, vous disposez de plusieurs options :

  • Interface utilisateur Web interactive : pour tester, prototyper ou fournir une expérience semblable à ChatGPT aux utilisateurs, vous pouvez déployer Open WebUI ou une interface utilisateur semblable.
  • Interface de ligne de commande (CLI) : pour une vérification, un script ou une automatisation rapides, vous pouvez utiliser curl ou des scripts personnalisés.
  • Intégration d'applications : connectez vos applications internes, vos agents d'IA ou vos plug-ins d'IDE (par exemple, Continue pour VS Code/JetBrains) directement aux points de terminaison compatibles avec OpenAI fournis par vLLM (/v1) ou Ollama (/v1).

1. Interagir avec le LLM à l'aide d'une interface utilisateur

Pour fournir une interface de type ChatGPT permettant d'interagir avec vos modèles, déployez Open WebUI dans votre cluster.

Créer le déploiement Open WebUI

Créez open-webui-deployment.yaml :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: open-webui
  namespace: osd-dev
  labels:
    app: open-webui
spec:
  replicas: 1
  selector:
    matchLabels:
      app: open-webui
  template:
    metadata:
      labels:
        app: open-webui
    spec:
      containers:
      - name: open-webui
        image: HARBOR_URL/PROJECT/open-webui:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        env:
        - name: OPENAI_API_BASE_URL
          value: "http://gemma-3-4b-it/v1" # Point to your vLLM service
        - name: OPENAI_API_KEY
          value: "EMPTY"
        - name: WEBUI_AUTH
          value: "False"
      imagePullSecrets:
      - name: oss-llm-pull-secret
---
apiVersion: v1
kind: Service
metadata:
  name: open-webui
  namespace: osd-dev
spec:
  type: LoadBalancer
  selector:
    app: open-webui
  ports:
  - port: 80
    targetPort: 8080

Appliquer la règle de réseau

Vous devez autoriser votre machine à accéder au service Open WebUI sur le port 80.

Mettez à jour votre règle de réseau de projet PNP pour inclure le service open-webui ou appliquez-en une plus large :

apiVersion: networking.gdc.goog/v1
kind: ProjectNetworkPolicy
metadata:
  name: allow-webui-ingress
  namespace: NAMESPACE
spec:
  subject:
    subjectType: UserWorkload
  policyType: Ingress
  ingress:
  - from:
    - ipBlock:
        cidr: 0.0.0.0/0 # Allows traffic from any IP then restrict this for production
    ports:
    - protocol: TCP
      port: 8080

Validation

  1. Obtenez l'adresse IP de l'interface utilisateur Web :

    kubectl get service open-webui -n NAMESPACE
    
  2. Accédez à l'UI : ouvrez votre navigateur et accédez à http://WEB_UI_EXTERNAL_IP.

  3. Configurer : lors de la première connexion, créez un compte administrateur. Dans les paramètres, assurez-vous que la connexion OpenAI pointe vers http://gemma-3-4b-it/v1.

  4. Sélectionnez le modèle : dans l'interface de chat, sélectionnez google/gemma-3-4b-it dans le menu déroulant des modèles.

    Ouvrez le menu déroulant de sélection du modèle de l'interface Web.

2. Envoyer des requêtes HTTP à l'aide d'une CLI

  • curl :
curl -X POST http://OLLAMA_LOAD_BALANCER_IP:11434/v1/completions \
-H "Content-Type: application/json" \
-d '{
  "model": "gemma3:latest",
  "prompt": "Google Distributed Cloud air-gapped is a",
  "max_tokens": 128,
  "temperature": 0.90
}'

Validation et vérification

Vérifiez que tous les conteneurs et services sont en cours d'exécution :

# Log in to GDC air-gapped using the next commands

gdcloud auth login --login-config-cert {path to your web TLS cert}
gdcloud clusters get-credentials {Your User Cluster}
kubectl config set-context --current --namespace=NAMESPACE

# Pods

kubectl get pods # This command should return results like below

# NAME                                   READY   STATUS    RESTARTS   AGE
# vllm-6fc6fff74b-9qtpf                 1/1     Running   0          1h
# ollama-798fbf6ff6-9m7ln               1/1     Running   0          1h


# Services

kubectl get services # This command should return results like below

# NAME                      TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)           AGE
# vllm-service              LoadBalancer   172.0.0.1        10.0.0.1       11434:31822/TCP   1h
# ollama-service        LoadBalancer   172.0.0.2        10.0.0.2       11434:30728/TCP   1h

Procédure de suppression

  1. Supprimez toutes les ressources Kubernetes :

    kubectl delete -f vllm-gemma-3-4b-it-deployment.yaml
    kubectl delete -f vllm-gemma-3-4b-it-service.yaml
    
  2. Supprimez manuellement les conteneurs inutilisés de votre dépôt Harbor.

Opérations

Backend vLLM

Principes de base de vLLM

vLLM est conçu comme un moteur de mise en service de modèle unique hautes performances. Il ne permet pas de diffuser plusieurs modèles dans un même processus de serveur ni de définir plusieurs modèles dans une même commande de démarrage. Pour mettre en service plusieurs modèles (par exemple, un modèle de chat et un modèle d'embedding distinct), vous devez lancer des instances vLLM distinctes, chacune dans son propre pod ou conteneur, éventuellement attribuées à différents GPU ou tranches de GPU. Contrairement à d'autres backends qui peuvent échanger des modèles de manière dynamique, une instance vLLM épingle son modèle et la mémoire cache KV associée lors de l'initialisation pour garantir un débit élevé et une faible latence constants.

Vous pouvez ouvrir un terminal sur l'un des pods vLLM à l'aide des commandes suivantes :

kubectl exec -it gemma-3-4b-random-string -n NAMESPACE -- /bin/bash

Vous verrez ainsi les modèles chargés, leurs arguments et leurs PID :

ps aux | grep vllm

Résultat similaire attendu :

root           1  0.1  0.8 9436960 1550504 ?     Ssl  Feb04   9:18 python3 -m vllm.entrypoints.openai.api_server --model google/gemma-3-4b-it --max-model-len 32768 --enforce-eager
root         504  0.0  0.0   3476  1596 pts/0    S+   02:48   0:00 grep --color=auto vllm

Si vous souhaitez obtenir une vue plus claire, plus "Ollama-like", sans l'encombrement de la commande grep elle-même et des PID système, vous pouvez utiliser cette commande sur une seule ligne :

ps aux | grep [v]llm.entrypoints | awk -F'--model ' '{print $2}' | awk '{print $1}'

Exemple de réponse :

google/gemma-3-4b-it

Vous pouvez surveiller l'état de votre déploiement vLLM à l'aide des commandes kubectl standards et en interrogeant les points de terminaison de l'API interne.

Vérifier les journaux des pods

Ouvrez un terminal pour afficher les journaux d'initialisation et de diffusion :

kubectl logs -f gemma-3-4b-it-random_string -n NAMESPACE

Recherchez la confirmation que le serveur est prêt :

(APIServer pid=1) INFO:     Started server process [1]
(APIServer pid=1) INFO:     Waiting for application startup.
(APIServer pid=1) INFO:     Application startup complete.

Interroger l'état interne

Étant donné que vLLM fournit une API compatible avec OpenAI, vous pouvez vérifier les modèles chargés et l'état du système directement à partir d'un terminal à l'intérieur du cluster (par exemple, à l'aide d'un pod debug-sh).

Vous devez d'abord lancer le pod de débogage. Voici les instructions :

Lancer le pod de débogage

Exécutez la commande suivante pour démarrer un shell éphémère dans l'espace de noms de votre projet. Cette configuration utilise l'image busybox (précédemment transférée vers votre registre Harbor) et injecte les identifiants nécessaires avec l'indicateur --overrides :

kubectl run --rm -it debug-sh \
  --image=HARBOR_URL/PROJECT/busybox:latest \
  --restart=Never -n osd-dev --overrides='{
    "spec": {
      "imagePullSecrets": [{"name": "oss-llm-pull-secret"}]
    }
  }' -- sh

Paramètres clés :

  • --rm : supprime automatiquement le pod à la sortie, ce qui préserve les ressources du cluster.
  • --overrides : obligatoire dans les environnements isolés pour permettre au pod de s'authentifier auprès du registre Harbor privé.

État du serveur du modèle de requête

Une fois dans le pod, utilisez l'utilitaire wget pour interroger l'API vLLM. Étant donné que le service vLLM mappe le port interne 8000 au port 80, vous pouvez utiliser le nom DNS du service :

  • Lister les modèles chargés : vérifiez que le moteur vLLM a bien été initialisé et que les pondérations Gemma 3 ont été chargées.

    wget -qO- http://gemma-3-4b-it/v1/models
    

    Réponse indiquant une réussite :

    {"object":"list","data":[{"id":"google/gemma-3-4b-it"}]}
    
  • Vérifiez l'état de l'application : assurez-vous que le serveur d'API est prêt à traiter les requêtes.

    wget -qO- http://gemma-3-4b-it/health
    

    Réponse indiquant une réussite :

    OK
    

Principes de base d'Ollama

Ollama ne permet pas de charger plusieurs modèles en mémoire simultanément. De plus, si vous n'utilisez pas le LLM pendant un certain temps (généralement 30 minutes par défaut), Ollama décharge le modèle actuel de la mémoire.

En raison du comportement décrit précédemment, la solution implémente deux backends Ollama ou plus en fonction de vos besoins et de votre cas d'utilisation. De nombreux développeurs ou utilisateurs peuvent ainsi les utiliser en parallèle sans qu'une seule instance Ollama charge et décharge fréquemment des modèles, ce qui génère une latence inutile.

Vous pouvez ouvrir un terminal sur l'un des pods Ollama à l'aide des commandes suivantes :

kubectl exec -it ollama-chat-random_string -- sh
kubectl exec -it ollama-autocomplete-random_string -- sh

Dans les pods, vous pouvez utiliser la CLI Ollama pour explorer les modèles disponibles et voir lequel est chargé :

  • Dans le pod ollama-chat, vous trouverez un modèle :

    # ollama list
    NAME                     ID              SIZE      MODIFIED
    codegemma:7b-instruct    0c96700aaada    5.0 GB    2 hours ago
    
    # ollama ps
    NAME                     ID              SIZE     PROCESSOR    UNTIL
    codegemma:7b-instruct    0c96700aaada    10 GB    100% GPU     4 minutes from now
    
  • Dans le pod ollama-autocomplete, vous trouverez deux modèles :

    # ollama list
    NAME                     ID              SIZE      MODIFIED
    codegemma:2b             926331004170    1.6 GB    2 hours ago
    codegemma:7b-code        aee9a63c13b9    5.0 GB    2 hours ago
    
    # ollama ps
    NAME                 ID              SIZE      PROCESSOR    UNTIL
    codegemma:7b-code    aee9a63c13b9    7.1 GB    100% GPU     4 minutes from now
    
  • Lorsque Ollama décharge son modèle actuel, la sortie est vide :

    # ollama ps
    NAME    ID    SIZE    PROCESSOR    UNTIL
    

Notez qu'Ollama recharge dynamiquement un modèle lorsque vous envoyez la prochaine demande d'assistance au code, sans aucune intervention manuelle.

Importance de la capacité du GPU

Si vous provisionnez une tranche de GPU de 10 Go, mais que l'espace mémoire utilisé du modèle est (légèrement) supérieur, vous remarquerez qu'une partie du LLM est chargée sur le processeur, comme suit :

# ollama ps
NAME                     ID              SIZE     PROCESSOR         UNTIL
codegemma:7b-instruct    0c96700aaada    10 GB    6%/94% CPU/GPU    29 minutes from now

Ce n'est pas optimal et cela entraîne une latence de réponse plus élevée. Assurez-vous donc de fournir la taille de GPU suggérée dans ce guide.

LLM

Utiliser un autre LLM ou votre LLM préféré avec vLLM

Pour exécuter différentes tailles de Gemma ou tout autre grand modèle de langage (LLM) Open Source avec vLLM sur GDC sous air gap, comme DeepSeek-R1 ou Llama 3.1, vous devez ingérer les nouveaux poids du modèle dans votre environnement et mettre à jour le fichier manifeste de déploiement pour qu'il pointe vers les nouveaux composants.

En fonction des procédures opérationnelles établies pour cette solution, suivez ces étapes pour charger un autre modèle :

  1. Télécharger de nouvelles pondérations de modèle :

    Sur une station de travail ayant accès à Internet, utilisez la CLI Hugging Face pour télécharger les pondérations du modèle de votre choix.

    • Pour Gemma 3 (3-12b-it) :
    hf download google/gemma-3-12b-it
    
    • Pour DeepSeek-R1 (7B Distill) :
    hf download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B
    
    • Pour Llama 3.1 (8B) :
    hf download meta-llama/Meta-Llama-3.1-8B-Instruct
    

    Remarque : Assurez-vous d'avoir accepté les conditions de licence du modèle sur Hugging Face avant de le télécharger.

  2. Remplissez le volume persistant (PVC) :

    Mettez à jour votre model-pvc existant ou créez-en un avec une capacité suffisante pour le nouveau modèle. Utilisez la méthode du pod d'assistance pour transférer les pondérations depuis votre station de travail. Les facteurs de forme plus grands nécessitent beaucoup plus d'espace disque. Assurez-vous que votre PersistentVolumeClaim (PVC) dispose d'une capacité suffisante pour stocker les nouveaux poids.

    • Gemma 3 4B : environ 15,2 Go.
    • Gemma 3 27B : environ 54 Go ou plus.
    • Recommandation : Conservez la recommandation de 500 Gio pour le PVC afin de garantir un nombre élevé d'IOPS (1 500) pour un chargement plus rapide, quelle que soit la taille du modèle.
    # Copy the new model's hub directory to the helper pod
    kubectl cp ~/.cache/huggingface/hub/ osd-dev/model-uploader:/data/
    
  3. Mettez à jour le fichier manifeste de déploiement vLLM :

    Modifiez le fichier YAML de votre déploiement vLLM pour référencer le nouvel ID de modèle. Contrairement à Ollama, qui peut échanger des modèles de manière dynamique, une instance vLLM est dédiée à un seul modèle et doit être mise à jour ou redéployée pour changer de modèle.

    Mettez à jour la section "args" de votre déploiement en fonction du modèle que vous utilisez (ici, deepseek comme exemple) :

    args: [
      "-m", "vllm.entrypoints.openai.api_server",
      "--model", "deepseek-ai/DeepSeek-R1-Distill-Qwen-7B", # Update to new Repo ID
      "--max-model-len", "32768",
      "--enforce-eager" # Recommended for GDC stability
    ]
    
  4. Ajustez les ressources de GPU et de mémoire :

    Les modèles plus volumineux nécessitent plus de VRAM pour les pondérations et le cache KV. Si vous passez d'un modèle 4B à un modèle 8B ou 14B, assurez-vous que vos limites de ressources sont suffisantes pour éviter les plantages "Mémoire insuffisante".

    • Empreinte VRAM : avec une précision de 16 bits, un modèle de 8 milliards de paramètres nécessite environ 16 Go pour les poids uniquement, plus de la mémoire supplémentaire pour le cache PagedAttention de vLLM.
    • Recommandation : Utilisez un GPU A100 complet (nvidia.com/gpu-pod-NVIDIA_A100_80GB_PCIE: 1) pour les modèles de plus de 7 milliards de paramètres afin de garantir des performances optimales et une marge de manœuvre pour le cache KV.
  5. Vérifier le nouveau modèle :

    Une fois le déploiement réconcilié, vérifiez que le nouveau modèle est actif avec l'API interne :

    # Inside a debug-sh pod
    wget -qO- http://gemma-3-4b-it/v1/models
    

    Réponse indiquant une réussite :

    {"object":"list","data":[{"id":"deepseek-ai/DeepSeek-R1-Distill-Qwen-7B"}]}
    

Utiliser un autre LLM avec Ollama

Si vous souhaitez essayer un autre LLM Open Source, tel qu'un modèle des familles Llama 3.2 ou DeepSeek-R1, modifiez cette commande Ollama dans le Dockerfile précédent :

ollama pull gemma3:latest

Par exemple, si vous souhaitez extraire Llama 3.2 avec 3 milliards de paramètres, utilisez la commande suivante :

ollama pull llama3.2:3b

Si vous préférez utiliser DeepSeek-R1 avec 8 milliards de paramètres, utilisez cette commande :

ollama pull deepseek-r1:8b

Vous pouvez également télécharger plusieurs LLM et conteneuriser leurs pondérations de modèle. Ollama pourra alors basculer entre les modèles lorsque vous demanderez des inférences par différents modèles préchargés. Par exemple, vous pouvez ajouter les modèles Gemma et Llama à votre image Docker. Rappelez-vous que dans un environnement isolé, un backend Ollama n'a pas accès à la bibliothèque Ollama pour télécharger un modèle à tout moment.

N'oubliez pas de vérifier et d'accepter les conditions d'utilisation et la licence de chaque modèle avant de les exécuter dans vos applications. La bibliothèque Ollama contient de nombreux LLM. Vous n'aurez besoin d'une connexion Internet que pour télécharger les pondérations du modèle lors de la création de l'image Docker du backend LLM.

Ouvrir l'interface utilisateur Web

Vérifiez si le pod Open WebUI est en cours d'exécution :

kubectl get pods -n NAMESPACE

Résultat attendu :

NAME                             READY   STATUS    RESTARTS   AGE
open-webui-69df4664d-przjl       1/1     Running   0          6d3h

Vérifiez l'adresse IP du service :

kubectl get service -n NAMESPACE

Résultat attendu :

NAME          TYPE            CLUSTER-IP       EXTERNAL-IP      PORT(S)           AGE
open-webui     LoadBalancer   10.201.137.164   136.125.37.224   80:30492/TCP      6d3h

Les sections suivantes expliquent comment utiliser les principales fonctionnalités de l'UI.

Diagramme de l'interface utilisateur WebUI ouverte.

Faire évoluer la solution avec un backend Ollama

Verticalement

  • Allouez une tranche de GPU plus grande à votre LLM devenu un goulot d'étranglement jusqu'à ce que vous utilisiez un GPU complet.
  • Si vous souhaitez utiliser un LLM plus grand pour améliorer la précision des réponses (par exemple, un LLM à 405 milliards de paramètres au lieu d'un LLM à 7 milliards de paramètres), vous aurez peut-être besoin de plusieurs GPU pour l'exécuter correctement.
  • Les modèles qui tiennent dans plusieurs GPU subissent une certaine latence liée à la communication entre les GPU.

Horizontalement

  • Déployez autant de pods Ollama que nécessaire pour atteindre le débit cible sur un LLM donné.
    • Pour ce faire, augmentez le nombre de réplicas dans le fichier YAML de déploiement Ollama correspondant.
  • Le service Kubernetes, de type LoadBalancer, distribuera les demandes d'assistance au code entre les points de terminaison (c'est-à-dire les pods) et renverra leurs réponses respectives via l'adresse IP externe exposée.
  • N'oubliez pas que le plug-in Continue ne pointe que vers une seule adresse IP par fonctionnalité.

Diagramme de l'architecture de scaling des LLM open-weight.

Pour mettre à l'échelle le backend vLLM dans votre environnement GDC isolé, vous pouvez suivre une stratégie similaire à celle utilisée pour Ollama, en vous concentrant à la fois sur l'allocation des ressources matérielles et sur la réplication des pods.

Mettre à l'échelle la solution avec un backend vLLM

Verticalement

  • Mettre à niveau l'allocation de GPU : si le débit d'inférence (jetons/s) devient un goulot d'étranglement, allouez une tranche de GPU plus importante jusqu'à ce que vous utilisiez un GPU NVIDIA A100 complet.
  • Configurations multi-GPU : pour les modèles massifs (par exemple, de 70 milliards à 405 milliards de paramètres) qui ne tiennent pas dans la mémoire d'un seul GPU A100 de 80 Go, vous devez passer à plusieurs GPU à l'aide du parallélisme de tenseur.
  • Considérations concernant la latence : Notez que les modèles s'étendant sur plusieurs GPU peuvent entraîner une légère surcharge liée à la communication entre les GPU (par exemple, la synchronisation NCCL).

Horizontalement

  • Augmenter le débit via les répliques : pour gérer un volume plus élevé de requêtes utilisateur simultanées pour le même modèle, augmentez le nombre replicas dans le fichier YAML de déploiement vLLM.
  • Instances de modèle dédiées : comme vLLM est conçu comme un moteur de diffusion de modèle unique et épingle sa mémoire cache KV lors de l'initialisation, vous devez déployer un ensemble distinct de pods pour chaque LLM différent que vous souhaitez héberger.
  • Équilibrage de charge : le service Kubernetes GDC (type LoadBalancer) distribue automatiquement les requêtes d'inférence entrantes entre tous les points de terminaison de pod vLLM sains associés à ce service.

Dépannage

Erreur Atténuation
ÉCHEC DE L'AUTOTEST FIPS Se produit lorsque des bibliothèques telles que BoringSSL ne disposent pas de signatures d'intégrité. Corriger en définissant BORINGSSL_FIPS=0 et en utilisant les images vLLM officielles
Chargement de poids bloqué Vérifiez si les IOPS sont limitées sur les petits PVC. Un volume de 500 Gio est requis pour l'initialisation du modèle de performances.
Connexion refusée Vérifiez que le PNP autorise explicitement le targetPort (8000/8080). Les pare-feu GDC n'accordent pas automatiquement l'accès aux ports de backend pour les adresses IP virtuelles de l'équilibreur de charge.