はじめに

第20回の「Azure Management LibraryでC#からAzureを操作する」ではC#から、第22回の「Azure Management LibraryでJavaからAzureを操作する」ではJavaから操作する方法を解説しましたが、今回は同様のアプリケーションをPythonで作成してきます。説明がやや重複する部分もでてきますが、なるべく本記事のみで理解できるよう構成しています。お時間があれば前回と対比していただくことで多様なAzureへの操作方法が提供されていることがご理解いただけると思います。

本稿での開発環境は以下の通りです。Pythonによるプログラミング経験とAzureの概要を理解している方を対象としています。

・Python 3.6.7
・Azure CLI 2.0.52
・Visual Studio Code

上記はいずれも本稿で利用したバージョンです。Python用のAzure SDKライブラリ自身は、Python 2.7 およびPython 3.xをサポートしています。また統合開発環境(IDE)としてVisual Studio Codeを利用しますが、基本的にコマンドライン等で操作しても構いません。

Azure REST APIとは

第20回の繰り返しにはなりますが簡単に説明すると、Azureには、「Azure REST API」と呼ばれるAzure自身を管理するためのAPI群が用意されており、リソースの作成、情報取得、更新、削除などの操作が提供されています。これをPythonから操作するライブラリが「Microsoft Azure SDK for Python」として提供されており、Pythonから簡易にAzureを操作することができるようになっています。

資格情報を作成する

ポータル画面からAzureを利用する場合、ブラウザからユーザーとパスワードを入力して目的のサブスクリプションにアクセスできる権限を取得できます。では、自分が作成したアプリケーションやサービス、自動化ツールからサブスクリプションを操作するためにはどのようにしたらよいでしょうか。Azureではサービスプリンシパルと呼ばれる資格情報をあらかじめ作成し、ユーザーその資格情報に対してサブスクリプションを操作する権限を割り当て、Azureを操作します。

第20回ではPowerShellにて操作を行いましたが、同様の方法はAzure CLIでも提供されているので、今回はこちらで実施します。「第18回Azureをコマンドラインツールから操作してみよう」を参考に、az loginコマンドでサブスクリプションに接続し、az account showコマンドを実行します。アカウント情報が表示されるので、サブスクリプションID(id)をメモしておきます(リスト1)。

[リスト1]アカウント情報の確認

C:\>az account show
{
  "environmentName": "AzureCloud",
  "id": " aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee ", 
  "isDefault": true,
  "name": "Visual Studio Ultimate with MSDN (MVP)",
  "state": "Enabled",
  "tenantId": "bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee",
  "user": {
  "name": "xxxxxxx@example.com",
  "type": "user"
  }
}

Azure PowerShellの例ではアプリケーションオブジェクトとサービスプリンシパルオブジェクトを別々に作成していましたが、Azure CLIでは一つのコマンドで作成可能です。

次に、az ad sp コマンドでアプリケーションオブジェクトとサービスプリンシパルオブジェクトを一括で作成します(リスト2)。password引数には任意の複雑な文字列を指定してください。

[リスト2]サービスプリンシパルオブジェクトの作成

C:\>az ad sp create-for-rbac --name mynavipythonapp --password "********"

{
  "appId": "718ac567-e615-490b-92cd-01f03e02c50b",
  "displayName": "mynavipythonapp",
  "name": "http://mynavipythonapp",
  "tenant": "bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee"
}

必要な情報は、クライアントID(appId)、クライアントシークレット(password)、テナントID(tenant)です。ここまで操作すると最終的に以下の情報が取得できているはずです。

表1:資格情報の値

名前 本稿での例
サブスクリプションID aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
テナントID bbbbbbbb-bbbb-cccc-dddd-eeeeeeeeeeee
クライアントID 718ac567-e615-490b-92cd-01f03e02c50b
クラアントシークレット(*) **********

(*)アクセスキーや、パスワードとも呼ばれます。機密情報ですので第三者に渡さないようにしてください。

ポータルから適切な権限が付与されたか確認してみます。ポータルから「サブスクリプション」一覧を開き、該当サブスクリプションを選択します。メニューから「アクセス制御 (IAM)」を選択すると、このサブスクリプションにアクセス可能なアイテム一覧が表示されます。上部のタブから「ロールの割り当て」を選択し、この中に、「mynavipythonapp」が表示されていれば正しく権限が設定されています(図1)。

  • 図1:権限の割り当て確認

    図1:権限の割り当て確認

PythonからAzureを操作する

それではファーストステップとして、これらの資格情報を利用してサブスクリプションに定義されているリソースグループ一覧を取得してみましょう。

ライブラリのインストール

