Partilhar via


Configurar e implantar um cluster Ray no Serviço Kubernetes do Azure (AKS)

Neste artigo, você configura e implanta um cluster Ray no Serviço Kubernetes do Azure (AKS) usando o KubeRay. Você também aprende a usar o cluster Ray para treinar um modelo simples de aprendizado de máquina e exibir os resultados no Ray Dashboard.

Este artigo fornece dois métodos para implantar o cluster Ray no AKS:

  • Implantação não interativa: Use o deploy.sh script no repositório GitHub para implantar o exemplo completo do Ray de forma não interativa.
  • Implantação manual: siga as etapas de implantação manual para implantar a amostra Ray no AKS.

Pré-requisitos

  • Analise a visão geral do cluster Ray no AKS para entender os componentes e o processo de implantação.
  • Uma subscrição do Azure. Se não tiver uma subscrição do Azure, pode criar uma conta gratuita aqui.
  • A CLI do Azure instalada em sua máquina local. Você pode instalá-lo usando as instruções em Como instalar a CLI do Azure.
  • A extensão Azure Kubernetes Service Preview foi instalada.
  • Helm instalado.
  • Ferramentas cliente Terraform ou OpenTofu instaladas. Este artigo usa Terraform, mas os módulos usados devem ser compatíveis com OpenTofu.

Implantar a amostra Ray de forma não interativa

