Esegui il deployment di un'applicazione Ray Serve con un modello di diffusione stabile su Google Kubernetes Engine (GKE)

Questa guida fornisce un esempio di come eseguire il deployment e pubblicare un modello Stable Diffusion su Google Kubernetes Engine (GKE) utilizzando Ray Serve e il componente aggiuntivo Operatore Ray come implementazione di esempio.

Informazioni su Ray e Ray Serve

Ray è un framework di calcolo scalabile open source per applicazioni AI/ML. Ray Serve è una libreria di erogazione del modello per Ray utilizzata per scalare ed erogare i modelli in un ambiente distribuito. Per saperne di più, consulta Ray Serve nella documentazione di Ray.

Puoi utilizzare una risorsa RayCluster o RayService per eseguire il deployment delle tue applicazioni Ray Serve. Devi utilizzare una risorsa RayService in produzione per i seguenti motivi:

  • Aggiornamenti sul posto per le applicazioni RayService
  • Upgrade senza tempi di inattività per le risorse RayCluster
  • Applicazioni Ray Serve ad alta disponibilità

Obiettivi

Questa guida è destinata ai clienti di AI generativa, agli utenti nuovi o esistenti di GKE, agli ingegneri ML, agli ingegneri MLOps (DevOps) o agli amministratori di piattaforma interessati a utilizzare le funzionalità di orchestrazione dei container Kubernetes per erogare modelli utilizzando Ray.

  • Crea un cluster GKE con un pool di nodi GPU.
  • Crea un cluster Ray utilizzando la risorsa personalizzata RayCluster.
  • Esegui un'applicazione Ray Serve.
  • Esegui il deployment di una risorsa personalizzata RayService.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

I nuovi utenti di Google Cloud potrebbero avere diritto a una prova senza costi.

Al termine delle attività descritte in questo documento, puoi evitare l'addebito di ulteriori costi eliminando le risorse che hai creato. Per saperne di più, consulta Esegui la pulizia.

Prima di iniziare

Cloud Shell è preinstallato con il software necessario per questo tutorial, tra cui kubectl e gcloud CLI. Se non utilizzi Cloud Shell, devi installare gcloud CLI.

  1. Accedi al tuo account Google Cloud . Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti senza costi per l'esecuzione, il test e il deployment dei workload.
  2. Installa Google Cloud CLI.

  3. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  4. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  5. Crea o seleziona un Google Cloud progetto.

    Ruoli richiesti per selezionare o creare un progetto

    • Seleziona un progetto: la selezione di un progetto non richiede un ruolo IAM specifico. Puoi selezionare qualsiasi progetto per il quale ti è stato concesso un ruolo.
    • Crea un progetto: per creare un progetto, devi disporre del ruolo Autore progetto (roles/resourcemanager.projectCreator), che contiene l'autorizzazione resourcemanager.projects.create. Scopri come concedere i ruoli.
    • Creare un progetto Google Cloud :

      gcloud projects create PROJECT_ID

      Sostituisci PROJECT_ID con un nome per il progetto Google Cloud che stai creando.

    • Seleziona il progetto Google Cloud che hai creato:

      gcloud config set project PROJECT_ID

      Sostituisci PROJECT_ID con il nome del progetto Google Cloud .

  6. Verifica che la fatturazione sia attivata per il tuo progetto Google Cloud .

  7. Abilita l'API GKE:

    Ruoli richiesti per abilitare le API

    Per abilitare le API, devi disporre del ruolo IAM Amministratore utilizzo dei servizi (roles/serviceusage.serviceUsageAdmin), che include l'autorizzazione serviceusage.services.enable. Scopri come concedere i ruoli.

    gcloud services enable container.googleapis.com
  8. Installa Google Cloud CLI.

  9. Se utilizzi un provider di identità (IdP) esterno, devi prima accedere a gcloud CLI con la tua identità federata.

  10. Per inizializzare gcloud CLI, esegui questo comando:

    gcloud init
  11. Crea o seleziona un Google Cloud progetto.

    Ruoli richiesti per selezionare o creare un progetto

    • Seleziona un progetto: la selezione di un progetto non richiede un ruolo IAM specifico. Puoi selezionare qualsiasi progetto per il quale ti è stato concesso un ruolo.
    • Crea un progetto: per creare un progetto, devi disporre del ruolo Autore progetto (roles/resourcemanager.projectCreator), che contiene l'autorizzazione resourcemanager.projects.create. Scopri come concedere i ruoli.
    • Creare un progetto Google Cloud :

      gcloud projects create PROJECT_ID

      Sostituisci PROJECT_ID con un nome per il progetto Google Cloud che stai creando.

    • Seleziona il progetto Google Cloud che hai creato:

      gcloud config set project PROJECT_ID

      Sostituisci PROJECT_ID con il nome del progetto Google Cloud .

  12. Verifica che la fatturazione sia attivata per il tuo progetto Google Cloud .

  13. Abilita l'API GKE:

    Ruoli richiesti per abilitare le API

    Per abilitare le API, devi disporre del ruolo IAM Amministratore utilizzo dei servizi (roles/serviceusage.serviceUsageAdmin), che include l'autorizzazione serviceusage.services.enable. Scopri come concedere i ruoli.

    gcloud services enable container.googleapis.com
  14. Concedi ruoli al tuo account utente. Esegui il seguente comando una volta per ciascuno dei seguenti ruoli IAM: roles/container.clusterAdmin, roles/container.admin

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

    Sostituisci quanto segue:

    • PROJECT_ID: il tuo ID progetto.
    • USER_IDENTIFIER: l'identificatore del tuo account utente . Ad esempio: myemail@example.com.
    • ROLE: il ruolo IAM che concedi al tuo account utente.

