Lernprogramm: Ausführen einer parallelen Workload mit Azure Batch mithilfe der Python-API

Mithilfe von Azure Batch können Sie umfangreiche auf Parallelverarbeitung ausgelegte HPC-Batchaufträge (High Performance Computing) effizient in Azure ausführen. In diesem Lernprogramm wird ein Python-Beispiel für die Ausführung einer parallelen Workload mithilfe von Batch erläutert. Sie erfahren, wie Sie einen gängigen Batch-Anwendungsworkflow durchführen und programmgesteuert mit Batch- und Storage-Ressourcen interagieren.

  • Authentifizieren mit Batch- und Storage-Konten.
  • Hochladen von Eingabedateien in Storage.
  • Erstellen eines Pools mit Computeknoten für die Ausführung einer Anwendung.
  • Erstellen eines Auftrags und von Aufgaben zum Verarbeiten von Eingabedateien.
  • Überwachen der Aufgabenausführung
  • Abrufen von Ausgabedateien.

In diesem Tutorial konvertieren Sie MP4-Mediendateien parallel in das MP3-Format, indem Sie das Open-Source-Tool ffmpeg verwenden.

Wenn Sie nicht über ein Azure-Konto verfügen, erstellen Sie ein kostenloses Konto , bevor Sie beginnen.

Voraussetzungen

Gewähren Sie Zugriff auf Ihre Batch- und Speicherkonten

Dieses Tutorial zeigt, wie man sich bei Azure Batch und Azure Storage authentifiziert, indem man Microsoft Entra ID mit DefaultAzureCredential verwendet. Die App verwendet keine Kontoschlüssel. Bevor du die App ausführst, stelle sicher, dass die Identität, die du verwendest, die erforderlichen Rollen auf beiden Konten hat.

  1. Melden Sie sich mit der Azure CLI an. DefaultAzureCredential übernimmt diese Anmeldung automatisch:

    az login
    
  2. Weisen Sie Ihrem Benutzerkonto eine Rolle zu, die Vorgänge auf der Datenebene für das Batch-Konto ermöglicht, z. B. Azure Batch Data Contributor. Diese Rolle ist erforderlich, um Pools, Jobs und Aufgaben zu erstellen. Sie können die Rolle auf der Access Control (IAM)-Seite des Batch-Kontos im Azure-Portal zuweisen oder die Azure CLI verwenden:

    az role assignment create \
        --assignee "<your-user-principal-name>" \
        --role "Azure Batch Data Contributor" \
        --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Batch/batchAccounts/<batch-account-name>"
    
  3. Weisen Sie Ihrem Benutzerkonto auf dem Speicherkonto die Rolle Storage Blob Data Contributor zu. Diese Rolle ist erforderlich, um Container zu erstellen, die Eingabedateien hochzuladen und den Benutzerdelegierungsschlüssel anzufordern, der die von den Aufgaben verwendeten Shared-Access-Signatur-URLs (SAS) signiert:

    az role assignment create \
        --assignee "<your-user-principal-name>" \
        --role "Storage Blob Data Contributor" \
        --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account-name>"
    
  4. Beachten Sie die folgenden Werte, die Sie im nächsten Abschnitt zur config.py-Datei des Samples hinzufügen. Sie finden sie auf der Übersichtsseite jedes Kontos im Azure-Portal:

    • Batch-Kontoname
    • URL eines Batch-Kontos, zum Beispiel https://mybatchaccount.westus2.batch.azure.com
    • Speicherkontoname

Note

Es kann ein paar Minuten dauern, bis Rollenzuweisungen sich verbreiten. Wenn die App direkt nach der Zuweisung der Rollen mit einem Autorisierungsfehler fehlschlägt, warte ein paar Minuten und versuche es erneut.

Herunterladen und Ausführen der Beispiel-App

Important

