Utiliser vLLM sur GKE pour exécuter l'inférence avec DeepSeek-V3.1-Base

Ce tutoriel vous explique comment déployer et diffuser un modèle de langage DeepSeek-V3.1-Base à l'aide du framework vLLM. Vous déployez ce modèle sur un cluster autopilot Google Kubernetes Engine (GKE) Enterprise et consommez une seule machine virtuelle A4 (VM) dotée de huit GPU B200.

Ce tutoriel est destiné aux ingénieurs en machine learning (ML), aux administrateurs et opérateurs de plate-forme, ainsi qu'aux spécialistes des données et de l'IA qui souhaitent utiliser les fonctionnalités d'orchestration de conteneurs Kubernetes pour gérer les charges de travail d'inférence.

Objectifs

  1. Accédez à DeepSeek-V3.1-Base à l'aide de Hugging Face.
  2. Préparez votre environnement.
  3. Créer un cluster GKE en mode Autopilot
  4. Créez un secret Kubernetes pour les identifiants Hugging Face.
  5. créer un bucket Cloud Storage ;
  6. Téléchargez le modèle dans votre bucket Cloud Storage.
  7. Déployez un conteneur vLLM sur votre cluster GKE.
  8. Interagissez avec DeepSeek-V3.1-Base à l'aide de curl.
  9. Effectuer un nettoyage.

Coûts

Ce tutoriel fait appel à des composants payants de Google Cloud, y compris :

Vous pouvez obtenir une estimation des coûts en fonction de votre utilisation prévue à l'aide du simulateur de coût.

Avant de commencer

  1. Installez la Google Cloud CLI.

  2. Configurez la gcloud CLI afin d'utiliser votre identité fédérée.

    Pour en savoir plus, consultez Se connecter à la gcloud CLI avec votre identité fédérée.

  3. Pour initialiser la gcloud CLI, exécutez la commande suivante :

    gcloud init
  4. Créez ou sélectionnez un projet Google Cloud .

    Rôles requis pour sélectionner ou créer un projet

    • Sélectionnez un projet : la sélection d'un projet ne nécessite pas de rôle IAM spécifique. Vous pouvez sélectionner n'importe quel projet pour lequel un rôle vous a été attribué.
    • Créer un projet : pour créer un projet, vous devez disposer du rôle Créateur de projet (roles/resourcemanager.projectCreator), qui contient l'autorisation resourcemanager.projects.create. Découvrez comment attribuer des rôles.
    • Créez un projet Google Cloud  :

      gcloud projects create PROJECT_ID

      Remplacez PROJECT_ID par le nom du projet Google Cloud que vous créez.

    • Sélectionnez le projet Google Cloud que vous avez créé :

      gcloud config set project PROJECT_ID

      Remplacez PROJECT_ID par le nom de votre projet Google Cloud .

  5. Vérifiez que la facturation est activée pour votre projet Google Cloud .

  6. Activez l'API requise :

    Rôles requis pour activer les API

    Pour activer les API, vous devez disposer de l'autorisation serviceusage.services.enable. Si vous avez créé le projet, vous disposez probablement déjà de cette autorisation grâce au rôle Propriétaire (roles/owner). Sinon, vous pouvez obtenir cette autorisation grâce au rôle Administrateur Service Usage (roles/serviceusage.serviceUsageAdmin). Découvrez comment attribuer des rôles.

    gcloud services enable container.googleapis.com
  7. Attribuez des rôles à votre compte utilisateur. Exécutez la commande suivante une fois pour chacun des rôles IAM suivants : roles/container.admin

    gcloud projects add-iam-policy-binding PROJECT_ID --member="user:USER_IDENTIFIER" --role=ROLE

    Remplacez les éléments suivants :

  8. Connectez-vous à votre compte Hugging Face ou créez-en un.

Accéder à DeepSeek à l'aide de Hugging Face

Pour utiliser Hugging Face afin d'accéder à DeepSeek, procédez comme suit :

  1. Connectez-vous à Hugging Face et explorez le modèle DeepSeek-V3.1-Base.
  2. Créez un jeton d'accès read Hugging Face.
  3. Copiez et enregistrez la valeur du jeton read access. Vous en aurez besoin dans la suite de ce tutoriel.

Préparer votre environnement

Pour préparer votre environnement, définissez les variables d'environnement par défaut :

export PROJECT_ID="YOUR_PROJECT_ID"
export RESERVATION_URL="YOUR_RESERVATION_NAME"
export REGION="YOUR_REGION"
export CLUSTER_NAME="YOUR_CLUSTER_NAME"
export GCS_BUCKET="YOUR_GCS_BUCKET"
export HUGGING_FACE_TOKEN="YOUR_HF_TOKEN"
export NETWORK="YOUR_NETWORK_NAME"
export SUBNETWORK="YOUR_SUBNETWORK_NAME"
export PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format="value(projectNumber)")

