Déployer une application Ray Serve avec un modèle Stable Diffusion sur Google Kubernetes Engine (GKE)

Ce guide fournit un exemple de déploiement et de diffusion d'un modèle Stable Diffusion sur Google Kubernetes Engine (GKE) à l'aide de Ray Serve et du module complémentaire Ray Operator comme exemple d'implémentation.

À propos de Ray et Ray Serve

Ray est un framework de calcul évolutif Open Source pour les applications d'IA/ML. Ray Serve est une bibliothèque de diffusion de modèles pour Ray, utilisée pour le scaling et la diffusion de modèles dans un environnement distribué. Pour en savoir plus, consultez la section Ray Serve dans la documentation Ray.

Vous pouvez utiliser une ressource RayCluster ou RayService pour déployer vos applications Ray Serve. Vous devez utiliser une ressource RayService en production pour les raisons suivantes :

  • Mises à jour sur place pour les applications RayService
  • Mise à niveau sans temps d'arrêt pour les ressources RayCluster
  • Applications Ray Serve à disponibilité élevée

Objectifs

Ce guide est destiné aux clients d'IA générative, aux utilisateurs nouveaux ou existants de GKE, aux ingénieurs en ML, aux ingénieurs MLOps (DevOps) ou aux administrateurs de plate-forme qui s'intéressent à l'utilisation des fonctionnalités d'orchestration de conteneurs Kubernetes pour diffuser des modèles utilisant Ray.

  • Créer un cluster GKE avec un pool de nœuds TPU.
  • Créez un cluster Ray à l'aide de la ressource personnalisée RayCluster.
  • Exécutez une application Ray Serve.
  • Déployer une ressource personnalisée RayService.

Coûts

Dans ce document, vous utilisez les composants facturables de Google Cloudsuivants :

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

Les nouveaux utilisateurs de Google Cloud peuvent bénéficier d'un essai sans frais.

Une fois que vous avez terminé les tâches décrites dans ce document, supprimez les ressources que vous avez créées pour éviter que des frais vous soient facturés. Pour en savoir plus, consultez la section Effectuer un nettoyage.

Avant de commencer