Das herunterladbare Beispiel im Batch-python-ffmpeg-Tutorial-Repository wird aktualisiert, um zu diesem Tutorial zu passen. Bis dieses Update veröffentlicht wird, könnte das Repository noch die frühere schlüsselbasierte Authentifizierung und den Ubuntu 20.04-Code enthalten. Der Code in diesem Artikel ist die Quelle der Wahrheit. Wenn das heruntergeladene Beispiel nicht mit den hier genannten Ausschnitten übereinstimmt, folgt dem in diesem Artikel gezeigten Code.

Herunterladen der Beispiel-App

Laden Sie die Beispiel-App von GitHub herunter, oder klonen Sie sie. Verwenden Sie den folgenden Befehl, um das Beispiel-App-Repository mit einem Git-Client zu klonen:

git clone https://github.com/Azure-Samples/batch-python-ffmpeg-tutorial.git

Navigieren Sie zu dem Verzeichnis, das die Datei batch_python_tutorial_ffmpeg.py enthält.

Installieren Sie in Ihrer Python-Umgebung die erforderlichen Pakete mithilfe von pip.

pip install -r requirements.txt

Verwenden Sie einen Code-Editor, um die Datei config.py zu öffnen. Aktualisieren Sie die Werte für das Batch- und Speicherkonto mit den Namen, die für Ihre Konten jeweils eindeutig sind. Im Beispiel wird DefaultAzureCredential zum Authentifizieren verwendet, sodass Kontoschlüssel nicht mehr erforderlich sind. Beispiel:

_BATCH_ACCOUNT_NAME = 'yourbatchaccount'
_BATCH_ACCOUNT_URL = 'https://yourbatchaccount.yourbatchregion.batch.azure.com'
_STORAGE_ACCOUNT_NAME = 'mystorageaccount'

Stellen Sie sicher, dass Sie über az login angemeldet sind und dass Ihre Identität über die in Zugriff auf Ihre Batch- und Speicherkonten gewähren beschriebenen Rollen verfügt. DefaultAzureCredentialkann auch andere Zugangsquellen finden, wie eine verwaltete Identität, Visual Studio Code oder Umgebungsvariablen.

App starten

So führen Sie das Skript aus

python batch_python_tutorial_ffmpeg.py

Beim Ausführen der Beispielanwendung sieht die Konsolenausgabe in etwa wie folgt aus: Bei der Ausführung kommt es bei Monitoring all tasks for 'Completed' state, timeout in 00:30:00... zu einer Pause, während die Computeknoten des Pools gestartet werden.

Sample start: 11/28/2018 3:20:21 PM

Container [input] created.
Container [output] created.
Uploading file LowPriVMs-1.mp4 to container [input]...
Uploading file LowPriVMs-2.mp4 to container [input]...
Uploading file LowPriVMs-3.mp4 to container [input]...
Uploading file LowPriVMs-4.mp4 to container [input]...
Uploading file LowPriVMs-5.mp4 to container [input]...
Creating pool [LinuxFFmpegPool]...
Creating job [LinuxFFmpegJob]...
Adding 5 tasks to job [LinuxFFmpegJob]...
Monitoring all tasks for 'Completed' state, timeout in 00:30:00...
Success! All tasks reached the 'Completed' state within the specified timeout period.
Deleting container [input]....

Sample end: 11/28/2018 3:29:36 PM
Elapsed time: 00:09:14.3418742

Navigieren Sie im Azure-Portal zu Ihrem Batch-Konto, um den Pool, die Computeknoten, den Auftrag und die Aufgaben zu überwachen. Um beispielsweise eine Wärmekarte der Computeknoten in Ihrem Pool anzuzeigen, wählen Sie Pools>LinuxFFmpegPool aus.

Bei der Ausführung von Aufgaben sieht das Wärmebild in etwa wie folgt aus:

Screenshot der Pool-Wärmekarte.

Die typische Ausführungszeit beträgt ungefähr 5 Minuten , wenn Sie die Anwendung in der Standardkonfiguration ausführen. Die meiste Zeit wird für die Poolerstellung benötigt.

