教學課程:使用 Python API 搭配 Azure Batch 執行平行工作負載

使用 Azure Batch 在 Azure 中有效率地執行大規模的平行和高效能運算 (HPC) 批次作業。 本教學課程會逐步解說使用 Batch 執行平行工作負載的 Python 範例。 您會了解 Batch 應用程式的通用工作流程,以及如何以程式設計方式與 Batch 和儲存體資源進行互動。

  • 驗證 Batch 和儲存體帳戶。
  • 將輸入檔案上傳至儲存體。
  • 建立計算節點的集區來執行應用程式。
  • 建立作業和工作來處理輸入檔案。
  • 監控任務執行。
  • 擷取輸出檔案。

在本教學課程中,您會使用 ffmpeg 開放原始碼工具將 MP4 媒體檔案平行轉換為 MP3 格式。

如果您沒有 Azure 帳戶,請在開始之前建立 免費帳戶

先決條件

授與您的 Batch 和儲存體帳戶的存取權

這個教學展示了如何使用 Microsoft Entra ID 搭配 DefaultAzureCredential 來驗證 Azure Batch 和 Azure 儲存體。 這個應用程式不會使用帳號金鑰。 執行應用程式前,請確認你所使用的身分在兩個帳戶中皆具有必要的角色。

  1. 請使用 Azure CLI 登入。 DefaultAzureCredential 會自動偵測到這次登入:

    az login
    
  2. 為你的使用者帳號指派一個角色,允許在批次帳號上進行資料平面操作,例如 Azure Batch Data Contributor。 此角色需要建立資源池、工作與任務。 你可以在 Azure 入口網站的批次帳號存取控制(IAM)頁面上指定角色,或使用 Azure CLI:

    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. 將你的使用者帳號指定為儲存帳號上的 Storage Blob 資料貢獻者 角色。 此角色需要建立容器、上傳輸入檔案,並請求簽署任務所使用的共享存取簽章(SAS)URL 的使用者委派金鑰:

    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. 請注意以下數值,請在下一節加入樣本的 config.py 檔。 你可以在 Azure 入口網站中每個帳戶的總覽頁面找到它們:

    • 批次帳號名稱
    • 批次帳戶 URL,例如 https://mybatchaccount.westus2.batch.azure.com
    • 儲存體帳戶名稱

Note

角色指派可能需要幾分鐘才會生效。 如果應用程式在你指派角色後立刻出現授權錯誤失敗,請等幾分鐘再試一次。

下載及執行範例應用程式

Important

batch-python-ffmpeg-tutorial 倉庫中可下載的範例正在更新以符合此教學。 在該更新發布前,倉庫可能仍包含早期的基於金鑰的認證和 Ubuntu 20.04 程式碼。 本文中的程式碼是真實的來源。 如果下載的樣本與這裡的片段不符,請依照本文所示的程式碼操作。

下載範例應用程式

從 GitHub 下載或複製範例應用程式。 若要使用 Git 用戶端複製範例應用程式存放庫,請使用下列命令:

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

流覽至包含 檔案batch_python_tutorial_ffmpeg.py的目錄。

在您的 Python 環境中,使用 pip安裝必要的套件。

pip install -r requirements.txt

使用程式代碼編輯器開啟 檔案 config.py。 使用您帳戶專屬的名稱更新 Batch 和儲存體帳戶值。 範例使用 DefaultAzureCredential 來認證,因此不再需要帳號金鑰。 例如:

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

請確認你是使用 az login 登入,且你的身分具有 授與 Batch 和儲存體帳戶的存取權 中所述的角色。 DefaultAzureCredential也能發現其他憑證來源,例如管理身份、Visual Studio Code 或環境變數。

執行應用程式

執行指令碼:

python batch_python_tutorial_ffmpeg.py

當您執行範例應用程式時,主控台輸出大致如下。 在執行期間,集區的計算節點啟動後,您會在 Monitoring all tasks for 'Completed' state, timeout in 00:30:00... 遇到暫停。

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