gcloud config set project "${PROJECT_ID}"
gcloud config set billing/quota_project "${PROJECT_ID}"

Remplacez les éléments suivants :

  • YOUR_PROJECT_ID : ID du Google Cloud projet dans lequel vous souhaitez créer le cluster GKE.

  • YOUR_RESERVATION_NAME : URL de la réservation que vous souhaitez utiliser pour créer votre cluster GKE. En fonction du projet dans lequel la réservation existe, spécifiez l'une des valeurs suivantes :

    • La réservation existe dans votre projet : RESERVATION_NAME

    • La réservation existe dans un autre projet et votre projet peut l'utiliser : projects/RESERVATION_PROJECT_ID/reservations/RESERVATION_NAME

  • YOUR_REGION : région dans laquelle vous souhaitez créer votre cluster GKE. Vous ne pouvez créer le cluster que dans la région où se trouve votre réservation.

  • YOUR_CLUSTER_NAME : nom du cluster GKE à créer.

  • YOUR_GCS_BUCKET : nom du bucket Cloud Storage à partir duquel vous téléchargez le modèle.

  • YOUR_HF_TOKEN : jeton d'accès Hugging Face que vous avez créé dans la section précédente.

  • YOUR_NETWORK_NAME : réseau utilisé par le cluster GKE. Spécifiez une des valeurs suivantes :

    • Si vous avez créé un réseau personnalisé, spécifiez son nom.

    • Sinon, spécifiez default.

  • YOUR_SUBNETWORK_NAME : sous-réseau utilisé par le cluster GKE. Spécifiez une des valeurs suivantes :

    • Si vous avez créé un sous-réseau personnalisé, spécifiez son nom. Vous ne pouvez spécifier qu'un sous-réseau situé dans la même région que la réservation.

    • Sinon, spécifiez default.

Créer un cluster GKE en mode Autopilot

Pour créer un cluster GKE en mode Autopilot, exécutez la commande suivante :

gcloud container clusters create-auto $CLUSTER_NAME \
    --project=$PROJECT_ID \
    --region=$REGION \
    --release-channel=rapid \
    --network=$NETWORK \
    --subnetwork=$SUBNETWORK

La création du cluster GKE peut prendre un certain temps. Pour vérifier que Google Cloud a terminé de créer votre cluster, accédez à Clusters Kubernetes dans la console Google Cloud .

Créer un secret Kubernetes pour les identifiants Hugging Face

Pour créer un secret Kubernetes pour les identifiants Hugging Face, procédez comme suit :

  1. Configurez kubectl pour communiquer avec votre cluster GKE :

    gcloud container clusters get-credentials $CLUSTER_NAME \
        --location=$REGION
  2. Créez un secret Kubernetes pour stocker votre jeton Hugging Face :

    kubectl create secret generic hf-secret \
        --from-literal=hf_token=${HUGGING_FACE_TOKEN} \
        --dry-run=client -o yaml | kubectl apply -f -

Créer un bucket Cloud Storage

Si vous souhaitez utiliser un nouveau bucket pour stocker le modèle, exécutez la commande suivante :

gcloud storage buckets create gs://$GCS_BUCKET --location=$REGION --uniform-bucket-level-access

Accordez les autorisations write sur le bucket Cloud Storage au compte de service par défaut :

gcloud storage buckets add-iam-policy-binding gs://$GCS_BUCKET \
    --member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID.svc.id.goog/subject/ns/default/sa/default" \
    --role="roles/storage.objectAdmin"

Si vous souhaitez utiliser un bucket Cloud Storage existant, vous pouvez ignorer cette étape. Toutefois, vous devez vous assurer que votre bucket se trouve dans la même région que votre cluster et que le compte de service dispose des autorisations write requises.