ライブラリのインストールはpipコマンドを利用します。コマンドラインからリスト2を実行します。Azureの操作に必要なライブラリはいくつかに分割されていますが、以下で必要なライブラリを一括でインストールできます。パッケージの詳細は、https://pypi.org/project/azure/から確認できます。

Azureライブラリのインストール

pip install azure

利用しているOSによっては管理者権限が必要になる場合があるので、Windowsなら管理権限で実行、Linuxであればsudo経由で実行してください。

コンソールアプリの作成

任意のフォルダを作成し、Visual Studio Codeで開きます。エクスプローラーから、新規ファイル「App.py」を追加します。Pythonの拡張機能がインストールされていない場合、「Python extension for Visual Studio Code」のインストールを促されますので、インストールを選択して拡張を有効にしてください。

  • 図2:Visual Studio Codeの外観

    図2:Visual Studio Codeの外観

リソースグループ一覧を取得する

APIを通してリソースを作成する前に、疎通を兼ねてリソースグループ一覧を取得するプログラムを実行してみましょう。まずは、App.pyを以下にように書き換えます(リスト3)。

[リスト3]リソースグループの取得(App.py)

from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.resource import ResourceManagementClient

# (1) アクセス情報
SUBSCRIPTION_ID = "サブスクリプションID"
TENANT_ID = "テナントID"
CLIENT_ID = "クライアントID"
CLIENT_SECRET= "クライアントシークレット"

def main():
    # (2) 資格情報の取得
    creds = ServicePrincipalCredentials(
        client_id = CLIENT_ID,
        secret = CLIENT_SECRET,
        tenant = TENANT_ID)

    # (3) サブスクリプションIDを指定しリソースグループを操作するオブジェクトを取得
    client = ResourceManagementClient(creds, SUBSCRIPTION_ID)

    # (4) リソースグループ一覧の取得
    for rg in client.resource_groups.list():
        print("{} {}".format(rg.name, rg.location))

if __name__ == '__main__':
    main()

(1)では、先ほどメモしておいた各情報を実際の値に書き換えてください。
(2)では、それらの情報より、ServicePrincipalCredentialsオブジェクトを取得します。
(3)では、資格情報とサブスクリプションIDをもとに、リソースグループを操作するResourceManagementClientオブジェクトを取得します。
(4)では、ResourceManagementClientオブジェクトからresource_groupsプロパティを経由し、listメソッドを呼び出すことによって、リソースグループ一覧を取得しています

それでは実行してみましょう。App.pyファイルを選択しコンテキストメニューから「ターミナルでPythonファイルを実行」を選択します。正しく実行され、リソースグループの一覧が表示されたでしょうか?例外が発生する場合は、設定を再度確認してみてください。

リソースを操作するクラス

前述したとおり、ResourceManagementClientクラスは、リソースグループを操作するクラスとなります。その他にも、コンポーネントを操作するには専用のクラスが用意されています。下表に代表的なクラスを示します。

表2:Azureを操作するための代表的なクラス

クラス名 説明
ComputeManagementClient クラウドサービスや仮想マシンを操作するクラス
NetworkManagementClient 仮想ネットワーク
RedisManagementClient Redisキャッシュを操作するクラス
ResourceManagementClient リソースグループを操作するクラス
SqlManagementClient SQLデータベースを操作するクラス
WebSiteManagementClient WebAppsを操作するクラス

仮想マシンを作成する

正しくAzureの情報を取得できたところで、次に仮想マシンの作成、操作をしてみましょう。あらかじめ作成する仮想マシンのパラメーターを決めておきます(表3)。

表3:仮想マシンのパラメーター一覧

リソース 名前
ロケーション 東日本
リソースグループ名 mynavipython
仮想ネットワーク mynavipythonvnet 10.0.0.0/16
サブネット subnet 10.0.1.0/24
仮想マシン名 mynavipython-vm
仮想マシンのOS Ubuntu 16.04 LTS
仮想マシンのサイズ Basic_A1
仮想マシンのDNS名 mynavipython-vm(Azureリージョンで一意)

先ほどの同様にApp1.pyを新規に作成し、プログラムをリスト4どおりに入力します。ただし、VM作成時に指定するDNS_NAME変数の値はDNS名の一部となるため、リージョンで一意な名前が必要です。またADMIN_PASSWORD変数は管理者パスワードとして利用されます。要件にあったパスワードを設定してから実行してください。

[リスト4]仮想マシンの作成(App1.py)

from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.resource import ResourceManagementClient

SUBSCRIPTION_ID = "サブスクリプションID";
TENANT_ID = "テナントID";
CLIENT_ID = "クライアントID";
CLIENT_SECRET= "クライアントシークレット";

