Ray Serve-Anwendung mit einem Stable Diffusion-Modell in Google Kubernetes Engine (GKE) bereitstellen

Dieser Leitfaden enthält ein Beispiel für die Bereitstellung eines Stable Diffusion-Modells in Google Kubernetes Engine (GKE) mithilfe von Ray-Serve und dem Ray Operator-Add-on als Beispielimplementierung.

Ray und Ray Serve

Ray ist ein skalierbares Open-Source-Computing-Framework für KI/ML-Anwendungen. Ray Serve ist eine Modellbereitstellungsbibliothek für Ray, die zur Skalierung und Bereitstellung von Modellen in einer verteilten Umgebung verwendet wird. Weitere Informationen finden Sie unter Ray Serve in der Ray-Dokumentation.

Sie können eine RayCluster- oder RayService-Ressource verwenden, um Ihre Ray Serve-Anwendungen bereitzustellen. Aus folgenden Gründen sollten Sie in der Produktion eine RayService-Ressource verwenden:

  • Direkte Aktualisierungen für RayService-Anwendungen
  • RayCluster-Ressourcen ohne Ausfallzeiten aktualisieren
  • Hochverfügbare Ray Serve-Anwendungen

Ziele

Dieser Leitfaden richtet sich an Kunden von generativer KI, neue oder bestehende Nutzer von GKE, ML-Entwickler, MLOps-Entwickler (DevOps) oder Plattformadministratoren, die daran interessiert sind, Funktionen zur Kubernetes-Containerorchestrierung für die Bereitstellung von Modellen mit Ray zu nutzen.

  • GKE-Cluster mit einem GPU-Knotenpool erstellen
  • Ray-Cluster mithilfe der benutzerdefinierten RayCluster-Ressource erstellen
  • Ray Serve-Anwendung ausführen
  • Benutzerdefinierte RayService-Ressource bereitstellen

Kosten

In diesem Dokument verwenden Sie die folgenden kostenpflichtigen Komponenten von Google Cloud:

Mit dem Preisrechner können Sie eine Kostenschätzung für Ihre voraussichtliche Nutzung vornehmen.

Neuen Nutzern von Google Cloud steht möglicherweise eine kostenlose Testversion zur Verfügung.

Nach Abschluss der in diesem Dokument beschriebenen Aufgaben können Sie weitere Kosten vermeiden, indem Sie die erstellten Ressourcen löschen. Weitere Informationen finden Sie unter Bereinigen.

Hinweise