請前往 Azure 入口網站中的 Batch 帳戶,以監視集區、計算節點、作業和任務。 例如,若要查看集區中計算節點的熱度圖,請選取 [集區]> [LinuxFFmpegPool]

當工作正在執行時,熱度圖會如下所示:

集區熱度圖的螢幕快照。

一般運行時間大約是 5 分鐘 ,當您在其預設組態中執行應用程式。 建立集區佔用大部分的時間。

擷取輸出檔案

您可以使用 Azure 入口網站來下載 ffmpeg 工作所產生的 MP3 輸出檔案。

  1. 按一下 [所有服務]>[儲存體帳戶],然後按一下您的儲存體帳戶名稱。
  2. 按一下 [Blob]> [輸出]
  3. 以滑鼠右鍵按一下其中一個 MP3 輸出檔案,然後按 [下載]。 請依照瀏覽器的提示開啟或儲存檔案。

下載輸出檔案

此範例雖未示範,但您也可以用程式設計方式從計算節點或儲存體容器下載檔案。

檢閱程式碼

後面各節將範例應用程式細分為用來處理 Batch 服務中工作負載的數個步驟。 當您閱讀本文的其餘部分時,請參閱 Python 程式代碼,因為不會討論範例中的每一行程序代碼。

驗證 Blob 和 Batch 用戶端

範例使用 DefaultAzureCredential(來自 azure-identity 套件),同時向 Storage 和 Batch 進行驗證。 DefaultAzureCredential 嘗試依序嘗試多種憑證類型(環境變數、管理身份、Azure CLI登入等),使同一程式碼在本地開發和生產環境中都能運作,且不儲存帳號金鑰。

要與儲存帳號互動,應用程式會使用 azure-storage-blob 套件來建立一個使用 credential 的 BlobServiceClient 物件。

範例匯入以下身份與儲存類型,並從 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)

應用程式會建立一個 BatchClient 物件,用來建立和管理批次服務中的池、工作與任務。 批次用戶端使用相同的 DefaultAzureCredential 透過 Microsoft Entra ID 進行認證。

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

批次運算節點透過共享存取簽章(SAS)網址存取輸入與輸出容器。 因為應用程式不使用儲存帳號金鑰,無法用它簽署 SAS 代幣。 相反地,應用程式會向 Blob 服務請求一組使用者委派金鑰,該金鑰以應用程式的 Microsoft Entra 憑證簽署,並用該金鑰產生 SAS 憑證。 如需詳細資訊,請參閱建立使用者委派 SAS

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

此範例中的使用者委派金鑰有效期為四小時。 用使用者委派金鑰簽署的 SAS 憑證無法超過金鑰的壽命,而使用者委派金鑰最多可有效七天。 對於長時間執行的工作負載,請申請新的金鑰,並在 SAS URL 到期之前重新產生 SAS URL。

上傳輸入檔案

在建立輸入和輸出容器後 blob_service_client,應用程式會將 InputFiles 資料夾中的每個本地 MP4 檔案上傳到輸入容器。 以下 upload_file_to_container 的輔助程式上傳單一檔案,產生一個只讀的 SAS 標記,該標記以使用者委派金鑰簽署,並回傳一個 Batch ResourceFile 物件,其 URL 包含 SAS 標記,讓 Batch 之後能將檔案下載到運算節點。 應用程式會對每個輸入檔案呼叫此輔助器一次:

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)

應用程式也會為輸出容器產生一個 SAS URL,授予寫入權限。 任務使用此網址將其輸出檔案上傳至儲存空間:

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}")

建立計算節點的集區

接著,範例會透過呼叫 create_pool,在 Batch 帳戶中建立計算節點集區。 此定義函式使用 Batch BatchPoolCreateOptions 類別來設定節點數量、虛擬機大小及池組態。 在此配置中,VirtualMachineConfiguration 物件指定一個 BatchVmImageReference,指向發佈於 Azure Marketplace 的 Ubuntu Server 22.04 LTS 映像。 Batch 支援 Azure Marketplace 中各式各樣的 VM 映像,以及自訂 VM 映像。