Cloud Shell est préinstallé avec les logiciels dont vous avez besoin dans ce tutoriel, y compris kubectl et gcloud CLI. Si vous n'utilisez pas Cloud Shell, vous devez installer gcloud CLI.

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Install the Google Cloud CLI.

  3. Si vous utilisez un fournisseur d'identité (IdP) externe, vous devez d'abord vous connecter à la gcloud CLI avec votre identité fédérée.

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

    gcloud init
  5. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the GKE API:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable container.googleapis.com
  8. Install the Google Cloud CLI.

  9. Si vous utilisez un fournisseur d'identité (IdP) externe, vous devez d'abord vous connecter à la gcloud CLI avec votre identité fédérée.

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

    gcloud init
  11. Create or select a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.
    • Create a Google Cloud project:

      gcloud projects create PROJECT_ID

      Replace PROJECT_ID with a name for the Google Cloud project you are creating.

    • Select the Google Cloud project that you created:

      gcloud config set project PROJECT_ID

      Replace PROJECT_ID with your Google Cloud project name.

  12. Verify that billing is enabled for your Google Cloud project.

  13. Enable the GKE API:

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    gcloud services enable container.googleapis.com
  14. Grant roles to your user account. Run the following command once for each of the following IAM roles: roles/container.clusterAdmin, roles/container.admin

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

    Replace the following:

    • PROJECT_ID: Your project ID.
    • USER_IDENTIFIER: The identifier for your user account. For example, myemail@example.com.
    • ROLE: The IAM role that you grant to your user account.
  15. Préparer votre environnement

    Pour préparer votre environnement, procédez comme suit :

    1. Lancez une session Cloud Shell depuis la console Google Cloud en cliquant sur Icône d'activation Cloud Shell Activer Cloud Shell dans la consoleGoogle Cloud . Une session s'ouvre dans le volet inférieur de la console Google Cloud .

    2. Définissez les variables d'environnement :

      export PROJECT_ID=PROJECT_ID
      export CLUSTER_NAME=rayserve-cluster
      export COMPUTE_REGION=us-central1
      export COMPUTE_ZONE=us-central1-c
      export CLUSTER_VERSION=CLUSTER_VERSION
      export TUTORIAL_HOME=`pwd`
      

      Remplacez les éléments suivants :

      • PROJECT_ID : ID de votre projet Google Cloud.
      • CLUSTER_VERSION : version de GKE à utiliser. Doit être 1.30.1 ou une version ultérieure.
    3. Clonez le dépôt GitHub.

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      
    4. Accédez au répertoire de travail :

      cd kubernetes-engine-samples/ai-ml/gke-ray/rayserve/stable-diffusion
      
    5. Créez un environnement virtuel Python :

      venv

      python -m venv myenv && \
      source myenv/bin/activate
      

      Conda

      1. Installez Conda.

      2. Exécutez les commandes suivantes :

        conda create -c conda-forge python=3.9.19 -n myenv && \
        conda activate myenv
        

      Lorsque vous déployez une application Serve avec serve run, Ray s'attend à ce que la version Python du client local corresponde à celle utilisée dans le cluster Ray. L'image rayproject/ray:2.37.0 utilise Python 3.9. Si vous exécutez une autre version du client, sélectionnez l'image Ray appropriée.

    6. Installez les dépendances requises pour exécuter l'application Serve :

      pip install ray[serve]==2.37.0
      pip install torch
      pip install requests
      

    Créer un cluster GKE avec un pool de nœuds GPU.

    Créez un cluster GKE Autopilot ou Standard avec un pool de nœuds GPU :

    Autopilot

    Créez un cluster Autopilot :

    gcloud container clusters create-auto ${CLUSTER_NAME}  \
        --enable-ray-operator \
        --cluster-version=${CLUSTER_VERSION} \
        --location=${COMPUTE_REGION}
    

    Standard

    1. Créez un cluster standard :

      gcloud container clusters create ${CLUSTER_NAME} \
          --addons=RayOperator \
          --cluster-version=${CLUSTER_VERSION}  \
          --machine-type=c3d-standard-8 \
          --location=${COMPUTE_ZONE} \
          --num-nodes=1
      
    2. Créez un pool de nœuds GPU :

      gcloud container node-pools create gpu-pool \
          --cluster=${CLUSTER_NAME} \
          --machine-type=g2-standard-8 \
          --location=${COMPUTE_ZONE} \
          --num-nodes=1 \
          --accelerator type=nvidia-l4,count=1,gpu-driver-version=latest
      

    Déployer une ressource RayCluster

    Pour déployer une ressource RayCluster :

    1. Examinez le fichier manifeste suivant :

      apiVersion: ray.io/v1
      kind: RayCluster
      metadata:
        name: stable-diffusion-cluster
      spec:
        rayVersion: '2.37.0'
        headGroupSpec:
          rayStartParams:
            dashboard-host: '0.0.0.0'
          template:
            metadata:
            spec:
              containers:
              - name: ray-head
                image: rayproject/ray:2.37.0
                ports:
                - containerPort: 6379
                  name: gcs
                - containerPort: 8265
                  name: dashboard
                - containerPort: 10001
                  name: client
                - containerPort: 8000
                  name: serve
                resources:
                  limits:
                    cpu: "2"
                    ephemeral-storage: "15Gi"
                    memory: "8Gi"
                  requests:
                    cpu: "2"
                    ephemeral-storage: "15Gi"
                    memory: "8Gi"
              nodeSelector:
                cloud.google.com/machine-family: c3d
        workerGroupSpecs:
        - replicas: 1
          minReplicas: 1
          maxReplicas: 4
          groupName: gpu-group
          rayStartParams: {}
          template:
            spec:
              containers:
              - name: ray-worker
                image: rayproject/ray:2.37.0-gpu
                resources:
                  limits:
                    cpu: 4
                    memory: "16Gi"
                    nvidia.com/gpu: 1
                  requests:
                    cpu: 3
                    memory: "16Gi"
                    nvidia.com/gpu: 1
              nodeSelector:
                cloud.google.com/gke-accelerator: nvidia-l4

      Ce fichier manifeste décrit une ressource RayCluster.

    2. Appliquez le fichier manifeste à votre cluster :

      kubectl apply -f ray-cluster.yaml
      
    3. Vérifiez que la ressource RayCluster est prête :

      kubectl get raycluster
      

      Le résultat ressemble à ce qui suit :

      NAME                       DESIRED WORKERS   AVAILABLE WORKERS   CPUS   MEMORY   GPUS   STATUS   AGE
      stable-diffusion-cluster   2                 2                   6      20Gi     0      ready    33s
      

      Dans ce résultat, ready dans la colonne STATUS indique que la ressource RayCluster est prête.

    Se connecter à la ressource RayCluster

    Pour vous connecter à la ressource RayCluster :

    1. Vérifiez que GKE a créé le service RayCluster :

      kubectl get svc stable-diffusion-cluster-head-svc
      

      Le résultat ressemble à ce qui suit :

      NAME                             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                                AGE
      pytorch-mnist-cluster-head-svc   ClusterIP   34.118.238.247   <none>        10001/TCP,8265/TCP,6379/TCP,8080/TCP   109s
      
    2. Établissez des sessions de transfert de port vers le nœud principal Ray :

      kubectl port-forward svc/stable-diffusion-cluster-head-svc 8265:8265 2>&1 >/dev/null &
      kubectl port-forward svc/stable-diffusion-cluster-head-svc 10001:10001 2>&1 >/dev/null &
      
    3. Vérifiez que le client Ray peut se connecter au cluster Ray à l'aide de localhost :

      ray list nodes --address http://localhost:8265
      

      Le résultat ressemble à ce qui suit :

      ======== List: 2024-06-19 15:15:15.707336 ========
      Stats:
      ------------------------------
      Total: 3
      
      Table:
      ------------------------------
          NODE_ID                                                   NODE_IP     IS_HEAD_NODE    STATE    NODE_NAME    RESOURCES_TOTAL                 LABELS
      0  1d07447d7d124db641052a3443ed882f913510dbe866719ac36667d2  10.28.1.21  False           ALIVE    10.28.1.21   CPU: 2.0                        ray.io/node_id: 1d07447d7d124db641052a3443ed882f913510dbe866719ac36667d2
      # Several lines of output omitted
      

    Exécuter une application Ray Serve

    Pour exécuter une application Ray Serve, procédez comme suit :

    1. Exécutez l'application Stable Diffusion Ray Serve :

      serve run stable_diffusion:entrypoint --working-dir=. --runtime-env-json='{"pip": ["torch", "torchvision", "diffusers==0.12.1", "huggingface_hub==0.25.2", "transformers", "fastapi==0.113.0"], "excludes": ["myenv"]}' --address ray://localhost:10001
      
      

      Le résultat ressemble à ce qui suit :

      2024-06-19 18:20:58,444 INFO scripts.py:499 -- Running import path: 'stable_diffusion:entrypoint'.
      2024-06-19 18:20:59,730 INFO packaging.py:530 -- Creating a file package for local directory '.'.
      2024-06-19 18:21:04,833 INFO handle.py:126 -- Created DeploymentHandle 'hyil6u9f' for Deployment(name='StableDiffusionV2', app='default').
      2024-06-19 18:21:04,834 INFO handle.py:126 -- Created DeploymentHandle 'xo25rl4k' for Deployment(name='StableDiffusionV2', app='default').
      2024-06-19 18:21:04,836 INFO handle.py:126 -- Created DeploymentHandle '57x9u4fp' for Deployment(name='APIIngress', app='default').
      2024-06-19 18:21:04,836 INFO handle.py:126 -- Created DeploymentHandle 'xr6kt85t' for Deployment(name='StableDiffusionV2', app='default').
      2024-06-19 18:21:04,836 INFO handle.py:126 -- Created DeploymentHandle 'g54qagbz' for Deployment(name='APIIngress', app='default').
      2024-06-19 18:21:19,139 INFO handle.py:126 -- Created DeploymentHandle 'iwuz00mv' for Deployment(name='APIIngress', app='default').
      2024-06-19 18:21:19,139 INFO api.py:583 -- Deployed app 'default' successfully.
      
    2. Établissez une session de transfert de port vers le port Ray Serve (8000) :

      kubectl port-forward svc/stable-diffusion-cluster-head-svc 8000:8000 2>&1 >/dev/null &
      
    3. Exécutez le script Python :

      python generate_image.py
      

      Le script génère une image dans un fichier nommé output.png. Le résultat ressemble à ce qui suit :

      Plage au coucher du soleil. Image générée par Stable Diffusion.

    Déployer un RayService

    La ressource personnalisée RayService gère le cycle de vie d'une ressource RayCluster et d'une application Ray Serve.

    Pour en savoir plus sur RayService, consultez Déployer des applications Ray Serve et le Guide de production dans la documentation Ray.

    Pour déployer une ressource RayService, procédez comme suit :

    1. Examinez le fichier manifeste suivant :

      apiVersion: ray.io/v1
      kind: RayService
      metadata:
        name: stable-diffusion
      spec:
        serveConfigV2: |
          applications:
            - name: stable_diffusion
              import_path: ai-ml.gke-ray.rayserve.stable-diffusion.stable_diffusion:entrypoint
              runtime_env:
                working_dir: "https://github.com/GoogleCloudPlatform/kubernetes-engine-samples/archive/main.zip"
                pip: ["diffusers==0.12.1", "torch", "torchvision", "huggingface_hub==0.25.2", "transformers"]
        rayClusterConfig:
          rayVersion: '2.37.0'
          headGroupSpec:
            rayStartParams:
              dashboard-host: '0.0.0.0'
            template:
              spec:
                containers:
                - name: ray-head
                  image:  rayproject/ray:2.37.0
                  ports:
                  - containerPort: 6379
                    name: gcs
                  - containerPort: 8265
                    name: dashboard
                  - containerPort: 10001
                    name: client
                  - containerPort: 8000
                    name: serve
                  resources:
                    limits:
                      cpu: "2"
                      ephemeral-storage: "15Gi"
                      memory: "8Gi"
                    requests:
                      cpu: "2"
                      ephemeral-storage: "15Gi"
                      memory: "8Gi"
                nodeSelector:
                  cloud.google.com/machine-family: c3d
          workerGroupSpecs:
          - replicas: 1
            minReplicas: 1
            maxReplicas: 4
            groupName: gpu-group
            rayStartParams: {}
            template:
              spec:
                containers:
                - name: ray-worker
                  image: rayproject/ray:2.37.0-gpu
                  resources:
                    limits:
                      cpu: 4
                      memory: "16Gi"
                      nvidia.com/gpu: 1
                    requests:
                      cpu: 3
                      memory: "16Gi"
                      nvidia.com/gpu: 1
                nodeSelector:
                  cloud.google.com/gke-accelerator: nvidia-l4

      Ce fichier manifeste décrit une ressource personnalisée RayService.

    2. Appliquez le fichier manifeste à votre cluster :

      kubectl apply -f ray-service.yaml
      
    3. Vérifiez que le service est prêt :

      kubectl get svc stable-diffusion-serve-svc
      

      Le résultat ressemble à ce qui suit :

      NAME                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
      
      stable-diffusion-serve-svc   ClusterIP   34.118.236.0   <none>        8000/TCP   31m
      
    4. Configurez le transfert de port vers le service Ray Serve :

      kubectl port-forward svc/stable-diffusion-serve-svc 8000:8000 2>&1 >/dev/null &
      
    5. Exécutez le script Python de la section précédente :

      python generate_image.py
      

      Le script génère une image semblable à celle générée dans la section précédente.

    Observer vos charges de travail Ray

    Pour afficher les détails de vos RayJobs, vous pouvez accéder à la section Kubernetes Engine > AI/ML > Jobs dans la console Google Cloud .

    Afficher les RayJobs dans la console Google Cloud

    Effectuer un nettoyage

    Supprimer le projet

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Supprimer des ressources individuelles

    Pour supprimer le cluster, saisissez ce qui suit :

    gcloud container clusters delete ${CLUSTER_NAME}
    

    Étape suivante

    • Découvrez des architectures de référence, des schémas et des bonnes pratiques concernant Google Cloud. Consultez notre Cloud Architecture Center.