使用 Azure Batch 來執行容器工作負載
Azure Batch 可讓您在 Azure 上執行及縮放大量批次運算作業。 Batch 工作可以直接在 Batch 集區中的虛擬機器 (節點) 上執行,但您也可以將 Batch 集區設定為在節點上的 Docker 相容容器中執行工作。 本文會示範如何建立可支援執行中容器工作的運算節點集區,以及如何在集區上執行容器工作。
此處的程式碼範例使用了 Batch .NET 和 Python SDK。 您也可以使用其他 Batch SDK 和工具,包括 Azure 入口網站,來建立啟用容器的 Batch 集區,並執行容器工作。
為何要使用容器?
容器可讓您輕鬆地執行 Batch 工作,無須管理環境和相依性,即可執行應用程式。 容器會將應用程式部署為輕量型、可攜、自給自足的單位,可以在數個不同環境中執行。 例如,在本機建置及測試容器,然後將容器映像上傳至 Azure 或其他位置中的登錄。 容器部署模型可確保您應用程式的執行階段環境一律會正確地安裝和設定 (無論您的應用程式裝載在何處)。 Batch 中的容器型工作也可以利用非容器工作的功能,包括應用程式封裝和資源檔與輸出檔案管理。
必要條件
您應該要熟悉容器概念,以及如何建立 Batch 集區與作業。
SDK 版本:自以下版本起的 Batch SDK 可支援容器映像:
- Batch REST API 2017-09-01.6.0 版
- Batch .NET SDK 8.0.0 版
- Batch Python SDK 4.0 版
- Batch Java SDK 3.0 版
- Batch Node.js SDK 3.0 版
帳戶:在您的 Azure 訂用帳戶中,您需要建立 Batch 帳戶,並選擇性地建立 Azure 儲存體帳戶。
支援的虛擬機器 (VM) 映像:只有使用虛擬機器設定,透過支援的映像 (如下一節所列) 建立的集區才支援容器。 如果您提供了自訂映像,請參閱下一節中的考量,以及使用受控映像來建立自訂映像集區中的需求。
注意
從 Batch SDK 版本:
- Batch .NET SDK 16.0.0 版
- Batch Python SDK 14.0.0 版
- Batch Java SDK 11.0.0 版
- Batch Node.js SDK 11.0.0 版
目前,containerConfiguration
需要傳遞 Type
屬性,且支援的值如下:ContainerType.DockerCompatible
和 ContainerType.CriCompatible
。
請記住下列限制:
- Batch 僅針對在 Linux 集區上執行的容器提供遠端直接記憶體存取 (RDMA) 支援。
- 對於 Windows 容器工作負載,您應為集區選擇多核心 VM 大小。
重要
Docker 預設會建立網路橋接器,其子網路規格為 172.17.0.0/16
。 如果您要為集區指定虛擬網路,請確定 IP 範圍是不衝突的。
支援的 VM 映像
請使用下列其中一個支援的 Windows 或 Linux 映像,來建立適用於容器工作負載的虛擬機器計算節點集區。 如需與 Batch 相容的 Marketplace 映像詳細資訊,請參閱虛擬機器映像的清單。
Windows 支援
Batch 支援有表明支援容器的 Windows 伺服器映像。
使用 API 列出 Batch 中所有支援的映像時,如果映像支援 Docker 容器,則會指出 DockerCompatible
功能。 Batch 允許但不直接支援的是,由 Mirantis 發行的映像,其中有標記為 DockerCompatible
的功能。 這些映像只能部署在使用者訂用帳戶集區配置模式 Batch 帳戶下。
您也可以建立自訂映像,以在 Windows 上啟用容器功能。
注意
映像 SKU -with-containers
或 -with-containers-smalldisk
已遭淘汰。 如需詳細資料和替代容器執行階段選項,請參閱此公告。
Linux 支援
針對 Linux 容器工作負載,Batch 目前支援以下在 Azure Marketplace 中發佈的 Linux 映像,而不需要自訂映像。
- 發行者:
microsoft-dsvm
- 供應項目:
ubuntu-hpc
- 供應項目:
- 發行者:
almalinux
- 供應項目:
8-hpc-gen1
- 供應項目:
8-hpc-gen2
- 供應項目:
替代映像選項
目前,存在由 microsoft-azure-batch
發行、支援容器工作負載的其他映像:
- 發行者:
microsoft-azure-batch
- 供應項目:
ubuntu-server-container
- 供應項目:
ubuntu-server-container-rdma
(僅適用於使用 Infiniband 的 VM SKU)
- 供應項目:
警告
建議使用 microsoft-azure-batch
所發佈映像以外的映像,因為這些映像即將因為結束支援而淘汰。
備註
上述映像的 Docker 資料根位於不同位置:
- 針對 HPC 映像或
microsoft-dsvm
(供應項目:ubuntu-hpc
等),Docker 資料根與 Docker 預設值相同,而 Docker 預設值在 Linux 上是 /var/lib/docker,在 Windows 上是 C:\ProgramData\Docker。 這些資料夾都位於 OS 磁碟上。
針對非 Batch 發佈的映像,OS 磁碟在下載容器映像時,可能會有遭到快速填滿的風險。
客戶的可能解決方案
在 BatchExplorer 中建立集區時,變更啟動工作中的 Docker 資料根。 以下是啟動工作命令的範例:
1) sudo systemctl stop docker
2) sudo vi /lib/systemd/system/docker.service
+++
FROM:
ExecStart=/usr/bin/docker daemon -H fd://
TO:
ExecStart=/usr/bin/docker daemon -g /new/path/docker -H fd://
+++
3) sudo systemctl daemon-reload
4) sudo systemctl start docker
這些映像僅支援在 Azure Batch 集區中使用,且適用於 Docker 容器執行。 它們具有:
- 預先安裝的 Docker 相容 Moby 容器執行階段。
- 預先安裝的 NVIDIA GPU 驅動程式和 NVIDIA 容器執行階段,可簡化 Azure N 系列 VM 上的部署。
- 具有
-rdma
尾碼的 VM 映像已預先設定,並支援 InfiniBand RDMA VM 大小。 這些 VM 映像不應與沒有 InfiniBand 支援的 VM 大小搭配使用。
您也可以在與 Batch 容器相容的其中一個 Linux 散發套件上,建立與 Batch 容器相容的自訂映像。 針對自訂映像上的 Docker 支援,請安裝適當的 Docker 相容執行階段,例如 Docker 版本或 Mirantis 容器執行階段。 只安裝 Docker-CLI 相容工具是不夠的;需要 Docker 引擎相容執行階段。
重要
Microsoft 或 Azure Batch 都不支援與 Docker (任何版本或版別)、Mirantis 容器執行階段或 Moby 執行階段相關的問題。 選擇在映像中使用這些執行階段的客戶,應該就執行階段問題,向提供支援的公司或實體連絡。
使用自訂 Linux 映像的更多考量:
- 若要在使用自訂映像時利用 Azure N 系列大小的 GPU 效能,請預先安裝 NVIDIA 驅動程式。 此外,您需要安裝適用於 NVIDIA GPU 的 Docker 引擎公用程式 NVIDIA Docker。
- 若要存取 Azure RDMA 網路,請使用具備 RDMA 功能的虛擬機器大小。 必要的 RDMA 驅動程式會安裝在 Batch 支援的 CentOS HPC 和 Ubuntu 映像上。 若要執行 MPI 工作負載,則可能需要額外設定。 請參閱在 Batch 集區中使用 RDMA 或 GPU 執行個體。
Batch 集區的容器設定
若要啟用 Batch 集區以執行容器工作負載,您必須在集區的 VirtualMachineConfiguration 物件中指定 ContainerConfiguration 設定。 本文提供 Batch .NET API 參考的連結。 對應設定位於 Batch Python API。
不論是否有預先擷取的容器映像,您都可以建立啟用容器的集區,如下列範例所示。 提取 (或預先擷取) 程序可讓您從 Docker Hub 或網際網路上的另一個容器登錄預先載入容器映像。 為了達到最佳效能,請使用與 Batch 帳戶位於相同區域中的 Azure 容器登錄。
預先擷取容器映像的好處是,當工作第一次開始執行時,不必等待容器映像下載。 容器設定會在集區建立時將容器映像提取到虛擬機器中。 在集區上執行的工作接著可以參考容器映像的清單和容器執行選項。
注意
Docker Hub 會限制映像提取的數目。 請確定您的工作負載不會超過 Docker Hub 型映像的已發佈比率限制。 建議您直接使用 Azure Container Registry,或利用 ACR 中的成品快取。
沒有預先擷取容器映像的集區
若要在沒有預先擷取容器映像的情況下設定啟用容器的集區,請定義 ContainerConfiguration
和 VirtualMachineConfiguration
物件,如下列範例所示。 這些範例會使用 Marketplace 中 Azure Batch 容器集區映像的 Ubuntu Server。
附註:範例中使用的 Ubuntu 伺服器版本僅供說明之用。 請自行將 node_agent_sku_id 變更為您所使用的版本。
image_ref_to_use = batch.models.ImageReference(
publisher='microsoft-dsvm',
offer='ubuntu-hpc',
sku='2204',
version='latest')
"""
Specify container configuration. This is required even though there are no prefetched images.
"""
container_conf = batch.models.ContainerConfiguration()
new_pool = batch.models.PoolAddParameter(
id=pool_id,
virtual_machine_configuration=batch.models.VirtualMachineConfiguration(
image_reference=image_ref_to_use,
container_configuration=container_conf,
node_agent_sku_id='batch.node.ubuntu 22.04'),
vm_size='STANDARD_D2S_V3',
target_dedicated_nodes=1)
...
ImageReference imageReference = new ImageReference(
publisher: "microsoft-dsvm",
offer: "ubuntu-hpc",
sku: "2204",
version: "latest");
// Specify container configuration. This is required even though there are no prefetched images.
ContainerConfiguration containerConfig = new ContainerConfiguration();
// VM configuration
VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration(
imageReference: imageReference,
nodeAgentSkuId: "batch.node.ubuntu 22.04");
virtualMachineConfiguration.ContainerConfiguration = containerConfig;
// Create pool
CloudPool pool = batchClient.PoolOperations.CreatePool(
poolId: poolId,
targetDedicatedComputeNodes: 1,
virtualMachineSize: "STANDARD_D2S_V3",
virtualMachineConfiguration: virtualMachineConfiguration);
為容器設定預先擷取映像
若要在集區上預先擷取容器映像,請將容器映像清單 (container_image_names
,在 Python 中) 新增至 ContainerConfiguration
。
下列基本 Python 範例示範如何從 Docker 中樞預先擷取標準 Ubuntu 容器映像。
image_ref_to_use = batch.models.ImageReference(
publisher='microsoft-dsvm',
offer='ubuntu-hpc',
sku='2204',
version='latest')
"""
Specify container configuration, fetching the official Ubuntu container image from Docker Hub.
"""
container_conf = batch.models.ContainerConfiguration(
container_image_names=['ubuntu'])
new_pool = batch.models.PoolAddParameter(
id=pool_id,
virtual_machine_configuration=batch.models.VirtualMachineConfiguration(
image_reference=image_ref_to_use,
container_configuration=container_conf,
node_agent_sku_id='batch.node.ubuntu 22.04'),
vm_size='STANDARD_D2S_V3',
target_dedicated_nodes=1)
...
下列 C# 範例假設您想要從 Docker 中樞預先擷取 TensorFlow 映像。 此範例包含在集區節點上 VM 主機中執行的啟動工作。 舉例而言,您可以在主機中執行啟動工作,以掛接可以從容器存取的檔案伺服器。
ImageReference imageReference = new ImageReference(
publisher: "microsoft-dsvm",
offer: "ubuntu-hpc",
sku: "2204",
version: "latest");
ContainerRegistry containerRegistry = new ContainerRegistry(
registryServer: "https://hub.docker.com",
identityReference: new ComputeNodeIdentityReference() { ResourceId = "/subscriptions/SUB/resourceGroups/RG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/identity-name" }
);
// Specify container configuration, prefetching Docker images
ContainerConfiguration containerConfig = new ContainerConfiguration();
containerConfig.ContainerImageNames = new List<string> { "tensorflow/tensorflow:latest-gpu" };
containerConfig.ContainerRegistries = new List<ContainerRegistry> { containerRegistry };
// VM configuration
VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration(
imageReference: imageReference,
nodeAgentSkuId: "batch.node.ubuntu 22.04");
virtualMachineConfiguration.ContainerConfiguration = containerConfig;
// Set a native host command line start task
StartTask startTaskContainer = new StartTask( commandLine: "<native-host-command-line>" );
// Create pool
CloudPool pool = batchClient.PoolOperations.CreatePool(
poolId: poolId,
virtualMachineSize: "Standard_NC6S_V3",
virtualMachineConfiguration: virtualMachineConfiguration);
// Start the task in the pool
pool.StartTask = startTaskContainer;
...
從私人容器登錄中預先擷取映像
您也可以透過驗證私人容器登錄伺服器,來預先擷取容器映像。 在下列範例中,ContainerConfiguration
和 VirtualMachineConfiguration
物件會從私人 Azure 容器登錄中預先擷取私人 TensorFlow 映像。 映像參考與先前範例相同。
image_ref_to_use = batch.models.ImageReference(
publisher='microsoft-dsvm',
offer='ubuntu-hpc',
sku='2204',
version='latest')
# Specify a container registry
subscription_id = "yyyy-yyy-yyy-yyy-yyy"
resource_group_name = "TestRG"
user_assigned_identity_name = "testUMI"
resource_id = f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{user_assigned_identity_name}"
container_registry = batch.models.ContainerRegistry(
registry_server="myRegistry.azurecr.io",
identity_reference = ComputeNodeIdentityReference(resource_id = resource_id))
# Create container configuration, prefetching Docker images from the container registry
container_conf = batch.models.ContainerConfiguration(
container_image_names = ["myRegistry.azurecr.io/samples/myImage"],
container_registries =[container_registry])
new_pool = batch.models.PoolAddParameter(
id="myPool",
virtual_machine_configuration=batch.models.VirtualMachineConfiguration(
image_reference=image_ref_to_use,
container_configuration=container_conf,
node_agent_sku_id='batch.node.ubuntu 22.04'),
vm_size='STANDARD_D2S_V3',
target_dedicated_nodes=1)
// Specify a container registry
ContainerRegistry containerRegistry = new ContainerRegistry(
registryServer: "myContainerRegistry.azurecr.io",
identityReference: new ComputeNodeIdentityReference() { ResourceId = "/subscriptions/SUB/resourceGroups/RG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/identity-name" }
);
// Create container configuration, prefetching Docker images from the container registry
ContainerConfiguration containerConfig = new ContainerConfiguration();
containerConfig.ContainerImageNames = new List<string> {
"myContainerRegistry.azurecr.io/tensorflow/tensorflow:latest-gpu" };
containerConfig.ContainerRegistries = new List<ContainerRegistry> { containerRegistry } );
// VM configuration
VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration(
imageReference: imageReference,
nodeAgentSkuId: "batch.node.ubuntu 22.04");
virtualMachineConfiguration.ContainerConfiguration = containerConfig;
// Create pool
CloudPool pool = batchClient.PoolOperations.CreatePool(
poolId: poolId,
targetDedicatedComputeNodes: 2,
virtualMachineSize: "Standard_NC6S_V3",
virtualMachineConfiguration: virtualMachineConfiguration);
...
受控識別支援 ACR
存取儲存在 Azure Container Registry 中的容器時,可以使用受控識別來向服務進行驗證。 若要使用受控識別,請先確定已將身分識別指派給集區,且身分識別具有指派給您想要存取容器登錄的 AcrPull
角色。 然後,指示 Batch 向 ACR 進行驗證時要使用的身分識別。
ContainerRegistry containerRegistry = new ContainerRegistry(
registryServer: "myContainerRegistry.azurecr.io",
identityReference: new ComputeNodeIdentityReference() { ResourceId = "/subscriptions/SUB/resourceGroups/RG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/identity-name" }
);
// Create container configuration, prefetching Docker images from the container registry
ContainerConfiguration containerConfig = new ContainerConfiguration();
containerConfig.ContainerImageNames = new List<string> {
"myContainerRegistry.azurecr.io/tensorflow/tensorflow:latest-gpu" };
containerConfig.ContainerRegistries = new List<ContainerRegistry> { containerRegistry } );
// VM configuration
VirtualMachineConfiguration virtualMachineConfiguration = new VirtualMachineConfiguration(
imageReference: imageReference,
nodeAgentSkuId: "batch.node.ubuntu 22.04");
virtualMachineConfiguration.ContainerConfiguration = containerConfig;
// Create pool
CloudPool pool = batchClient.PoolOperations.CreatePool(
poolId: poolId,
targetDedicatedComputeNodes: 2,
virtualMachineSize: "Standard_NC6S_V3",
virtualMachineConfiguration: virtualMachineConfiguration);
...
工作的容器設定
若要在已啟用容器的集區上執行容器工作,請指定容器專屬設定。 設定包括要使用的映像、登錄及容器執行選項。
使用工作類別的
ContainerSettings
屬性來設定容器專屬設定。 這些設定會由 TaskContainerSettings 類別定義。--rm
容器選項不需要其他的--runtime
選項,因為這是由 Batch 負責。如果您在容器映像上執行工作,雲端工作和作業管理員工作會需要容器設定。 但是,啟動工作、作業準備工作和作業解除工作不需要容器設定 (也就是這些工作可以在容器內容中執行或直接在節點上執行)。
針對 Linux,Batch 會將使用者/群組權限對應至容器。 如果存取容器內的任何資料夾需要系統管理員權限,則您可能需要以具有管理員提高權限層級的集區範圍來執行工作。 這可確保 Batch 在容器內容中以根目錄執行工作。 否則,非系統管理員使用者可能無法存取這些資料夾。
對於已啟用 GPU 硬體的容器集區,Batch 會自動為容器工作啟用 GPU,因此您不應該包含
–gpus
引數。
容器工作命令列
當您執行容器工作時,Batch 會自動使用 docker create \(英文\) 命令,利用工作中指定的映像來建立容器。 Batch 接著會控制容器中的工作執行。
就像使用非容器的 Batch 工作,您要針對容器工作設定命令列。 由於 Batch 會自動建立容器,因此,命令列只會指定在容器中執行的一或多個命令。
以下是 Batch 套用至 Docker 容器工作的預設行為:
- Batch 會以指定的工作命令列作為 CMD 來執行容器。
- Batch 不會干擾容器映像的指定 ENTRYPOINT。
- Batch 會使用 Batch 工作的工作目錄覆寫 WORKDIR。
務必檢閱 ENTRYPOINT 與 CMD 之間的 Docker 文件,以便了解容器映像具有指定 ENTRYPOINT 時可能發生的互動效果,同時指定工作命令列。
如果您想要覆寫容器映像 ENTRYPOINT,您可以將 --entrypoint <args>
引數指定為 containerRunOption。 請參閱選用的 ContainerRunOptions,了解您可以提供給 docker create
命令的引數,Batch 會使用此命令來建立並執行容器。 例如,若要設定容器的工作目錄,請設定 --workdir <directory>
選項。
以下是容器映像和 Batch 容器選項或工作命令列及其效果的一些範例:
- 未指定容器映像 ENTRYPOINT,Batch 工作命令列為 "/bin/sh -c python myscript.py"。
- Batch 會使用指定的 Batch 工作命令列建立容器,並在 Batch 工作的工作目錄中執行容器。 如果 "myscript.py" 不在 Batch 工作的工作目錄中,則這可能會導致失敗。
- 如果工作命令列指定為 "/bin/sh -c python /path/to/script/myscript.py",則即使工作目錄設定為 Batch 工作的工作目錄 (滿足指令碼的所有相依性),此工作仍可正常運作。
- 容器映像 ENTRYPOINT 指定為 "./myscript.sh",而 Batch 工作命令列是空的。
- Batch 會建立依賴 ENTRYPOINT 的容器,並在 Batch 工作的工作目錄中執行容器。 如果容器映像 WORKDIR 與 Batch 工作的工作目錄不同,則此工作可能會導致失敗,這取決於作業系統、作業識別碼、工作識別碼等各種因素。
- 如果 "--workdir /path/to/script" 指定為 containerRunOption,則如果滿足指令碼的所有相依性,此工作可能會正常運作。
- 未指定容器映像 ENTRYPOINT、Batch 工作命令列為 "./myscript.sh",而 CONTAINERRunOptions 中的 WORKDIR 覆寫為 "--workdir /path/to/script"。
- Batch 建立工作目錄為 "/path/to/script" 的容器,並執行命令列 "./myscript.sh",此命令列會在指定的工作目錄中找到指令碼時成功執行。
容器工作工作目錄
Batch 容器工作會在容器的工作目錄中執行,與 Batch 為一般 (非容器) 工作設定的目錄類似。 如果此工作目錄設定於映像中,則不同於 WORKDIR,否則為預設的容器工作目錄 (Windows 容器上的 C:\
或 Linux 容器上的 /
)。
針對 Batch 容器工作:
- 以遞迴方式位於主機節點 (Azure Batch 目錄的根目錄) 上
AZ_BATCH_NODE_ROOT_DIR
下方的所有目錄都會對應至容器。 - 所有工作環境變數都會對應至容器。
- 節點上工作的工作目錄
AZ_BATCH_TASK_WORKING_DIR
會設定為與一般工作相同,並對應至容器。
重要
針對具有暫時性磁碟之 VM 系列上的 Windows 容器集區,由於 Windows 容器限制,整個暫時性磁碟會對應至容器空間。
這些對應可讓您以與非容器工作相同的方式來使用容器工作。 例如,使用應用程式封裝安裝應用程式、從 Azure 儲存體存取資源檔、使用工作環境設定,以及在容器停止之後保存工作輸出檔案。
不論如何為容器映像設定 WORKDIR,stdout.txt
和 stderr.txt
都會擷取到 AZ_BATCH_TASK_DIR
。
進行容器工作的疑難排解
如果您的容器工作並未如預期般執行,您可能需要取得容器映像的 WORKDIR 或進入點設定的相關資訊。 若要查看設定,請執行 docker image inspect \(英文\) 命令。
視需要根據映像來調整容器工作的設定:
- 在工作命令列中指定絕對路徑。 如果針對工作命令列使用映像的預設進入點,請確定會設定絕對路徑。
- 在工作的容器執行選項中,變更工作目錄以符合映像中的 WORKDIR。 例如,設定
--workdir /app
。
容器工作範例
下列 Python 程式碼片段顯示的基本命令列,會在從提取自 Docker 中樞之虛擬映像建立的容器中執行。 在這裡,--rm
容器選項會在工作完成之後移除容器,而 --workdir
選項會設定工作目錄。 此命令列會使用簡單殼層命令來覆寫容器進入點,以將小型檔案寫入至主機上工作的工作目錄。
task_id = 'sampletask'
task_container_settings = batch.models.TaskContainerSettings(
image_name='myimage',
container_run_options='--rm --workdir /')
task = batch.models.TaskAddParameter(
id=task_id,
command_line='/bin/sh -c \"echo \'hello world\' > $AZ_BATCH_TASK_WORKING_DIR/output.txt\"',
container_settings=task_container_settings
)
下列 C# 範例會示範雲端工作的基本容器設定:
// Simple container task command
string cmdLine = "c:\\app\\myApp.exe";
TaskContainerSettings cmdContainerSettings = new TaskContainerSettings (
imageName: "myimage",
containerRunOptions: "--rm --workdir c:\\app"
);
CloudTask containerTask = new CloudTask (
id: "Task1",
commandline: cmdLine);
containerTask.ContainerSettings = cmdContainerSettings;
下一步
- 如需有關在 Linux 上安裝和使用 Docker CE 的相關資訊,請參閱 Docker 文件。
- 了解如何使用受控映像,來建立自訂映像集區。
- 深入了解 Moby 專案,這是一個用來建立容器型系統的架構。