Este guia fornece um exemplo de como implementar e publicar um modelo Stable Diffusion no Google Kubernetes Engine (GKE) através do Ray Serve e do suplemento Ray Operator como exemplo de implementação.
Acerca do Ray e do Ray Serve
O Ray é uma framework de computação escalável de código aberto para aplicações de IA/AA. O RayServe é uma biblioteca de publicação de modelos para o Ray usada para dimensionar e publicar modelos num ambiente distribuído. Para mais informações, consulte o artigo Ray Serve na documentação do Ray.
Pode usar um recurso RayCluster ou RayService para implementar as suas aplicações Ray Serve. Deve usar um recurso RayService em produção pelos seguintes motivos:
- Atualizações no local para aplicações RayService
- Atualização sem período de inatividade para recursos RayCluster
- Aplicações Ray Serve altamente disponíveis
Objetivos
Este guia destina-se a clientes de IA generativa, utilizadores novos ou existentes do GKE, engenheiros de ML, engenheiros de MLOps (DevOps) ou administradores de plataformas interessados em usar capacidades de orquestração de contentores do Kubernetes para publicar modelos com o Ray.
- Crie um cluster do GKE com um node pool de GPU.
- Crie um cluster do Ray com o recurso personalizado RayCluster.
- Execute uma aplicação Ray Serve.
- Implemente um recurso personalizado RayService.
Custos
Neste documento, usa os seguintes componentes faturáveis do Google Cloud:
Para gerar uma estimativa de custos com base na sua utilização projetada,
use a calculadora de preços.
Quando terminar as tarefas descritas neste documento, pode evitar a faturação contínua eliminando os recursos que criou. Para mais informações, consulte o artigo Limpe.
Antes de começar
O Cloud Shell está pré-instalado com o software necessário para este tutorial, incluindo o kubectl
e a CLI gcloud. Se não usar o Cloud Shell,
tem de instalar a CLI gcloud.
- 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.
-
Install the Google Cloud CLI.
-
Se estiver a usar um fornecedor de identidade (IdP) externo, tem primeiro de iniciar sessão na CLI gcloud com a sua identidade federada.
-
Para inicializar a CLI gcloud, execute o seguinte comando:
gcloud init
-
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 theresourcemanager.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.
-
Verify that billing is enabled for your Google Cloud project.
-
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 theserviceusage.services.enable
permission. Learn how to grant roles.gcloud services enable container.googleapis.com
-
Install the Google Cloud CLI.
-
Se estiver a usar um fornecedor de identidade (IdP) externo, tem primeiro de iniciar sessão na CLI gcloud com a sua identidade federada.
-
Para inicializar a CLI gcloud, execute o seguinte comando:
gcloud init
-
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 theresourcemanager.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.
-
Verify that billing is enabled for your Google Cloud project.
-
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 theserviceusage.services.enable
permission. Learn how to grant roles.gcloud services enable container.googleapis.com
-
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.
Inicie uma sessão do Cloud Shell a partir da Google Cloud consola, clicando em
Ativar Cloud Shell na Google Cloud consola. Esta ação inicia uma sessão no painel inferior da Google Cloud consola.
Defina variáveis de 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`
Substitua o seguinte:
PROJECT_ID
: o seu Google Cloud ID do projeto.CLUSTER_VERSION
: a versão do GKE a usar. Tem de ser1.30.1
ou posterior.
Clone o repositório do GitHub:
git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples
Mude para o diretório de trabalho:
cd kubernetes-engine-samples/ai-ml/gke-ray/rayserve/stable-diffusion
Crie um ambiente virtual do Python:
venv
python -m venv myenv && \ source myenv/bin/activate
Conda
Execute os seguintes comandos:
conda create -c conda-forge python=3.9.19 -n myenv && \ conda activate myenv
Quando implementa uma aplicação Serve com
serve run
, o Ray espera que a versão do Python do cliente local corresponda à versão usada no cluster do Ray. A imagemrayproject/ray:2.37.0
usa o Python 3.9. Se estiver a usar uma versão diferente do cliente, selecione a imagem do raio adequada.Instale as dependências necessárias para executar a aplicação Serve:
pip install ray[serve]==2.37.0 pip install torch pip install requests
Criar um cluster padrão:
gcloud container clusters create ${CLUSTER_NAME} \ --addons=RayOperator \ --cluster-version=${CLUSTER_VERSION} \ --machine-type=c3d-standard-8 \ --location=${COMPUTE_ZONE} \ --num-nodes=1
Crie um node pool de 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
Reveja o seguinte manifesto:
Este manifesto descreve um recurso RayCluster.
Aplique o manifesto ao cluster:
kubectl apply -f ray-cluster.yaml
Verifique se o recurso RayCluster está pronto:
kubectl get raycluster
O resultado é semelhante ao seguinte:
NAME DESIRED WORKERS AVAILABLE WORKERS CPUS MEMORY GPUS STATUS AGE stable-diffusion-cluster 2 2 6 20Gi 0 ready 33s
Neste resultado,
ready
na colunaSTATUS
indica que o recurso RayCluster está pronto.Verifique se o GKE criou o serviço RayCluster:
kubectl get svc stable-diffusion-cluster-head-svc
O resultado é semelhante ao seguinte:
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
Estabeleça sessões de encaminhamento de portas para a cabeça do 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 &
Verifique se o cliente Ray consegue estabelecer ligação ao cluster Ray através de localhost:
ray list nodes --address http://localhost:8265
O resultado é semelhante ao seguinte:
======== 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
Execute a aplicação 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
O resultado é semelhante ao seguinte:
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.
Estabeleça uma sessão de encaminhamento de porta para a porta do Ray Serve (8000):
kubectl port-forward svc/stable-diffusion-cluster-head-svc 8000:8000 2>&1 >/dev/null &
Execute o script Python:
python generate_image.py
O script gera uma imagem para um ficheiro denominado
output.png
. A imagem é semelhante à seguinte:Reveja o seguinte manifesto:
Este manifesto descreve um recurso personalizado RayService.
Aplique o manifesto ao cluster:
kubectl apply -f ray-service.yaml
Verifique se o serviço está pronto:
kubectl get svc stable-diffusion-serve-svc
O resultado é semelhante ao seguinte:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE stable-diffusion-serve-svc ClusterIP 34.118.236.0 <none> 8000/TCP 31m
Configure o encaminhamento de portas para o serviço Ray Serve:
kubectl port-forward svc/stable-diffusion-serve-svc 8000:8000 2>&1 >/dev/null &
Execute o script Python da secção anterior:
python generate_image.py
O script gera uma imagem semelhante à imagem gerada na secção anterior.
- Explore arquiteturas de referência, diagramas e práticas recomendadas sobre o Google Cloud. Consulte o nosso Centro de arquitetura na nuvem.
Prepare o seu ambiente
Para preparar o seu ambiente, siga estes passos:
Crie um cluster com um node pool de GPU
Crie um cluster do GKE Autopilot ou Standard com um node pool de GPU:
Piloto automático
Crie um cluster do Autopilot:
gcloud container clusters create-auto ${CLUSTER_NAME} \
--enable-ray-operator \
--cluster-version=${CLUSTER_VERSION} \
--location=${COMPUTE_REGION}
Standard
Implemente um recurso RayCluster
Para implementar um recurso RayCluster:
Estabeleça ligação ao recurso RayCluster
Para se ligar ao recurso RayCluster:
Execute uma aplicação Ray Serve
Para executar uma aplicação Ray Serve:
Implemente um RayService
O recurso personalizado RayService gere o ciclo de vida de um recurso RayCluster e de uma aplicação Ray Serve.
Para mais informações sobre o RayService, consulte os artigos Implemente aplicações Ray Serve e Guia de produção na documentação do Ray.
Para implementar um recurso RayService, siga estes passos:
Limpar
Elimine o projeto
Delete a Google Cloud project:
gcloud projects delete PROJECT_ID
Elimine recursos individuais
Para eliminar o cluster, escreva:
gcloud container clusters delete ${CLUSTER_NAME}