Se quiser implantar o exemplo completo do Ray de forma não interativa, você pode usar o deploy.sh script no repositório GitHub (https://github.com/Azure-Samples/aks-ray-sample). Esse script conclui as etapas descritas na seção Processo de implantação do Ray.

  1. Clone o repositório GitHub localmente e mude para a raiz do repositório usando os seguintes comandos:

    git clone https://github.com/Azure-Samples/aks-ray-sample
    cd aks-ray-sample
    
  2. Implante o exemplo completo usando os seguintes comandos:

    chmod +x deploy.sh
    ./deploy.sh
    
  3. Quando a implantação for concluída, examine a saída dos logs e o grupo de recursos no portal do Azure para ver a infraestrutura que foi criada.

Implantar manualmente o exemplo de Ray

Fashion MNIST é um conjunto de dados de imagens de artigos de Zalando que consiste em um conjunto de treinamento de 60.000 exemplos e um conjunto de teste de 10.000 exemplos. Cada exemplo é uma imagem em tons de cinza 28x28 associada a um rótulo de dez classes. Neste guia, você treina um modelo PyTorch simples neste conjunto de dados usando o cluster Ray.

Implantar a especificação RayJob

Para treinar o modelo, é necessário submeter uma especificação Ray Job ao operador KubeRay em execução num cluster AKS privado. A especificação Ray Job é um arquivo YAML que descreve os recursos necessários para executar o trabalho, incluindo a imagem do Docker, o comando a ser executado e o número de trabalhadores a serem usados.

Observando a descrição do Ray Job, talvez seja necessário modificar alguns campos para corresponder ao seu ambiente:

  • O replicas campo sob a workerGroupSpecs seção em rayClusterSpec especifica o número de pods de trabalho que o KubeRay agenda para o cluster do Kubernetes. Cada pod de trabalho requer 3 CPUs e 4 GB de memória. O pod principal requer 1 CPU e 4 GB de memória. Definir o replicas campo como 2 requer 8 vCPUs no pool de nós usado para implementar o RayCluster para o trabalho.
  • O NUM_WORKERS campo abaixo runtimeEnvYAML especifica spec o número de atores Ray a serem lançados. Cada ator Ray deve ser atendido por um pod de trabalho no cluster do Kubernetes, portanto, esse campo deve ser menor ou igual ao replicas campo. Neste exemplo, definimos NUM_WORKERS como 2, que corresponde ao replicas campo.
  • O CPUS_PER_WORKER campo deve ser definido como menor ou igual ao número de CPUs alocadas a cada pod de trabalhador menos 1. Neste exemplo, a solicitação de recurso da CPU por pod de trabalho é 3, portanto CPUS_PER_WORKER é definido como 2.

Para resumir, você precisa de um total de 8 vCPUs no pool de nós para executar o trabalho de treinamento do modelo PyTorch. Como adicionámos uma restrição no pool de nós do sistema para que nenhum pod de utilizador possa ser alocado nele, devemos criar um novo pool de nós com pelo menos 8 vCPUs para hospedar o cluster Ray.

  1. Baixe o arquivo de especificação do Ray Job usando o seguinte comando:

    curl -LO https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/pytorch-mnist/ray-job.pytorch-mnist.yaml
    
  2. Faça as modificações necessárias no arquivo de especificação do Ray Job.

  3. Inicie o trabalho de treinamento do modelo PyTorch usando o kubectl apply comando.

    kubectl apply -n kuberay -f ray-job.pytorch-mnist.yaml
    

Verificar a implantação do RayJob

  1. Verifica se tens dois pods de trabalho e um pod de controlo em execução no namespace usando o comando kubectl get pods.

    kubectl get pods -n kuberay
    

    Sua saída deve ser semelhante à saída de exemplo a seguir:

    NAME                                                      READY   STATUS    RESTARTS   AGE
    kuberay-operator-7d7998bcdb-9h8hx                         1/1     Running   0          3d2h
    pytorch-mnist-raycluster-s7xd9-worker-small-group-knpgl   1/1     Running   0          6m15s
    pytorch-mnist-raycluster-s7xd9-worker-small-group-p74cm   1/1     Running   0          6m15s
    rayjob-pytorch-mnist-fc959                                1/1     Running   0          5m35s
    rayjob-pytorch-mnist-raycluster-s7xd9-head-l24hn          1/1     Running   0          6m15s
    
  2. Verifique o status do RayJob usando o kubectl get comando.

    kubectl get rayjob -n kuberay
    

    Sua saída deve ser semelhante à saída de exemplo a seguir:

    NAME                   JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME   AGE
    rayjob-pytorch-mnist   RUNNING      Running             2024-11-22T03:08:22Z              9m36s
    
  3. Aguarde até que o RayJob seja concluído. Isto poderá demorar alguns minutos. Uma vez que o JOB STATUS é SUCCEEDED, pode-se verificar os registos de treino. Você pode fazer isso primeiro obtendo o nome do pod que executa o RayJob usando o kubectl get pods comando.

    kubectl get pods -n kuberay
    

    Na saída, você verá um pod com um nome que começa com rayjob-pytorch-mnist, semelhante ao seguinte exemplo de saída:

    NAME                                                      READY   STATUS      RESTARTS   AGE
    kuberay-operator-7d7998bcdb-9h8hx                         1/1     Running     0          3d2h
    pytorch-mnist-raycluster-s7xd9-worker-small-group-knpgl   1/1     Running     0          14m
    pytorch-mnist-raycluster-s7xd9-worker-small-group-p74cm   1/1     Running     0          14m
    rayjob-pytorch-mnist-fc959                                0/1     Completed   0          13m
    rayjob-pytorch-mnist-raycluster-s7xd9-head-l24hn          1/1     Running     0          14m
    
  4. Visualize os logs do RayJob usando o kubectl logs comando. Certifique-se de substituir rayjob-pytorch-mnist-fc959 pelo nome do pod que executa seu RayJob.

    kubectl logs -n kuberay rayjob-pytorch-mnist-fc959
    

    Na saída, deverá ver os registos de treino para o modelo PyTorch, semelhante ao exemplo de saída a seguir.

    2024-11-21 19:09:04,986 INFO cli.py:39 -- Job submission server address: http://rayjob-pytorch-mnist-raycluster-s7xd9-head-svc.kuberay.svc.cluster.local:8265
    2024-11-21 19:09:05,712 SUCC cli.py:63 -- -------------------------------------------------------
    2024-11-21 19:09:05,713 SUCC cli.py:64 -- Job 'rayjob-pytorch-mnist-hndpx' submitted successfully
    2024-11-21 19:09:05,713 SUCC cli.py:65 -- -------------------------------------------------------
    2024-11-21 19:09:05,713 INFO cli.py:289 -- Next steps
    2024-11-21 19:09:05,713 INFO cli.py:290 -- Query the logs of the job:
    2024-11-21 19:09:05,713 INFO cli.py:292 -- ray job logs rayjob-pytorch-mnist-hndpx
    2024-11-21 19:09:05,713 INFO cli.py:294 -- Query the status of the job:
    ...
    
    View detailed results here: /home/ray/ray_results/TorchTrainer_2024-11-21_19-11-23
    To visualize your results with TensorBoard, run: `tensorboard --logdir /tmp/ray/session_2024-11-21_19-08-24_556164_1/artifacts/2024-11-21_19-11-24/TorchTrainer_2024-11-21_19-11-23/driver_artifacts`
    
    Training started with configuration:
    ╭─────────────────────────────────────────────────╮
    │ Training config                                 │
    ├─────────────────────────────────────────────────┤
    │ train_loop_config/batch_size_per_worker      16 │
    │ train_loop_config/epochs                     10 │
    │ train_loop_config/lr                      0.001 │
    ╰─────────────────────────────────────────────────╯
    (RayTrainWorker pid=1193, ip=10.244.4.193) Setting up process group for: env:// [rank=0, world_size=2]
    (TorchTrainer pid=1138, ip=10.244.4.193) Started distributed worker processes:
    (TorchTrainer pid=1138, ip=10.244.4.193) - (node_id=3ea81f12c0f73ebfbd5b46664e29ced00266e69355c699970e1d824b, ip=10.244.4.193, pid=1193) world_rank=0, local_rank=0, node_rank=0
    (TorchTrainer pid=1138, ip=10.244.4.193) - (node_id=2b00ea2b369c9d27de9596ce329daad1d24626b149975cf23cd10ea3, ip=10.244.1.42, pid=1341) world_rank=1, local_rank=0, node_rank=1
    (RayTrainWorker pid=1341, ip=10.244.1.42) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz
    (RayTrainWorker pid=1193, ip=10.244.4.193) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz to /home/ray/data/FashionMNIST/raw/train-images-idx3-ubyte.gz
    (RayTrainWorker pid=1193, ip=10.244.4.193)
      0%|          | 0.00/26.4M [00:00<?, ?B/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
      0%|          | 65.5k/26.4M [00:00<01:13, 356kB/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    100%|██████████| 26.4M/26.4M [00:01<00:00, 18.9MB/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193) Extracting /home/ray/data/FashionMNIST/raw/train-images-idx3-ubyte.gz to /home/ray/data/FashionMNIST/raw
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    100%|██████████| 26.4M/26.4M [00:01<00:00, 18.7MB/s]
    ...
    Training finished iteration 1 at 2024-11-21 19:15:46. Total running time: 4min 22s
    ╭───────────────────────────────╮
    │ Training result               │
    ├───────────────────────────────┤
    │ checkpoint_dir_name           │
    │ time_this_iter_s        144.9 │
    │ time_total_s            144.9 │
    │ training_iteration          1 │
    │ accuracy                0.805 │
    │ loss                  0.52336 │
    ╰───────────────────────────────╯
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 0:  97%|█████████▋| 303/313 [00:01<00:00, 269.60it/s]
    Test Epoch 0: 100%|██████████| 313/313 [00:01<00:00, 267.14it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 1:   0%|          | 0/1875 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 0: 100%|██████████| 313/313 [00:01<00:00, 270.44it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 0: 100%|█████████▉| 1866/1875 [00:24<00:00, 82.49it/s] [repeated 35x across cluster]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 0: 100%|██████████| 1875/1875 [00:24<00:00, 77.99it/s]
    Train Epoch 0: 100%|██████████| 1875/1875 [00:24<00:00, 76.19it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 0:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 0:  88%|████████▊ | 275/313 [00:01<00:00, 265.39it/s] [repeated 19x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  19%|█▉        | 354/1875 [00:04<00:18, 82.66it/s] [repeated 80x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:   0%|          | 0/1875 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  40%|████      | 757/1875 [00:09<00:13, 83.01it/s] [repeated 90x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  62%|██████▏   | 1164/1875 [00:14<00:08, 83.39it/s] [repeated 92x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  82%|████████▏ | 1533/1875 [00:19<00:05, 68.09it/s] [repeated 91x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 1:  91%|█████████▏| 1713/1875 [00:22<00:02, 70.20it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 1:  91%|█████████ | 1707/1875 [00:22<00:02, 70.04it/s] [repeated 47x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:   8%|▊         | 24/313 [00:00<00:01, 237.98it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 1:  96%|█████████▋| 302/313 [00:01<00:00, 250.76it/s]
    Test Epoch 1: 100%|██████████| 313/313 [00:01<00:00, 262.94it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 2:   0%|          | 0/1875 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:  92%|█████████▏| 289/313 [00:01<00:00, 222.57it/s]
    
    Training finished iteration 2 at 2024-11-21 19:16:12. Total running time: 4min 48s
    ╭───────────────────────────────╮
    │ Training result               │
    ├───────────────────────────────┤
    │ checkpoint_dir_name           │
    │ time_this_iter_s       25.975 │
    │ time_total_s          170.875 │
    │ training_iteration          2 │
    │ accuracy                0.828 │
    │ loss                  0.45946 │
    ╰───────────────────────────────╯
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1: 100%|██████████| 313/313 [00:01<00:00, 226.04it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Train Epoch 1: 100%|██████████| 1875/1875 [00:24<00:00, 76.24it/s] [repeated 45x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 2:  13%|█▎        | 239/1875 [00:03<00:24, 67.30it/s] [repeated 64x across cluster]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 1:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 1:  85%|████████▍ | 266/313 [00:01<00:00, 222.54it/s] [repeated 20x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    ..
    
    Training completed after 10 iterations at 2024-11-21 19:19:47. Total running time: 8min 23s
    2024-11-21 19:19:47,596 INFO tune.py:1009 -- Wrote the latest version of all result files and experiment state to '/home/ray/ray_results/TorchTrainer_2024-11-21_19-11-23' in 0.0029s.
    
    Training result: Result(
      metrics={'loss': 0.35892221605786073, 'accuracy': 0.872},
      path='/home/ray/ray_results/TorchTrainer_2024-11-21_19-11-23/TorchTrainer_74867_00000_0_2024-11-21_19-11-24',
      filesystem='local',
      checkpoint=None
    )
    (RayTrainWorker pid=1341, ip=10.244.1.42) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz [repeated 7x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42) Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz to /home/ray/data/FashionMNIST/raw/t10k-labels-idx1-ubyte.gz [repeated 7x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42) Extracting /home/ray/data/FashionMNIST/raw/t10k-labels-idx1-ubyte.gz to /home/ray/data/FashionMNIST/raw [repeated 7x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 9:  91%|█████████ | 1708/1875 [00:21<00:01, 83.84it/s] [repeated 23x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Train Epoch 9: 100%|██████████| 1875/1875 [00:23<00:00, 78.52it/s] [repeated 37x across cluster]
    (RayTrainWorker pid=1341, ip=10.244.1.42)
    Test Epoch 9:   0%|          | 0/313 [00:00<?, ?it/s]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 9:  89%|████████▉ | 278/313 [00:01<00:00, 266.46it/s] [repeated 19x across cluster]
    (RayTrainWorker pid=1193, ip=10.244.4.193)
    Test Epoch 9:  97%|█████████▋| 305/313 [00:01<00:00, 256.69it/s]
    Test Epoch 9: 100%|██████████| 313/313 [00:01<00:00, 267.35it/s]
    2024-11-21 19:19:51,728 SUCC cli.py:63 -- ------------------------------------------
    2024-11-21 19:19:51,728 SUCC cli.py:64 -- Job 'rayjob-pytorch-mnist-hndpx' succeeded
    2024-11-21 19:19:51,728 SUCC cli.py:65 -- ------------------------------------------
    

Veja os resultados do treinamento no Ray Dashboard

Quando o RayJob for concluído com sucesso, você poderá visualizar os resultados do treinamento no Painel do Ray. O Ray Dashboard fornece monitoramento e visualizações em tempo real de clusters Ray. Você pode usar o Ray Dashboard para monitorar o status de clusters Ray, visualizar logs e visualizar os resultados de trabalhos de aprendizado de máquina.

Para acessar o Ray Dashboard, você precisa expor o serviço Ray head à internet pública criando um shim de serviço para expor o serviço Ray head na porta 80 em vez da porta 8265.

Nota

O deploy.sh descrito na seção anterior expõe automaticamente o serviço principal do Ray para a Internet pública. As etapas a seguir estão incluídas no deploy.sh script.

  1. Obtenha o nome do serviço principal Ray e guarde-o numa variável de shell usando o seguinte comando:

    rayclusterhead=$(kubectl get service -n $kuberay_namespace | grep 'rayjob-pytorch-mnist-raycluster' | grep 'ClusterIP' | awk '{print $1}')
    
  2. Crie o shim de serviço para expor o serviço Ray head na porta 80 usando o kubectl expose service comando.

    kubectl expose service $rayclusterhead \
    -n $kuberay_namespace \
    --port=80 \
    --target-port=8265 \
    --type=NodePort \
    --name=ray-dash
    
  3. Crie o ingress para expor o service shim com o controlador de ingress usando o seguinte comando:

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ray-dash
      namespace: kuberay
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:
      ingressClassName: webapprouting.kubernetes.azure.com
      rules:
      - http:
          paths:
          - backend:
              service:
                name: ray-dash
                port:
                  number: 80
            path: /
            pathType: Prefix
    EOF
    
  4. Obtenha o endereço IP público do controlador de entrada usando o kubectl get service comando.

    kubectl get service -n app-routing-system
    
  5. Na saída, você deve ver o endereço IP público do balanceador de carga conectado ao controlador de entrada. Copie o endereço IP público e cole-o em um navegador da Web. Você deve ver o Ray Dashboard.

Limpar recursos

Para limpar os recursos criados neste guia, você pode excluir o grupo de recursos do Azure que contém o cluster AKS.

Próximos passos

Para saber mais sobre cargas de trabalho de IA e aprendizado de máquina no AKS, consulte os seguintes artigos:

Contribuidores

A Microsoft mantém este artigo. Os seguintes colaboradores escreveram-no originalmente:

  • Russell de Pina - Brasil | Principal TPM
  • Ken Kilty - Brasil | Principal TPM
  • Erin Schaffer | Desenvolvedora de Conteúdo 2
  • Adrian Joian | Engenheiro Principal de Clientes
  • Ryan Graham | Especialista Técnico Principal