Abrufen von Ausgabedateien

Sie können das Azure-Portal verwenden, um die ausgegebenen MP3-Dateien herunterzuladen, die durch die ffmpeg-Aufgaben generiert werden.

  1. Klicken Sie auf Alle Dienste>Speicherkonten und anschließend auf den Namen Ihres Speicherkontos.
  2. Klicken Sie auf Blobs>Ausgabe.
  3. Klicken Sie mit der rechten Maustaste auf eine der ausgegebenen MP3-Dateien, und klicken Sie anschließend auf Herunterladen. Folgen Sie den Anweisungen in Ihrem Browser, um die Datei zu öffnen oder zu speichern.

Herunterladen der Ausgabedatei

Die Dateien können auch programmgesteuert aus den Computeknoten oder aus dem Speichercontainer heruntergeladen werden. Dies wird in diesem Beispiel allerdings nicht gezeigt.

Überprüfen des Codes

In den folgenden Abschnitten ist die Beispielanwendung in die Schritte unterteilt, die ausgeführt werden, um eine Workload im Batch-Dienst zu verarbeiten. Beziehen Sie sich auf den Python-Code, während Sie den Rest dieses Artikels lesen, da nicht jede Codezeile im Beispiel besprochen wird.

Authentifizieren des Blobs und der Batch-Clients

Das Beispiel authentifiziert sich mit "Storage" und "Batch" mithilfe von DefaultAzureCredential aus dem Azure-Identity-Paket . DefaultAzureCredential versucht mehrere Anmeldeinformationstypen in der Reihenfolge (Umgebungsvariablen, verwaltete Identität, Azure CLI Anmeldung usw.), wodurch derselbe Code in der lokalen Entwicklung und in der Produktion funktioniert, ohne Kontoschlüssel zu speichern.

Um mit einem Speicherkonto zu interagieren, verwendet die App das Azure-storage-blob-Paket , um ein BlobServiceClient-Objekt zu erstellen, das die Anmeldeinformationen verwendet.

Das Beispiel importiert die folgenden Identitäts- und Speichertypen und liest die Kontonamen aus config.py:

import config
from azure.identity import DefaultAzureCredential
from azure.storage.blob import (
    BlobServiceClient,
    BlobSasPermissions,
    ContainerSasPermissions,
    generate_blob_sas,
    generate_container_sas,
)
credential = DefaultAzureCredential()

blob_service_client = BlobServiceClient(
    account_url=f"https://{config._STORAGE_ACCOUNT_NAME}.blob.core.windows.net/",
    credential=credential)

Die App erstellt ein BatchClient-Objekt zum Erstellen und Verwalten von Pools, Aufträgen und Aufgaben im Batchdienst. Der Batchclient verwendet dieselbe DefaultAzureCredential für die Authentifizierung über Microsoft Entra ID.

batch_client = BatchClient(
    endpoint=config._BATCH_ACCOUNT_URL,
    credential=credential)

Batch-Compute-Knoten greifen auf die Eingabe- und Ausgabecontainer mithilfe von Shared-Access-Signatur (SAS)-URLs zu. Da die App den Speicherkontoschlüssel nicht verwendet, kann sie damit keine SAS-Token signieren. Stattdessen fordert die App einen Benutzerdelegierungsschlüssel vom Blob-Dienst an, der mit den Microsoft Entra-Zugangsdaten der App signiert ist, und verwendet diesen Schlüssel, um die SAS-Token zu generieren. Weitere Informationen finden Sie unter Erstellen einer SAS für die Benutzerdelegierung.

start = datetime.datetime.now(datetime.timezone.utc)
expiry = start + datetime.timedelta(hours=4)
user_delegation_key = blob_service_client.get_user_delegation_key(
    key_start_time=start, key_expiry_time=expiry)

# Sign the SAS tokens with the same expiry as the user delegation key.
sas_expiry = expiry