Télécharger le modèle dans votre bucket Cloud Storage

  1. Créez un fichier deepseek-download-job.yaml :

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: deepseek-download-job
      namespace: default
    spec:
      template:
        metadata:
          labels:
            app: deepseek-oss-downloader
        spec:
          restartPolicy: OnFailure
          containers:
          - name: downloader
            image: google/cloud-sdk:slim
            resources:
              requests:
                cpu: "8"
                memory: "32Gi"
              limits:
                cpu: "8"
                memory: "32Gi"
            env:
            - name: HUGGING_FACE_HUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: hf-secret
                  key: hf_token
            - name: HF_XET_HIGH_PERFORMANCE
              value: "0"
            - name: PIP_BREAK_SYSTEM_PACKAGES
              value: "1"
            command: ["/bin/sh", "-c"]
            args:
            - |
              set -e
              echo "Installing Hugging Face Hub CLI..."
              pip install -U "huggingface_hub[cli]"
    
              LOCAL_DIR="/mnt/model-download/deepseek-v3-1"
              mkdir -p "$LOCAL_DIR"
    
              echo "Downloading model from HF to local SSD using parallel workers..."
              hf download deepseek-ai/DeepSeek-V3.1-Base \
                --token "$HUGGING_FACE_HUB_TOKEN" \
                --local-dir "$LOCAL_DIR" \
                --max-workers 8
    
              DOWNLOAD_STATUS=$?
    
              if [ $DOWNLOAD_STATUS -ne 0 ]; then
                echo "ERROR: Model download failed with exit code $DOWNLOAD_STATUS"
                exit $DOWNLOAD_STATUS
              fi
    
              echo "Download to SSD complete. Syncing to GCS..."
              gcloud storage rsync "$LOCAL_DIR" "gs://$GCS_BUCKET/deepseek-v3-1" --recursive
    
              echo "Process successfully completed!"
            volumeMounts:
            - mountPath: /mnt/model-download
              name: download-storage
          volumes:
          - name: download-storage
            ephemeral:
              volumeClaimTemplate:
                spec:
                  accessModes: [ "ReadWriteOnce" ]
                  storageClassName: premium-rwo
                  resources:
                    requests:
                      storage: 800Gi
  2. Appliquez le fichier manifeste deepseek-download-job.yaml pour initialiser le job de téléchargement :

    envsubst '$GCS_BUCKET' < deepseek-download-job.yaml | kubectl apply -f -
  3. Pour afficher l'état d'achèvement, exécutez la commande suivante :

    kubectl wait \
        --for=condition=Complete \
        --timeout=7200s job/deepseek-download-job

    L'indicateur --timeout spécifie la durée pendant laquelle la commande surveille le job avant d'expirer.

    La ressource de job télécharge les pondérations du modèle DeepSeek-V3.1-Base depuis Hugging Face vers votre bucket Google Cloud Storage à l'aide du volume SSD. Le téléchargement prend environ 40 minutes. Une fois le téléchargement terminé, passez à la section suivante pour lancer le déploiement du modèle.

  4. Pour supprimer le job, exécutez la commande suivante :

    kubectl delete job deepseek-download-job

Déployer un conteneur vLLM sur votre cluster GKE

Une fois le modèle téléchargé dans votre bucket Cloud Storage, déployez un conteneur vLLM sur votre cluster GKE en procédant comme suit :

  1. Créez un fichier vllm-deepseek3-1-base.yaml avec le déploiement vLLM de votre choix :

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: deepseek3-1-deploy
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: deepseek
      template:
        metadata:
          labels:
            app: deepseek
            ai.gke.io/model: deepseek-v3-1-base
            ai.gke.io/inference-server: vllm
            examples.ai.gke.io/source: user-guide
          annotations:
            gke-gcsfuse/volumes: "true"
        spec:
          containers:
          - name: vllm-inference
            image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:20250819_0916_RC01
            resources:
              requests:
                cpu: "10"
                memory: "1000Gi"
                ephemeral-storage: "1Ti"
                nvidia.com/gpu: "8"
              limits:
                cpu: "10"
                memory: "1000Gi"
                ephemeral-storage: "1Ti"
                nvidia.com/gpu: "8"
            command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
            args:
            - --model=/mnt/gcs/deepseek-v3-1
            - --tensor-parallel-size=8
            - --host=0.0.0.0
            - --port=8000
            - --max-model-len=8192
            - --max-num-seqs=4
            volumeMounts:
            - mountPath: /dev/shm
              name: dshm
            - mountPath: /mnt/gcs
              name: gcs-bucket-volume
              readOnly: true
            livenessProbe:
              httpGet:
                path: /health
                port: 8000
              initialDelaySeconds: 1800
              periodSeconds: 10
            readinessProbe:
              httpGet:
                path: /health
                port: 8000
              initialDelaySeconds: 1800
              periodSeconds: 5
          volumes:
          - name: dshm
            emptyDir:
                medium: Memory
          - name: gcs-bucket-volume
            csi:
              driver: gcsfuse.csi.storage.gke.io
              volumeAttributes:
                bucketName: $GCS_BUCKET
                mountOptions: "implicit-dirs,file-cache:max-size-mb:-1,file-cache:enable-parallel-downloads:true,file-cache:max-parallel-downloads:32,file-cache:parallel-downloads-per-file:8,file-cache:download-chunk-size-mb:16"
          nodeSelector:
            cloud.google.com/gke-accelerator: nvidia-b200
            cloud.google.com/reservation-name: $RESERVATION_URL
            cloud.google.com/reservation-affinity: "specific"
            cloud.google.com/gke-gpu-driver-version: latest
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: deepseek-service
    spec:
      selector:
        app: deepseek
      type: ClusterIP
      ports:
        - protocol: TCP
          port: 8000
          targetPort: 8000
    ---
    apiVersion: monitoring.googleapis.com/v1
    kind: PodMonitoring
    metadata:
      name: deepseek-monitoring
    spec:
      selector:
        matchLabels:
          app: deepseek
      endpoints:
      - port: 8000
        path: /metrics
        interval: 30s
  2. Appliquez le fichier vllm-deepseek3-1-base.yaml à votre cluster GKE :

    envsubst < vllm-deepseek3-1-base.yaml | kubectl apply -f -
  3. Pour afficher l'état d'achèvement, exécutez la commande suivante :

    kubectl wait \
      --for=condition=Available \
      --timeout=7200s deployment/deepseek3-1-deploy

    L'indicateur --timeout permet à la commande de surveiller le déploiement pendant la période spécifiée.

