Freigeben über


Konfigurieren und Bereitstellen eines Ray-Clusters in Azure Kubernetes Service (AKS)

In diesem Artikel nutzen Sie KubeRay, um einen Ray-Cluster in Azure Kubernetes Service (AKS) zu konfigurieren und bereitzustellen. Außerdem erfahren Sie, wie Sie den Ray-Cluster verwenden, um ein einfaches Machine Learning-Modell zu trainieren und die Ergebnisse im Ray-Dashboard anzuzeigen.

In diesem Artikel werden zwei Methoden zur Bereitstellung des Ray-Clusters in AKS vorgestellt:

  • Nicht interaktive Bereitstellung: Verwenden Sie das Skript deploy.sh im GitHub-Repository, um das vollständige Ray-Beispiel nicht interaktiv bereitzustellen.
  • Manuelle Bereitstellung: Führen Sie die manuellen Bereitstellungsschritte aus, um das Ray-Beispiel in AKS bereitzustellen.

Voraussetzungen

Nicht interaktives Bereitstellen des Ray-Beispiels

Wenn Sie das vollständige Ray-Beispiel nicht interaktiv bereitstellen möchten, können Sie das Skript deploy.sh im GitHub-Repository (https://github.com/Azure-Samples/aks-ray-sample) verwenden. Dieses Skript führt die im Abschnitt Ray-Bereitstellungsprozessbeschriebenen Schritte aus.

  1. Klonen Sie das GitHub-Repository lokal, und ändern Sie den Stamm des Repositorys mithilfe der folgenden Befehle:

    git clone https://github.com/Azure-Samples/aks-ray-sample
    cd aks-ray-sample
    
  2. Stellen Sie das vollständige Beispiel mithilfe der folgenden Befehle bereit:

    chmod +x deploy.sh
    ./deploy.sh
    
  3. Überprüfen Sie nach Abschluss der Bereitstellung die Ausgabe der Protokolle und der Ressourcengruppe im Azure-Portal, um die erstellte Infrastruktur anzuzeigen.

Manuelles Bereitstellen des Ray-Beispiels

Fashion MNIST ist ein Dataset der Artikelbilder von Zalando, bestehend aus einem Trainingssatz von 60.000 Beispielen und einem Testsatz von 10.000 Beispielen. Jedes Beispiel ist ein Graustufenbild mit 28 x 28 Pixeln, das einer Beschriftung aus zehn Klassen zugeordnet ist. In diesem Leitfaden trainieren Sie ein einfaches PyTorch-Modell auf dieses Dataset mithilfe des Ray-Clusters.

Bereitstellen der RayJob-Spezifikation

Zum Trainieren des Modells müssen Sie eine Ray-Auftragsspezifikation an den KubeRay-Operator senden, der auf einem privaten AKS-Cluster ausgeführt wird. Bei der Ray-Auftragsspezifikation handelt es sich um eine YAML-Datei, in der die für die Ausführung des Auftrags erforderlichen Ressourcen beschrieben werden, darunter das Docker-Image, der auszuführende Befehl und die Anzahl der zu verwendenden Worker.

Unter Umständen müssen Sie einige Felder der Ray-Auftragsbeschreibung an Ihre Umgebung anpassen:

  • Das Feld replicas im Abschnitt workerGroupSpecs in rayClusterSpec gibt die Anzahl der Worker-Pods an, die KubeRay für den Kubernetes-Cluster plant. Jeder Worker-Pod erfordert 3 CPUs und 4 GB Arbeitsspeicher. Der Hauptpod erfordert 1 CPU und 4 GB Arbeitsspeicher. Um für das Feld replicas den Wert 2 festzulegen, sind 8 vCPUs im Knotenpool erforderlich, der zum Implementieren des RayCluster für den Auftrag verwendet wird.
  • Das Feld NUM_WORKERS im Abschnitt runtimeEnvYAML in spec gibt die Anzahl der zu startenden Ray-Akteure an. Jeder Ray-Akteur muss von einem Worker-Pod im Kubernetes-Cluster gewartet werden, daher muss der Wert in diesem Feld kleiner oder gleich dem Wert im Feld replicas sein. In diesem Beispiel legen wir für NUM_WORKERS den Wert 2 fest, entsprechend dem Wert des Felds replicas.
  • Für Feld CPUS_PER_WORKER muss ein Wert festgelegt werden, der kleiner oder gleich der Anzahl der jedem Worker-Pod zugeordneten CPUs minus 1 ist. In diesem Beispiel hat die CPU-Ressourcenanforderung pro Worker-Pod den Wert 3, sodass für CPUS_PER_WORKER der Wert 2 festgelegt wird.

Fassen wir zusammen: Sie benötigen insgesamt 8 vCPUs im Knotenpool, um den PyTorch-Modelltrainingsauftrag auszuführen. Da wir dem Systemknotenpool einen Taint hinzugefügt haben, damit keine Benutzer-Pods darauf geplant werden können, müssen wir einen neuen Knotenpool mit mindestens 8 vCPUs erstellen, um den Ray-Cluster zu hosten.

  1. Laden Sie die Ray-Auftragsspezifikationsdatei mit dem folgenden Befehl herunter:

    curl -LO https://raw.githubusercontent.com/ray-project/kuberay/master/ray-operator/config/samples/pytorch-mnist/ray-job.pytorch-mnist.yaml
    
  2. Nehmen Sie alle erforderlichen Änderungen an der Ray-Auftragsspezifikationsdatei vor.

  3. Starten Sie den PyTorch-Modelltrainingsauftrag mit dem Befehl kubectl apply.

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

Überprüfen der RayJob-Bereitstellung

  1. Stellen Sie mit dem Befehl kubectl get pods sicher, dass Sie über zwei Worker-Pods und einen Hauptpod verfügen, der im Namespace ausgeführt wird.

    kubectl get pods -n kuberay
    

    Ihre Ausgabe sollte in etwa dem folgendem Beispiel entsprechen:

    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. Überprüfen Sie mit dem Befehl kubectl get den Status des RayJob.

    kubectl get rayjob -n kuberay
    

    Ihre Ausgabe sollte in etwa dem folgendem Beispiel entsprechen:

    NAME                   JOB STATUS   DEPLOYMENT STATUS   START TIME             END TIME   AGE
    rayjob-pytorch-mnist   RUNNING      Running             2024-11-22T03:08:22Z              9m36s
    
  3. Warten Sie auf den Abschluss des RayJob. Dieser Vorgang kann einige Minuten in Anspruch nehmen. Sobald der JOB STATUSSUCCEEDED lautet, können Sie die Trainingsprotokolle überprüfen. Dazu müssen Sie zunächst mit dem Befehl kubectl get pods den Namen des Pods ermitteln, auf dem RayJob ausgeführt wird.

    kubectl get pods -n kuberay
    

    In der Ausgabe sollte ein Pod mit einem Namen angezeigt werden, der mit rayjob-pytorch-mnistbeginnt, ähnlich wie in der folgenden Beispielausgabe:

    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. Zeigen Sie die Protokolle des RayJob mit dem Befehl kubectl logs an. Ersetzen Sie rayjob-pytorch-mnist-fc959 durch den Namen des Pods, auf dem Ihr RayJob ausgeführt wird.

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

    In der Ausgabe sollten die Trainingsprotokolle für das PyTorch-Modell angezeigt werden, ähnlich wie in der folgenden Beispielausgabe:

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

Anzeigen von Trainingsergebnissen im Ray-Dashboard

Wenn der RayJob erfolgreich abgeschlossen ist, können Sie die Trainingsergebnisse im Ray-Dashboard anzeigen. Das Ray-Dashboard ermöglicht die Echtzeitüberwachung und Visualisierung von Ray-Clustern. Mit dem Ray-Dashboard können Sie den Status von Ray-Clustern überwachen, Protokolle anzeigen und die Ergebnisse von Machine Learning-Aufträgen visualisieren.

Um auf das Ray-Dashboard zugreifen zu können, müssen Sie den Ray-Hauptdienst für das öffentliche Internet verfügbar machen. Dazu müssen Sie einen Dienst-Shim erstellen, um den Ray-Hauptdienst an Port 80 anstelle von Port 8265 verfügbar zu machen.

Hinweis

Der im vorherigen Abschnitt beschriebene deploy.sh macht den Ray-Hauptdienst automatisch für das öffentliche Internet verfügbar. Das Skript deploy.sh enthält die folgenden Schritte.

  1. Ermitteln Sie den Namen des Ray-Hauptdiensts, und speichern Sie ihn mithilfe des folgenden Befehls in einer Shellvariable:

    rayclusterhead=$(kubectl get service -n $kuberay_namespace | grep 'rayjob-pytorch-mnist-raycluster' | grep 'ClusterIP' | awk '{print $1}')
    
  2. Erstellen Sie den Dienst-Shim, um den Ray-Hauptdienst an Port 80 mit dem Befehl kubectl expose service verfügbar zu machen.

    kubectl expose service $rayclusterhead \
    -n $kuberay_namespace \
    --port=80 \
    --target-port=8265 \
    --type=NodePort \
    --name=ray-dash
    
  3. Erstellen Sie den Eingang, um den Dienst-Shim mithilfe des Eingangscontrollers mit dem folgenden Befehl verfügbar zu machen:

    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. Ermitteln Sie die öffentliche IP-Adresse des Eingangsdatencontrollers mit dem Befehl kubectl get service.

    kubectl get service -n app-routing-system
    
  5. In der Ausgabe sollte die öffentliche IP-Adresse des Lastenausgleichs angezeigt werden, der an den Eingangscontroller angeschlossen ist. Kopieren Sie die öffentliche IP-Adresse, und fügen Sie sie in einen Webbrowser ein. Sie sollten das Ray-Dashboard sehen.

Bereinigen von Ressourcen

Zum Bereinigen der in dieser Anleitung erstellten Ressourcen können Sie die Azure-Ressourcengruppe löschen, die den AKS-Cluster enthält.

Nächste Schritte

Weitere Informationen zu KI- und Machine Learning-Workloads in AKS finden Sie in den folgenden Artikeln:

Beitragende

Microsoft pflegt diesen Artikel. Die folgenden Mitwirkenden haben es ursprünglich geschrieben:

  • Russell de Pina | Prinzipal-TPM
  • Ken Kilty | Prinzipal-TPM
  • Erin Schaffer | Inhaltsentwickler 2
  • Adrian Joian | Leitender Kundeningenieur
  • Ryan Graham | Technischer Hauptfachmann