Note

Der Benutzerdelegierungsschlüssel in diesem Beispiel ist vier Stunden gültig. Ein SAS-Token, das mit einem Benutzerdelegierungsschlüssel signiert ist, kann den Schlüssel nicht überdauern, und ein Benutzerdelegierungsschlüssel kann maximal sieben Tage gültig sein. Für langlebige Workloads fordern Sie einen neuen Schlüssel an und generieren Sie die SAS-URLs erneut, bevor sie ablaufen.

Hochladen von Eingabedateien

Nachdem sie die Eingabe- und Ausgabecontainer mit blob_service_clienterstellt hat, lädt die App jede lokale MP4-Datei im InputFiles-Ordner in den Eingabecontainer hoch. Der folgende upload_file_to_container Helfer lädt eine einzelne Datei hoch, erzeugt ein schreibgeschütztes SAS-Token dafür, das mit dem Benutzerdelegierungsschlüssel signiert wird, und gibt ein Batch ResourceFile-Objekt zurück, dessen URL das SAS-Token enthält, damit Batch die Datei später auf einen Rechenknoten herunterladen kann. Die App ruft diesen Helfer einmal für jede Eingabedatei auf:

def upload_file_to_container(blob_service_client, user_delegation_key,
                             sas_expiry, container_name, file_path):
    blob_name = os.path.basename(file_path)
    blob_client = blob_service_client.get_blob_client(container_name, blob_name)

    with open(file_path, "rb") as data:
        blob_client.upload_blob(data, overwrite=True)

    sas_token = generate_blob_sas(
        account_name=config._STORAGE_ACCOUNT_NAME,
        container_name=container_name,
        blob_name=blob_name,
        user_delegation_key=user_delegation_key,
        permission=BlobSasPermissions(read=True),
        expiry=sas_expiry)

    sas_url = f"{blob_client.url}?{sas_token}"

    return models.ResourceFile(http_url=sas_url, file_path=blob_name)

Die App erzeugt außerdem eine SAS-URL für den Ausgabecontainer, die Schreibzugriff gewährt. Die Aufgaben verwenden diese URL, um ihre Ausgabedateien in die Speicherung hochzuladen:

sas_token = generate_container_sas(
    account_name=config._STORAGE_ACCOUNT_NAME,
    container_name=output_container_name,
    user_delegation_key=user_delegation_key,
    permission=ContainerSasPermissions(write=True, create=True, list=True),
    expiry=sas_expiry)

output_container_sas_url = (
    f"https://{config._STORAGE_ACCOUNT_NAME}.blob.core.windows.net/"
    f"{output_container_name}?{sas_token}")

Erstellen eines Pools mit Computeknoten

Als nächstes erstellt die Probe einen Pool von Rechenknoten im Batch-Konto, indem sie aufruft create_pool. Diese definierte Funktion verwendet die BatchPoolCreateOptions-Klasse , um die Anzahl von Knoten, VM-Größe und eine Poolkonfiguration festzulegen. In dieser Konfiguration spezifiziert ein VirtualMachineConfiguration-Objekt eine BatchVmImageReference für ein Ubuntu Server 22.04 LTS-Image, das im Azure Marketplace veröffentlicht wurde. Batch unterstützt viele verschiedene VM-Images im Azure Marketplace und auch benutzerdefinierte VM-Images.

Die Anzahl von Knoten und die VM-Größe werden mit definierten Konstanten festgelegt. Batch unterstützt dedizierte Knoten und Spot-Knoten, und Sie können entweder einen oder beide in Ihren Pools verwenden. Dedizierte Knoten sind für Ihren Pool reserviert. Spot-Knoten werden zu einem reduzierten Preis aus überschüssiger VM-Kapazität in Azure angeboten. Spotknoten sind nicht verfügbar, wenn Azure nicht genügend Kapazität aufweist. Im Beispiel wird standardmäßig ein Pool erstellt, der nur fünf Spotknoten in der Größe Standard_A1_v2 enthält.