Interagir avec DeepSeek-V3.1-Base à l'aide de curl

Pour vérifier le modèle DeepSeek-V3.1-Base que vous avez déployé, procédez comme suit :

  1. Configurez le transfert de port vers DeepSeek-V3.1-Base :

    kubectl port-forward service/deepseek-service 8000:8000
  2. Ouvrez une nouvelle fenêtre de terminal. Vous pouvez ensuite discuter avec votre modèle à l'aide de curl :

    curl http://127.0.0.1:8000/v1/chat/completions \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{
      "model": "deepseek-ai/DeepSeek-V3.1-Base",
      "messages": [
        {
          "role": "user",
          "content": "Describe how generative AI works in one short and easy to understand sentence"
        }
      ],
    "stream":false
    }' | jq .
  3. Le résultat renvoyé ressemble à ceci :

    {
      "id": "chatcmpl-1a47172070544a5d83199ed5548befca",
      "object": "chat.completion",
      "created": 1755891024,
      "model": "deepseek-ai/DeepSeek-V3.1-Base",
      "choices": [
        {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": "\nGenerative AI uses patterns from existing data to create new, similar content, like text, images, or music.\n",
            "refusal": null,
            "annotations": null,
            "audio": null,
            "function_call": null,
            "tool_calls": [],
            "reasoning_content": null
          },
          "logprobs": null,
          "finish_reason": "stop",
          "stop_reason": null
        }
      ],
      "service_tier": null,
      "system_fingerprint": null,
      "usage": {
        "prompt_tokens": 17,
        "total_tokens": 42,
        "completion_tokens": 25,
        "prompt_tokens_details": null
      },
      "prompt_logprobs": null,
      "kv_transfer_params": null
    }
    

Observer les performances du modèle

Si vous souhaitez observer les performances de votre modèle, vous pouvez utiliser l'intégration du tableau de bord vLLM dans Cloud Monitoring. Ce tableau de bord vous permet d'afficher les métriques de performances critiques de votre modèle, comme le débit de jetons, la latence réseau et les taux d'erreur. Pour en savoir plus, consultez vLLM dans la documentation de Monitoring.

Effectuer un nettoyage

Pour éviter que les ressources utilisées lors de ce tutoriel soient facturées sur votre compte Google Cloud, supprimez le projet contenant les ressources, ou conservez le projet et supprimez les ressources individuelles.

Supprimer les ressources

Une fois le tutoriel terminé, supprimez les ressources dont vous n'avez plus besoin :

  1. Pour supprimer le déploiement et le service définis dans le fichier vllm-deepseek3-1-base.yaml, ainsi que le secret Kubernetes du cluster GKE, exécutez la commande suivante :

    envsubst < vllm-deepseek3-1-base.yaml | kubectl delete -f -
    kubectl delete secret hf-secret
  2. Pour supprimer votre bucket Cloud Storage, exécutez la commande suivante :

    gcloud storage rm --recursive gs://$GCS_BUCKET
  3. Pour supprimer votre cluster GKE :

    gcloud container clusters delete $CLUSTER_NAME \
        --region=$REGION \
        --quiet

Supprimer votre projet

Supprimer un projet Google Cloud  :

gcloud projects delete PROJECT_ID

Étapes suivantes