(仮) ブログ

主にWeb Apps や、Azure PaaS サービス を使う際に役立ちそうなことを書こうと思っています。

Azure Batch で Docker コンテナと Python を利用する

先日、Azure Batch で Docker コンテナを利用したのですが、結構大変で気が遠くなったので書いておこうと思います。

目次

Azure Batchとは ?

Azure Batchは仮想マシンと Azure Storage Blob を利用したサービスで、Azure Batch を利用することで大規模な並列計算を行うことができます。 ただ、、設定して使えるようになるまでの道のりがめちゃくちゃ長い、、簡単にコンテナを使いたいなら、Batch Shipyard の方が簡単でした。。。

docs.microsoft.com

Docker コンテナとの連携

この Azure Batch ですが、これまでは動的に作成した VM 上で、必要なパッケージをインストールしたりと、Batch 上で実行するアプリケーションの依存関係を管理する必要がありました。

しかし、下記ドキュメントのように設定を行うことで、Docker コンテナ上で Azure Batch のタスクを実行できるようになります。 Docker コンテナをあらかじめ作っておくことで、VM の環境に左右されずにタスクの実行ができます。

docs.microsoft.com

ドキュメント内にも書いてありますが、Linux ベースの Docker コンテナを利用するためには、あらかじめ下記の設定を行う必要があります。

  • Docker が実行可能な Ubuntu 16.04 LTS または CentOS 7.3 の VM のカスタム イメージを作る
  • Batch のジョブ実行時にAzure Active Directory を使用して認証する

是非、Docker コンテナと Batch を使って欲しいのでそれぞれに関して下記について説明します。

Docker が実行可能な Ubuntu 16.04 LTS または CentOS 7.3 の VM のカスタム イメージを作る

Azure ポータルから VM を作ってカスタム イメージを作る方法が簡単です。 下記のドキュメントから Azure CLI を使ってカスタム イメージを作ってください。

docs.microsoft.com

カスタム イメージを作る前に、OS に Docker CEをインストールしておきましょう。

docs.docker.com

作成が終わったら、カスタム イメージのリソース ID を保存しておきましょう。

Batch のジョブ実行時にAzure Active Directory を使用して認証する

Azure Batch がカスタム イメージの VMを利用するためには、既定の共有キー認証ではなく Azure Active Directory 認証を利用する必要があります。 下記のドキュメントに従って設定しましょう。

docs.microsoft.com

これで準備が整いました。Docker コンテナを利用できるよう Pythonスクリプトを作成します。

Azure Batch × Docker × Python

今回は、下記のドキュメントのチュートリアルの内容を、Docker コンテナ上で同じように動作させるよう設定します。

docs.microsoft.com

Docker コンテナを利用するためには、このチュートリアルのコードを変更する必要があります。 具体的には下記の部分を追加/変更します。

  • Batch サービスの認証に Azure Active Directory を利用する
  • ImageReference クラスで カスタムイメージを利用するように設定する
  • Docker コンテナをプリフェチするよう設定する
  • タスク向けにコンテナの設定を行う

Batch サービスの認証に Azure Active Directory を利用する

通常は、SharedKeyCredentials を利用して認証を行いますが、今回はカスタムイメージを利用するので、ServicePrincipalCredentials による認証を行います。 サンプルスクリプト内の SharedKeyCredentials の部分を ServicePrincipalCredentials へ変更しましょう。

# SharedKeyCredentials

from azure.batch import BatchServiceClient
from azure.batch.batch_auth import SharedKeyCredentials

credentials = SharedKeyCredentials(BATCH_ACCOUNT_NAME, BATCH_ACCOUNT_KEY)
batch_client = BatchServiceClient(
    credentials,
    base_url=BATCH_ACCOUNT_URL
)

↓

# ServicePrincipalCredentials

from azure.batch import BatchServiceClient
from azure.common.credentials import ServicePrincipalCredentials

credentials = ServicePrincipalCredentials(
    client_id=CLIENT_ID,
    secret=SECRET,
    tenant=TENANT_ID,
    resource="https://batch.core.windows.net/"
)
    batch_client = BatchServiceClient(
    credentials,
    base_url=BATCH_ACCOUNT_URL
)

ImageReference クラスで カスタムイメージを利用するように設定する

チュートリアルでは、サンプルコードの 219 行目あたりで、helper 関数を利用して MarketPlace 上のイメージを取ってくるように記述されてます。 これを変更して、ImageReference クラスでカスタムイメージを利用するように変更しましょう。今回は Ubuntu Server 16.04 LTS からカスタムイメージを作ったので、SKU は Ubuntu です。