Zusätzlich zu physischen Knoteneigenschaften enthält diese Poolkonfiguration ein BatchStartTask-Objekt . Die BatchStartTask wird auf jedem Knoten ausgeführt, da dieser Knoten dem Pool beitritt, und jedes Mal, wenn ein Knoten neu gestartet wird. In diesem Beispiel führt BatchStartTask Bash-Shellbefehle aus, um das ffmpeg-Paket und die Abhängigkeiten auf den Knoten zu installieren.

Die create_pool-Methode sendet den Pool an den Batchdienst.

new_pool = models.BatchPoolCreateOptions(
    id=pool_id,
    virtual_machine_configuration=models.VirtualMachineConfiguration(
        image_reference=models.BatchVmImageReference(
            publisher="canonical",
            offer="0001-com-ubuntu-server-jammy",
            sku="22_04-lts",
            version="latest"
        ),
        node_agent_sku_id="batch.node.ubuntu 22.04"),
    vm_size=_POOL_VM_SIZE,
    target_dedicated_nodes=_DEDICATED_POOL_NODE_COUNT,
    target_low_priority_nodes=_LOW_PRIORITY_POOL_NODE_COUNT,
    start_task=models.BatchStartTask(
        command_line="/bin/bash -c \"apt-get update && apt-get install -y ffmpeg\"",
        wait_for_success=True,
        user_identity=models.UserIdentity(
            auto_user=models.AutoUserSpecification(
                scope=models.AutoUserScope.POOL,
                elevation_level=models.ElevationLevel.ADMIN)),
    )
)
batch_client.create_pool(pool=new_pool)

Note

Für VM-Images aus dem Marketplace und Batch-Node-Agenten gibt es Enddaten für den Support. Ubuntu Server 20.04 LTS-Images und der batch.node.ubuntu 20.04 Node-Agent werden für neue Batch-Pools nicht mehr unterstützt. Um die Bildreferenzen und Node-Agent-SKUs aufzulisten, die Ihr Batch-Konto derzeit unterstützt, rufen Sie die list_supported_images-Methode auf.

Einen Job erstellen

Für einen Batch-Auftrag werden ein Pool zum Ausführen von Aufgaben und optionale Einstellungen wie eine Priorität und ein Zeitplan für die Arbeitsschritte angegeben. Das Beispiel erstellt einen Job durch Aufrufen von create_job. Bei dieser definierten Funktion wird die BatchJobCreateOptions-Klasse verwendet, um einen Auftrag in Ihrem Pool zu erstellen. Die create_job-Methode übermittelt den Job an den Batch-Service. Zunächst hat der Job keine Aufgaben.

job = models.BatchJobCreateOptions(
    id=job_id,
    pool_info=models.BatchPoolInfo(pool_id=pool_id))

batch_client.create_job(job=job)

Aufgaben erstellen

Die App erstellt Aufgaben im Auftrag per Aufruf von add_tasks. Diese definierte Funktion erstellt eine Liste von Aufgabenobjekten mithilfe der BatchTaskCreateOptions-Klasse . Jede Aufgabe führt ffmpeg aus, um ein Eingabeobjekt resource_files mithilfe eines command_line Parameters zu verarbeiten. ffmpeg wurde zuvor bei der Erstellung des Pools auf jedem Knoten installiert. Hier wird in der Befehlszeile ffmpeg ausgeführt, um jede MP4-Eingabedatei (Video) in eine MP3-Datei (Audio) zu konvertieren.

Im Beispiel wird nach der Ausführung über die Befehlszeile ein OutputFile-Objekt für die MP3-Datei erstellt. Die Ausgabedateien jeder Aufgabe (in diesem Fall eine) werden mithilfe der Eigenschaft der Aufgabe output_files in einen Container im verknüpften Speicherkonto hochgeladen.

