概要
Ansible による Azure Resource Manager (ARM) リソース管理において、関連リソースの参照解決を伴う複雑なタスクを楽に作成するテクニックを紹介します。次のサービスやコンポーネントを活用します。
- Azure Resource Explorer
- Ansible ARM 汎用モジュール: azure_rm_resource, azure_rm_resource_info
-
azure_rids
フィルタプラグイン: yaegashi.ansibleplugins
この記事で紹介する手法はあまり一般的なものではありません。基礎については Azure 上の Ansible のドキュメントに丁寧な説明があるのでそちらを参照してください。
Azure Resource Explorer
Azure Resource Explorer は ARM リソースの閲覧や操作ができる、開発者向けの Web アプリです。サインインすると、Azure サブスクリプション・リソースグループのツリー構造に含まれる様々な ARM リソースを探索できます。
この Web アプリから各リソースに対して REST API が発行できて、さらにドキュメントも埋め込まれているので、眺めているだけで ARM にはどんな API があって何ができるかがだいたい把握できます。
そして Azure Resource Explorer にはなんと Ansible のサポートが組み込まれています。各リソースについている Ansible のタブを選択すると、 Ansible の ARM 汎用モジュールである azure_rm_resource と azure_rm_resource_facts (Ansible 2.9 からは azure_rm_resource_info) タスクのテンプレートが表示されます。
これによりプリミティブな ARM REST API を発行する Ansible タスクが簡単に書けるようになります。
ただし、このような REST API の発行には冪等性がないので、通常のリソース管理には使うべきではありません。たとえば Azure の DNS ゾーンを作りたいのであれば、画像にある CREATE dnsZones
タスクではなく、まずは素直に azure_rm_dnszone モジュールを使うべきでしょう。 Ansible のモジュールがサポートしていない特殊な操作が必要なときに限って利用するのがよいと思います。
Ansible ARM 汎用モジュールとリソース ID の活用
Ansible の ARM モジュールはとても充実しており、様々な種類の ARM リソースを操作できますが、各モジュールの操作対象となるリソースの指定に苦労することはないでしょうか。
たとえば VM の NIC に関連づけた NSG のルールをいじることはよくあると思いますが、その NSG の所在と名前が不明なことが多く、結果として「リソースグループ X に属する名前 Y の VM にくっついている最初の NIC にくっついている NSG のルールに OpenVPN のポート (1194) の受信許可がなければ作る」のような、関連リソースの参照を解決していく複雑なタスクを作ることになりがちです。
ARM ではリソースの所在と名前は次の形式の「リソース ID」で参照することになっています。 VM に関連づけられた NIC や NSG もこの形式で記録されています。
/subscriptions/{サブスクリプションID}/resourceGroups/{リソースグループ名}/providers/{プロバイダ名}/{リソースタイプ名}/{リソース名}/{サブリソースタイプ名1}/{サブリソース名1}/...
ARM 汎用モジュール azure_rm_resource および azure_rm_resource_info では、操作対象リソースの指定において url
パラメータでこのリソース ID が利用できます。これと Azure Resource Explorer を活用すれば、関連リソースの参照を解決するタスクの記述が簡単にできるようになります。
次は前述の VM から関連をたどって所在を得た NSG のルールを更新するタスクを記述したプレイブックです。
- hosts: localhost
connection: local
gather_facts: no
vars:
resource_group: GROUP
vm_name: VM
nsg_rules:
- name: AllowOpenVPN
priority: 200
destination_port_range: 1194
direction: Inbound
access: Allow
tasks:
- name: (1) azure_rids フィルタプラグイン読み込み
include_role:
role: yaegashi.azureplugins
- name: (2) VM リソース情報取得
azure_rm_resource_info:
resource_group: "{{resource_group}}"
provider: Compute
resource_type: virtualMachines
resource_name: "{{vm_name}}"
register: r
- name: (3) NIC リソース情報取得
azure_rm_resource_info:
url: "{{r.response[0].properties.networkProfile.networkInterfaces[0].id}}"
register: r
- name: (4) NSG ルール追加
azure_rm_securitygroup:
resource_group: "{{rid.resource_group}}"
name: "{{rid.name}}"
rules: "{{nsg_rules}}"
vars:
rid: "{{r.response[0].properties.networkSecurityGroup.id | azure_rids}}"
タスクの説明
- タスク (1) では yaegashi.azureplugins ロールを読みこんで
azure_rids
フィルタプラグインを利用可能にしています (後述)。 - タスク (2) ではリソースグループ・プロバイダ・リソースタイプ・リソース名の指定により VM リソースの情報を取得しています。
- タスク (3) では VM 情報に埋め込まれた NIC のリソース ID を使って NIC リソースの情報を取得しています。
- タスク (4) では NSG のルールを冪等操作するために azure_rm_securitygroup を利用していますが、このモジュールはリソース ID を受け付けないので、リソース ID からリソースグループとリソース名を取り出すために
azure_rids
フィルタを使用しています。
ポイント
- azure_rm_resource_info は Ansible 2.9 で azure_rm_resource_facts から名前が変わったモジュールです。 Ansible 2.9 より前のバージョンでは azure_rm_resource_facts を使用してください。
-
azure_rm_resource_info の実行結果を変数
r
に register した場合 REST API の結果はr.response[0]
に入っています。この中のオブジェクト構造は Azure Resource Explorer を参照して調べます。
次の画像は VM リソースの中身を見たものです。「VM にくっついている最初の NIC のリソース ID」はproperties.networkProfile.networkInterfaces[0].id
で参照できることがわかります。
- タスク (4) のように
vars
を使うと一時的な変数の定義ができます。わざわざset_fact
タスクを書く必要がなくなるので便利です。ただし上位のプレイブックから呼び出される場合はそこで同じ名前の変数が定義されると上書きされてしまうので注意が必要です。
Ansible azure_rids フィルタプラグイン
Ansible ARM モジュールが利用している Azure SDK for Python には parse_resource_id という関数があり、これを使うとリソース ID に含まれるリソースグループ名やリソース名といった要素を抽出することができます。この関数を Jinja2 のフィルタとして使えるようにしたのが azure_rids
です。
このフィルタプラグインは Ansible Galaxy の yaegashi.azureplugins ロールに登録していますので、これをインストールして最初に呼び出すだけで azure_rids
フィルタが使えるようになります。
次のプレイブックは、様々なリソース ID に対する azure_rids
の動作をテストするものです。
- hosts: localhost
connection: local
gather_facts: no
vars:
resource_ids:
- /subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/RG1/providers/Microsoft.Compute/virtualMachines/VM1
- /subscriptions/22222222-2222-2222-2222-222222222222/resourceGroups/RG2/providers/Microsoft.Network/virtualNetworks/VNET1/subnets/SUBNET1
- /subscriptions/33333333-3333-3333-3333-333333333333/resourceGroups/RG3/providers/Microsoft.Compute/galleries/SIG1/images/DEF1/versions/1.2.3
tasks:
- name: (1) azure_rids フィルタプラグイン読み込み
include_role:
role: yaegashi.azureplugins
- name: (2) azure_rids テスト
debug:
msg: "{{item | azure_rids}}"
loop: "{{resource_ids}}"
実行結果は次のとおりです。仮想ネットワークのサブネットや共有イメージギャラリーのバージョンのような、多段階のサブリソースを持つリソース ID でも、各サブリソースのタイプや名前が取り出せることがわかります。
PLAY [localhost] *************************************************************************************
TASK [(1) azure_rids フィルタプラグイン読み込み] ******************************************************************
TASK [(2) azure_rids テスト] ****************************************************************************
ok: [localhost] => (item=/subscriptions/11111111-1111-1111-1111-111111111111/resourceGroups/RG1/providers/Microsoft.Compute/virtualMachines/VM1) =>
msg:
children: ''
name: VM1
namespace: Microsoft.Compute
resource_group: RG1
resource_name: VM1
resource_namespace: Microsoft.Compute
resource_parent: ''
resource_type: virtualMachines
subscription: 11111111-1111-1111-1111-111111111111
type: virtualMachines
ok: [localhost] => (item=/subscriptions/22222222-2222-2222-2222-222222222222/resourceGroups/RG2/providers/Microsoft.Network/virtualNetworks/VNET1/subnets/SUBNET1) =>
msg:
child_name_1: SUBNET1
child_parent_1: virtualNetworks/VNET1/
child_type_1: subnets
children: /subnets/SUBNET1
last_child_num: 1
name: VNET1
namespace: Microsoft.Network
resource_group: RG2
resource_name: SUBNET1
resource_namespace: Microsoft.Network
resource_parent: virtualNetworks/VNET1/
resource_type: subnets
subscription: 22222222-2222-2222-2222-222222222222
type: virtualNetworks
ok: [localhost] => (item=/subscriptions/33333333-3333-3333-3333-333333333333/resourceGroups/RG3/providers/Microsoft.Compute/galleries/SIG1/images/DEF1/versions/1.2.3) =>
msg:
child_name_1: DEF1
child_name_2: 1.2.3
child_parent_1: galleries/SIG1/
child_parent_2: galleries/SIG1/images/DEF1/
child_type_1: images
child_type_2: versions
children: /images/DEF1/versions/1.2.3
last_child_num: 2
name: SIG1
namespace: Microsoft.Compute
resource_group: RG3
resource_name: 1.2.3
resource_namespace: Microsoft.Compute
resource_parent: galleries/SIG1/images/DEF1/
resource_type: versions
subscription: 33333333-3333-3333-3333-333333333333
type: galleries
PLAY RECAP *******************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
まとめ
Ansible の ARM リソース管理タスクの作成に Azure Resource Explorer や azure_rids
フィルタを活用する手法について紹介しました。
Ansible では azure_rids
のような基本機能のフィルタは標準添付になっていてほしいですし、また azure_rm_resource や azure_rm_resource_info だけでなくすべての ARM モジュールで、リソース ID を受け付ける url
パラメータを追加してくれないかなと思っています。そのうち時間を見つけて、このような改善を Ansible にコントリビュートしていきたいです。