# (1) リソース情報の定義
GROUP_NAME = "mynavipython"
LOCATION = "japaneast"
VNET_NAME = "mynavipythonvnet"
SUBNET_NAME = "subnet"
VM_NAME  = "mynavipython-vm"
DNS_NAME = "mynavipython-vm"

ADMIN_USER  = "azureuser"
ADMIN_PASSWORD = "**********"

def main():

    creds = ServicePrincipalCredentials(
        client_id=CLIENT_ID, secret=CLIENT_SECRET, tenant=TENANT_ID)

    # (2) 各コンポーネントを操作するオブジェクトを取得
    resourcegroup_client = ResourceManagementClient(creds, SUBSCRIPTION_ID)
    network_client = NetworkManagementClient(creds, SUBSCRIPTION_ID)
    compute_client = ComputeManagementClient(creds, SUBSCRIPTION_ID)

    # (3) リソースグループの作成
    resourcegroup_client.resource_groups.create_or_update(
        GROUP_NAME,  {'location': LOCATION})

    # (4) 仮想ネットワークの作成
    async_vnet_creation = network_client.virtual_networks.create_or_update(
        GROUP_NAME,
        VNET_NAME,
        {
            'location': LOCATION,
            'address_space': {
                'address_prefixes': ['10.0.0.0/16']
            }
        })
    async_vnet_creation.wait()

    # (5) サブネットの作成
    async_subnet_creation = network_client.subnets.create_or_update(
        GROUP_NAME,
        VNET_NAME,
        SUBNET_NAME,
        {'address_prefix': '10.0.1.0/24'})
    async_subnet_creation.wait()

    # (6) IPアドレスの割り当て
    async_pip_creation = network_client.public_ip_addresses.create_or_update(
        GROUP_NAME,
        'myIPAddress',
        {
            'location': LOCATION,
            'public_ip_allocation_method': 'Dynamic',
            'dns_settings': {'domain_name_label': DNS_NAME}
        })
    async_pip_creation.wait()

    # (7) ネットワークインタフェースの作成
    async_nic_creation = network_client.network_interfaces.create_or_update(
        GROUP_NAME,
        'myNic',
        {
            'location': LOCATION,
            'ip_configurations': [{
                'name': 'myIPConfig',
                'public_ip_address': async_pip_creation.result(),
                'subnet': async_subnet_creation.result()
            }]
        })
    async_nic_creation.wait()

    # (8) 仮想マシンの作成
    vm_params = {
        'location': LOCATION,
        'os_profile': {
            'computer_name': VM_NAME,
            'admin_username': ADMIN_USER,
            'admin_password': ADMIN_PASSWORD
        },
        'hardware_profile': {
            'vm_size': 'BASIC_A1'
        },
        'storage_profile': {
            'image_reference': {
                'publisher': 'Canonical',
                'offer': 'UbuntuServer',
                'sku': '16.04.0-LTS',
                'version': 'latest'
            },
        },
        'network_profile': {
            'network_interfaces': [async_nic_creation.result()]
        },
    }
    async_vm_creation = compute_client.virtual_machines.create_or_update(
        GROUP_NAME, VM_NAME, vm_params)
    async_vm_creation.wait()

if __name__ == '__main__':
    main()

少々時間はかかりますが、仮想マシンが作成されますので、ポータルで確認してみましょう(図4)

  • 仮想マシン作成後のポータル

    図3 仮想マシン作成後のポータル

C#やJavaの例と比較すると、Python SDKによる仮想マシン作成はやや冗長な感じがしますが、これはFluent APIが用意されていないためです。Python SDKはAzure REST APIとほぼ一対一に対応したAPI構造となっています。それではプログラムの中身について説明していきます。

(1)繰り返し利用する各種リソース名を定義しています。
(2)各コンポーネントを操作するオブジェクトを取得します。ここではネットワークと仮想マシンを操作するため、新たにNetworkManagementClientとComputeManagementClientオブジェクトを取得します。
(3)create_or_updateメソッドでリソースグループを作成します。Python SDKではリソースの作成および更新、どちらにおいてもこのメソッドを利用します。作成と更新では、当然渡すパラメーターは異なりますが、作成時に必要な情報がない場合などは適宜例外が発生します。
(4)~(7)順番に仮想マシンに必要なリソースを作成していきます。ここでは、仮想ネットワーク、サブネット、パブリックIPアドレス、ネットワークインタフェースを作成しています。時間のかかる操作でのcreate_or_updateメソッドは基本的に非同期実行です。そのため、返却値としてPollingオブジェクトが返されます。waitメソッドを呼び出して作成を待機することで待ち合わせでき、実行結果はresultメソッドで取得できます。
(8)最後に仮想マシンの作成です。パラメーターがやや複雑ですが、ユーザー情報、VMサイズ、仮想マシンイメージ、ネットワークインタフェースの情報を渡しています。