使用已定義的常數可設定節點數目和 VM 大小。 Batch 支援專用節點和現成品節點,而您可以在集區中使用其中一種或同時使用兩種。 專用節點會保留給您的集區使用。 現成品節點則會以較低的價格從 Azure 中的剩餘容量提供。 如果 Azure 沒有足夠的容量,現成節點將無法使用。 根據預設,此範例會建立集區,其大小只有五個 Spot 節點 Standard_A1_v2

除了實體節點屬性外,此池配置還包含一個 BatchStartTask 物件。 BatchStartTask 會在每個節點加入池時執行,每次節點重啟時也會執行。 在此範例中,BatchStartTask 執行 Bash shell 指令,安裝節點上的 ffmpeg 套件及依賴關係。

create_pool 方法將池提交給批次服務。

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

Marketplace 虛擬機映像檔和批次節點代理都有支援結束日期。 Ubuntu Server 20.04 LTS 映像檔及 batch.node.ubuntu 20.04 節點代理已不再支援新的批次池。 要列出你的批次帳號目前支援的映像參考和節點代理 SKU,請呼叫 list_supported_images 方法。

建立職位

Batch 工作會指定要在其中執行工作的集區及選擇性設定,例如工作的優先順序和排程。 該範例透過呼叫 create_job來建立一個工作。 此已定義的函式會使用 BatchJobCreateOptions 類別,在您的集區上建立作業。 create_job 方法會將工作提交給批次服務。 一開始這份工作沒有任何任務。

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

batch_client.create_job(job=job)

建立任務

應用程式會藉由呼叫 add_tasks 在作業中建立工作。 此定義函式使用 BatchTaskCreateOptions 類別建立任務物件清單。 每個工作都會執行 ffmpeg,以使用 resource_files 參數處理輸入command_line物件。 ffmpeg 已在先前建立集區時安裝於每個節點上。 在此,命令列會執行 ffmpeg,將每個輸入 MP4 (影片) 檔案轉換為 MP3 (音訊) 檔案。

此範例會在執行命令列之後,為 MP3 檔案建立 OutputFile 物件。 每個任務的輸出檔案(在此案例中一個)會使用任務的 output_files 屬性上傳至已連結的儲存帳戶中的容器。

接著,應用程式會用 create_tasks 方法將任務加入工作,並排隊在運算節點上執行。

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)

監視工作

當任務被新增至作業時,Batch 會自動將它們排入佇列,並排程它們在相關聯集區中的計算節點上執行。 根據您指定的設定,Batch 會處理所有工作佇列、排程、重試和其他工作管理職責。

監視工作執行的方法有很多種。 此範例中的 wait_for_tasks_to_complete 函式會使用 BatchTaskState 物件,在時限內監視任務是否處於特定狀態,在此情況下為已完成狀態。

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

清理資源

應用程式在執行工作之後,會自動刪除它所建立的輸入儲存體容器,並且為您提供用於刪除 Batch 集區和工作的選項。 類別中的 begin_delete_jobBatchClient 方法在確認提示符時各自啟動相應的刪除操作。 雖然你不需為工作和任務本身收費,但計算節點則需收費。 因此,僅依需求分配池。 當您刪除集區時,節點上的所有工作輸出也會跟著刪除。 不過,輸出檔案會保留在儲存體帳戶中。

若不再需要,可刪除資源群組、Batch 帳戶和儲存體帳戶。 若要在 Azure 入口網站中這樣做,請選取 Batch 帳戶的資源群組,然後選擇 [ 刪除資源群組]。

後續步驟

在本教程中,您將學到如何:

  • 驗證 Batch 和儲存體帳戶。
  • 將輸入檔案上傳至儲存體。
  • 建立計算節點的集區來執行應用程式。
  • 建立作業和工作來處理輸入檔案。
  • 監控任務執行。
  • 擷取輸出檔案。

如需使用 Python API 排程及處理 Batch 工作負載的更多範例,請參閱 GitHub 上的 Batch Python 範例