Die Software, die Sie für diese Anleitung benötigen, ist in Cloud Shell vorinstalliert, einschließlich kubectl und der gcloud CLI. Wenn Sie Cloud Shell nicht verwenden, müssen Sie die gcloud CLI installieren.

  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. Wenn Sie einen externen Identitätsanbieter (IdP) verwenden, müssen Sie sich zuerst mit Ihrer föderierten Identität in der gcloud CLI anmelden.

  4. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    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 (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. Wenn Sie einen externen Identitätsanbieter (IdP) verwenden, müssen Sie sich zuerst mit Ihrer föderierten Identität in der gcloud CLI anmelden.

  10. Führen Sie folgenden Befehl aus, um die gcloud CLI zu initialisieren:

    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 (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. Umgebung vorbereiten

    So richten Sie Ihre Umgebung ein:

    1. Starten Sie eine Cloud Shell-Sitzung über die Google Cloud Console. Klicken Sie dazu in der Google Cloud Console auf Symbol für die Cloud Shell-Aktivierung Cloud Shell aktivieren. Dadurch wird im unteren Bereich der Google Cloud Console eine Sitzung gestartet.

    2. Legen Sie Umgebungsvariablen fest:

      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`
      

      Ersetzen Sie Folgendes:

      • PROJECT_ID: Ihre Google Cloud Projekt-ID.
      • CLUSTER_VERSION ist die zu verwendende GKE-Version. Es muss 1.30.1 oder höher sein.
    3. Klonen Sie das GitHub-Repository:

      git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
      
    4. Wechseln Sie in das Arbeitsverzeichnis:

      cd kubernetes-engine-samples/ai-ml/gke-ray/rayserve/stable-diffusion
      
    5. Erstellen Sie eine virtuelle Python-Umgebung:

      venv

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

      Conda

      1. Installieren Sie Conda.

      2. Führen Sie folgende Befehle aus:

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

      Wenn Sie eine Serve-Anwendung mit serve run bereitstellen, erwartet Ray, dass die Python-Version des lokalen Clients mit der im Ray-Cluster verwendeten Version übereinstimmt. Das rayproject/ray:2.37.0-Image verwendet Python 3.9. Wenn Sie eine andere Clientversion verwenden, wählen Sie das entsprechende Ray-Image aus.

    6. Installieren Sie die erforderlichen Abhängigkeiten, um die Serve-Anwendung auszuführen:

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

    Cluster mit einem GPU-Knotenpool erstellen

    Erstellen Sie einen Autopilot- oder Standard-GKE-Cluster mit einem GPU-Knotenpool:

    Autopilot

    Autopilot-Cluster erstellen:

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

    Standard

    1. Standardcluster erstellen:

      gcloud container clusters create ${CLUSTER_NAME} \
          --addons=RayOperator \
          --cluster-version=${CLUSTER_VERSION}  \
          --machine-type=c3d-standard-8 \
          --location=${COMPUTE_ZONE} \
          --num-nodes=1
      
    2. Erstellen Sie einen GPU-Knotenpool:

      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
      

    RayCluster-Ressource bereitstellen

    So stellen Sie eine RayCluster-Ressource bereit:

    1. Prüfen Sie das folgende Manifest:

      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

      Dieses Manifest beschreibt eine RayCluster-Ressource.

    2. Wenden Sie das Manifest auf Ihren Cluster an:

      kubectl apply -f ray-cluster.yaml
      
    3. Prüfen Sie, ob die RayCluster-Ressource bereit ist:

      kubectl get raycluster
      

      Die Ausgabe sieht in etwa so aus:

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

      In dieser Ausgabe gibt ready in der Spalte STATUS an, dass die RayCluster-Ressource bereit ist.

    Verbindung zur RayCluster-Ressource herstellen

    So stellen Sie eine Verbindung zur RayCluster-Ressource her:

    1. Prüfen Sie, ob GKE den RayCluster-Dienst erstellt hat:

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

      Die Ausgabe sieht in etwa so aus:

      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. Richten Sie Portweiterleitungssitzungen zum Ray-Head ein:

      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. Prüfen Sie, ob der Ray-Client über localhost eine Verbindung zum Ray-Cluster herstellen kann:

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

      Die Ausgabe sieht in etwa so aus:

      ======== 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
      

    Ray Serve-Anwendung ausführen

    So führen Sie eine Ray Serve-Anwendung aus:

    1. Führen Sie die Stable Diffusion Ray Serve-Anwendung aus:

      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
      
      

      Die Ausgabe sieht in etwa so aus:

      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. Richten Sie eine Portweiterleitungssitzung zum Ray Serve-Port (8000) ein:

      kubectl port-forward svc/stable-diffusion-cluster-head-svc 8000:8000 2>&1 >/dev/null &
      
    3. Führen Sie das Python-Skript aus:

      python generate_image.py
      

      Das Skript generiert ein Bild in einer Datei mit dem Namen output.png. Das Bild sieht in etwa so aus:

      Ein Strand bei Sonnenuntergang. Mit Stable Diffusion generiertes Bild.

    RayService bereitstellen

    Die benutzerdefinierte RayService-Ressource verwaltet den Lebenszyklus einer RayCluster-Ressource und Ray Serve-Anwendung.

    Weitere Informationen zu RayService finden Sie unter Ray-Serve-Anwendungen bereitstellen und Produktionsanleitung in der Ray-Dokumentation.

    So stellen Sie eine RayService-Ressource bereit:

    1. Prüfen Sie das folgende Manifest:

      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

      Dieses Manifest beschreibt eine benutzerdefinierte RayService-Ressource.

    2. Wenden Sie das Manifest auf Ihren Cluster an:

      kubectl apply -f ray-service.yaml
      
    3. Prüfen Sie, ob der Dienst bereit ist:

      kubectl get svc stable-diffusion-serve-svc
      

      Die Ausgabe sieht in etwa so aus:

      NAME                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
      
      stable-diffusion-serve-svc   ClusterIP   34.118.236.0   <none>        8000/TCP   31m
      
    4. Konfigurieren Sie die Portweiterleitung zum Ray Serve-Dienst:

      kubectl port-forward svc/stable-diffusion-serve-svc 8000:8000 2>&1 >/dev/null &
      
    5. Führen Sie das Python-Skript aus dem vorherigen Abschnitt aus:

      python generate_image.py
      

      Das Skript generiert ein Bild, das dem im vorherigen Abschnitt generierten Bild ähnelt.

    Bereinigen

    Projekt löschen

      Delete a Google Cloud project:

      gcloud projects delete PROJECT_ID

    Einzelne Ressourcen löschen

    Zum Löschen des Clusters geben Sie Folgendes ein:

    gcloud container clusters delete ${CLUSTER_NAME}
    

    Nächste Schritte

    • Referenzarchitekturen, Diagramme und Best Practices zu Google Cloud kennenlernen. Weitere Informationen zu Cloud Architecture Center