最後にSSHで仮想マシンにログインしてみましょう。管理ポータルの仮想マシン画面から「接続」を選択すると、右側にssh接続情報が表示されます(図4)。

  • 図4:SSHでの仮想マシンへの接続

    図4 管理ポータルのssh接続情報

適宜ターミナルを開いて仮想マシンにたいして、ssh接続してみましょう(図5)。接続できれば正しく仮想マシンが作成されています。

  • 図5 SSHでの仮想マシンへの接続

情報取得、停止、開始などの操作を行う

仮想マシンが作成できたところで、仮想マシンの情報を取得、停止や開始などの操作を行ってみたいと思います。

前述したとおりComputeManagementClientクラスが仮想マシンを操作するクラスとなります。例えば、リソースグループ名と仮想マシン名を指定してvirtual_machines.getメソッドを呼び出すと、目的の仮想マシンのインスタンスを取得できます。まずは、このインスタンスから代表的な情報を表示してみましょう(リスト5)。

仮想マシンの情報取得(App2.py)

from azure.common.credentials import ServicePrincipalCredentials
from azure.mgmt.compute import ComputeManagementClient
from azure.mgmt.resource import ResourceManagementClient

SUBSCRIPTION_ID = "サブスクリプションID";
TENANT_ID = "テナントID";
CLIENT_ID = "クライアントID";
CLIENT_SECRET= "クライアントシークレット";

GROUP_NAME = "mynavipython"
VM_NAME  = "mynavipython-vm"

def main():
    creds = ServicePrincipalCredentials(
        client_id = CLIENT_ID,
        secret = CLIENT_SECRET,
        tenant = TENANT_ID)

    compute_client = ComputeManagementClient(creds, SUBSCRIPTION_ID)

    # (1) 仮想マシン情報の取得
    vm = compute_client.virtual_machines.get(GROUP_NAME, VM_NAME, expand='instanceView')
    print('コンピュータ名   {}'.format(vm.name))
    print('ロケーション     {}'.format(vm.location))
    print('管理者ユーザー     {}'.format(vm.os_profile.admin_username))
    print('仮想マシンサイズ {}'.format(vm.hardware_profile.vm_size))
    print('DISKサイズ       {}'.format(vm.storage_profile.os_disk.disk_size_gb))
    print('ステータス0      {} {}'.format(vm.instance_view.statuses[0].code, vm.instance_view.statuses[0].display_status))
    print('ステータス1      {} {}'.format(vm.instance_view.statuses[1].code, vm.instance_view.statuses[1].display_status))
    print('OS Publisher {}'.format(vm.storage_profile.image_reference.publisher))
    print('OS Offer     {}'.format(vm.storage_profile.image_reference.offer))
    print('OS Sku       {}'.format(vm.storage_profile.image_reference.sku))
    print('OS Version   {}'.format(vm.storage_profile.image_reference.version))

if __name__ == '__main__':
    main()

以下のような結果が得られます。プロパティの意味については後ほど紹介するAPIリファレンスで確認できます。

[リスト6]仮想マシン情報の結果

コンピュータ名   mynavipython-vm
ロケーション     japaneast
管理者ユーザー   azureuser
仮想マシンサイズ BASIC_A1
DISKサイズ       30
ステータス0      ProvisioningState/succeeded Provisioning succeeded
ステータス1      PowerState/running VM running
OS Publisher Canonical
OS Offer     UbuntuServer
OS Sku       16.04.0-LTS
OS Version   latest

次にdeallocateメソッドを呼び出してみましょう。これで仮想マシンを停止(課金されない状態)することができます(リスト7)。ポータルで仮想マシンの状態を確認し、停止済み(割り当て解除)と表示されていることが確認できます。

[リスト7]仮想マシンの停止

    async_vm_deallocation = compute_client.virtual_machines.deallocate(GROUP_NAME, VM_NAME)
    async_vm_deallocation.wait()

開始するにはStartメソッドを呼びます(リスト8)

[リスト8]仮想マシンの開始

    async_vm_start = compute_client.virtual_machines.start(GROUP_NAME, VM_NAME)
    async_vm_start.wait()

このほかにも、おおよそポータルから取得できる項目や操作はAPIを通して実行可能です。

さらに詳しい情報が欲しい場合は、「APIリファレンス」を参考にしてください。

まとめ

3回に渡ってC#、Java、Pythonと異なる言語にてAzureを操作する方法を説明してきました。このことからも分かるようにAzureは決してプロプライエタリなものではなく、オープンなクラウドであるとこがご理解いただけたのではないかと思います。これらを活用し専用のAzureツールを作成することで、開発や運用効率を高めていくことができます。

WINGSプロジェクト 森島政人著/山田祥寛監修
<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中