Anschließend werden dem Auftrag in der App mit der create_tasks-Methode Aufgaben hinzugefügt und für die Ausführung auf den Computeknoten in die Warteschlange eingereiht.

tasks = list()

for idx, input_file in enumerate(input_files):
    input_file_path = input_file.file_path
    output_file_path = "".join((input_file_path).split('.')[:-1]) + '.mp3'
    command = "/bin/bash -c \"ffmpeg -i {} {} \"".format(
        input_file_path, output_file_path)
    tasks.append(models.BatchTaskCreateOptions(
        id='Task{}'.format(idx),
        command_line=command,
        resource_files=[input_file],
        output_files=[models.OutputFile(
            file_pattern=output_file_path,
            destination=models.OutputFileDestination(
                container=models.OutputFileBlobContainerDestination(
                    container_url=output_container_sas_url)),
            upload_options=models.OutputFileUploadConfiguration(
                upload_condition=models.OutputFileUploadCondition.TASK_SUCCESS))]
    )
    )
batch_client.create_tasks(job_id=job_id, task_collection=tasks)

Aufgaben überwachen

Wenn Aufgaben einem Auftrag hinzugefügt werden, werden sie von Batch automatisch in die Warteschlange eingereiht und für die Ausführung auf Computeknoten im zugeordneten Pool eingeplant. Basierend auf den Einstellungen, die Sie angeben, führt Batch das Einreihen, Planen und erneute Ausführen sowie andere Schritte der Aufgabenverwaltung aus.

Es gibt viele Ansätze zur Überwachung der Aufgabenausführung. Die wait_for_tasks_to_complete Funktion in diesem Beispiel verwendet das BatchTaskState - Objekt, um Aufgaben für einen bestimmten Zustand zu überwachen, in diesem Fall der abgeschlossene Zustand innerhalb eines Zeitlimits.

while datetime.datetime.now() < timeout_expiration:
    print('.', end='')
    sys.stdout.flush()
    tasks = batch_client.list_tasks(job_id=job_id)

    incomplete_tasks = [task for task in tasks if
                        task.state != models.BatchTaskState.COMPLETED]
    if not incomplete_tasks:
        print()
        return True
    else:
        time.sleep(5)
...

Bereinigen von Ressourcen

Nach dem Ausführen der Aufgaben löscht die App den erstellten Eingabespeichercontainer automatisch und ermöglicht Ihnen das Löschen des Batch-Pools und -Auftrags. Die Methoden begin_delete_job und begin_delete_pool der BatchClient Klasse starten jeweils die entsprechende Löschoperation, wenn du den Prompt bestätigt. Obwohl dir für Jobs und Aufgaben selbst keine Gebühren berechnet werden, werden dir für Rechenknoten Gebühren berechnet. Daher sollten Pools nur bei Bedarf zugeteilt werden. Beim Löschen des Pools werden alle Aufgabenausgaben auf den Knoten gelöscht. Die Ausgabedateien verbleiben aber im Speicherkonto.

Löschen Sie die Ressourcengruppe, das Batch-Konto und das Speicherkonto, wenn diese Elemente nicht mehr benötigt werden. Wählen Sie dazu im Azure-Portal die Ressourcengruppe für das Batchkonto aus, und wählen Sie " Ressourcengruppe löschen" aus.

Nächste Schritte

In diesem Tutorial haben Sie Folgendes gelernt:

  • Authentifizieren mit Batch- und Storage-Konten.
  • Hochladen von Eingabedateien in Storage.
  • Erstellen eines Pools mit Computeknoten für die Ausführung einer Anwendung.
  • Erstellen eines Auftrags und von Aufgaben zum Verarbeiten von Eingabedateien.
  • Überwachen der Aufgabenausführung
  • Abrufen von Ausgabedateien.

Weitere Beispiele für die Verwendung der Python-API zum Planen und Verarbeiten von Batchworkloads finden Sie in den Batch Python-Beispielen auf GitHub.