prepara l'ambiente

Per preparare l'ambiente:

  1. Avvia una sessione di Cloud Shell dalla console Google Cloud facendo clic su Icona di attivazione di Cloud Shell Attiva Cloud Shell nella consoleGoogle Cloud . Viene avviata una sessione nel riquadro inferiore della console Google Cloud .

  2. Imposta le variabili di ambiente:

    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`
    

    Sostituisci quanto segue:

    • PROJECT_ID: il tuo Google Cloud ID progetto.
    • CLUSTER_VERSION: la versione di GKE da utilizzare. Deve essere 1.30.1 o successiva.
  3. Clona il repository GitHub:

    git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
    
  4. Passa alla directory di lavoro:

    cd kubernetes-engine-samples/ai-ml/gke-ray/rayserve/stable-diffusion
    
  5. Crea un ambiente virtuale Python:

    venv

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

    Conda

    1. Installa Conda.

    2. Esegui questi comandi:

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

    Quando esegui il deployment di un'applicazione Serve con serve run, Ray si aspetta che la versione di Python del client locale corrisponda a quella utilizzata nel cluster Ray. L'immagine rayproject/ray:2.37.0 utilizza Python 3.9. Se utilizzi una versione diversa del client, seleziona l'immagine Ray appropriata.

  6. Installa le dipendenze richieste per eseguire l'applicazione Serve:

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

Crea un cluster con un node pool GPU

Crea un cluster GKE Autopilot o Standard con un pool di nodi GPU:

Autopilot

Crea un cluster Autopilot:

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

Standard

  1. Crea 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. Crea un pool di nodi 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
    

Esegui il deployment di una risorsa RayCluster

Per eseguire il deployment di una risorsa RayCluster:

  1. Esamina il seguente 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

    Questo manifest descrive una risorsa RayCluster.

  2. Applica il manifest al cluster:

    kubectl apply -f ray-cluster.yaml
    
  3. Verifica che la risorsa RayCluster sia pronta:

    kubectl get raycluster
    

    L'output è simile al seguente:

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

    In questo output, ready nella colonna STATUS indica che la risorsa RayCluster è pronta.

Connettiti alla risorsa RayCluster

Per connetterti alla risorsa RayCluster:

  1. Verifica che GKE abbia creato il servizio RayCluster:

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

    L'output è simile al seguente:

    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. Stabilisci sessioni di port forwarding verso la testa di 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. Verifica che il client Ray possa connettersi al cluster Ray utilizzando localhost:

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

    L'output è simile al seguente:

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

Esegui un'applicazione Ray Serve

Per eseguire un'applicazione Ray Serve:

  1. Esegui l'applicazione 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
    
    

    L'output è simile al seguente:

    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. Stabilisci una sessione di port forwarding alla porta Ray Serve (8000):

    kubectl port-forward svc/stable-diffusion-cluster-head-svc 8000:8000 2>&1 >/dev/null &
    
  3. Esegui lo script Python:

    python generate_image.py
    

    Lo script genera un'immagine in un file denominato output.png. L'immagine è simile alla seguente:

    Una spiaggia al tramonto. Immagine generata da Stable Diffusion.

Esegui il deployment di un RayService

La risorsa personalizzata RayService gestisce il ciclo di vita di una risorsa RayCluster e dell'applicazione Ray Serve.

Per ulteriori informazioni su RayService, consulta Deploy Ray Serve Applications e Production Guide nella documentazione di Ray.

Per eseguire il deployment di una risorsa RayService:

  1. Esamina il seguente 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

    Questo manifest descrive una risorsa personalizzata RayService.

  2. Applica il manifest al cluster:

    kubectl apply -f ray-service.yaml
    
  3. Verifica che il servizio sia pronto:

    kubectl get svc stable-diffusion-serve-svc
    

    L'output è simile al seguente:

    NAME                         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    
    stable-diffusion-serve-svc   ClusterIP   34.118.236.0   <none>        8000/TCP   31m
    
  4. Configura il port forwarding al servizio Ray Serve:

    kubectl port-forward svc/stable-diffusion-serve-svc 8000:8000 2>&1 >/dev/null &
    
  5. Esegui lo script Python della sezione precedente:

    python generate_image.py
    

    Lo script genera un'immagine simile a quella generata nella sezione precedente.

Osserva i tuoi carichi di lavoro Ray

Per visualizzare i dettagli dei tuoi RayJob, puoi andare alla sezione Kubernetes Engine > AI/ML > Job della console Google Cloud .

Visualizza RayJobs nella Google Cloud console

Esegui la pulizia

Elimina il progetto

    Elimina un progetto Google Cloud :

    gcloud projects delete PROJECT_ID

Elimina singole risorse

Per eliminare il cluster, digita:

gcloud container clusters delete ${CLUSTER_NAME}

Passaggi successivi

  • Esplora architetture di riferimento, diagrammi e best practice su Google Cloud. Consulta il nostro Cloud Architecture Center.