IMAGE はカスタムイメージのリソース ID になります。仮想マシンのイメージは同リージョン、同サブスクリプション上に配置されている必要があります。

sku_to_use, image_ref_to_use = \
    common.helpers.select_latest_verified_vm_image_with_node_agent_sku(
        batch_service_client, publisher, offer, sku)
user = batchmodels.AutoUserSpecification(
    scope=batchmodels.AutoUserScope.pool,
    elevation_level=batchmodels.ElevationLevel.admin)
new_pool = batch.models.PoolAddParameter(
    id=pool_id,
    virtual_machine_configuration=batchmodels.VirtualMachineConfiguration(
        image_reference=image_ref_to_use,
        node_agent_sku_id=sku_to_use),
    vm_size=_POOL_VM_SIZE,
    target_dedicated_nodes=_POOL_NODE_COUNT,
    start_task=batch.models.StartTask(
        command_line=common.helpers.wrap_commands_in_shell('linux',
                                                               task_commands),
        user_identity=batchmodels.UserIdentity(auto_user=user),
        wait_for_success=True,
        resource_files=resource_files),
)

↓

  
    user = batchmodels.AutoUserSpecification(
        scope=batchmodels.AutoUserScope.pool,
        elevation_level=batchmodels.ElevationLevel.admin)
    new_pool = batch.models.PoolAddParameter(
        id=pool_id,
        virtual_machine_configuration=batchmodels.VirtualMachineConfiguration(
            image_reference=batchmodels.image_reference.ImageReference(
                virtual_machine_image_id=IMAGE
            ),
            node_agent_sku_id="batch.node.ubuntu 16.04",
            container_configuration=CONTAINER_CONFIG),
        vm_size=_POOL_VM_SIZE,
        target_dedicated_nodes=_POOL_NODE_COUNT,
        start_task=batch.models.StartTask(
            command_line=common.helpers.wrap_commands_in_shell('linux',
                                                               task_commands),
            user_identity=batchmodels.UserIdentity(auto_user=user),
            wait_for_success=True,
            resource_files=resource_files,
            container_settings=CONTAINER_TASK),
)

Docker コンテナをプリフェチするよう設定する

上記のコードですでにでていますが、コンテナをプリフェッチするためには、VirtualMachineConfiguration クラスで container_configuration に、ContainerConfiguration クラスを指定する必要があります。

Docker Hub から引っ張ってくる場合はこんな感じ

CONTAINER_IMAGE = "test/image"

CONTAINER_CONFIG = batchmodels.container_configuration.ContainerConfiguration(
    container_image_names=[CONTAINER_IMAGE])

Azure Container Registry から引っ張ってくる場合はこんな感じ

CONTAINER_IMAGE = "yourregistry.azurecr.io/image"
CONTAINER_USER = "yourregistory"
CONTAINER_PASS = "yourpassword"
CONTAINER_HOST = "yourregisty.azurecr.io"

CONTAINER_REGISTRY = batchmodels.container_registry.ContainerRegistry(
    user_name=CONTAINER_USER,
    password=CONTAINER_PASS,
    registry_server=CONTAINER_HOST)

CONTAINER_CONFIG = batchmodels.container_configuration.ContainerConfiguration(
    container_image_names=[CONTAINER_IMAGE],
    container_registries=[CONTAINER_REGISTRY])

この CONTAINER_CONFIG をcontainer_configuration に設定します。

タスク向けのコンテナ設定を行う

最後に各タスク向けのコンテナの設定を行います。スタートタスクには不要ですが上記コードでは一応入れてみました。 チュートリアルだとこのあたりになります。

# 新しく追加するコード

CONTAINER_TASK = batchmodels.task_container_settings.TaskContainerSettings(
    container_run_options="--rm",
    image_name=CONTAINER_IMAGE
)

# チュートリアルの 329 行目あたり

tasks.append(batch.models.TaskAddParameter(
            'topNtask{}'.format(idx),
            common.helpers.wrap_commands_in_shell('linux', command),
            resource_files=[input_file],
            container_settings=CONTAINER_TASK
            )

最後に実行、、!

これでやっと準備完了です。。長い道のりでしたね。あとは、Python がインストールされた適当なコンテナを作ってチュートリアルを試してみてください。 Docker コンテナが使えると、今までスタートタスクで必要なソフトをインストールしていましたが、その手間も省けるので、Batch 利用がもっと簡単になりそうです。