AzureでInfrastructure as Codeするときの設計を考える

Azure上で簡単なWebシステムを作るにあたって
リソースグループとARMテンプレートの分け方について考えてみたのでまとめようと思います。

まずは簡単に基本知識のまとめから。

# リソースグループについて

Azureを語る上でまず最初に出てくるのがリソースグループという概念。
複数のリソースを仮想的なグループにまとめられます。
ネットワーク的な意味合いはなく、あくまで管理上のグループであり、
Azure上の全てのリソースは、必ず何かしらのリソースグループに所属しなければなりませんが、複数のリソースグループに所属することはできません。
リソースグループ自体も入れ子にすることはできません。

# リソースについて
ここで言うリソースとはAzure上で作られるサービスや設定などの1つ1つを意味します。
AppServiceを1つ立てるにしても
- AppServicePlan
- Webapps
- WebAppsのConfig
- AplicationInsghts(任意)
などなど複数のリソースが作られます。

# ARMテンプレートについて
ARMテンプレートはAzureでInfrastructure as Codeを実現するために公式で提供されている機能で、TerraformやCloudFormationのようなものです。
JSON形式でリソースと変数を定義します。

```テンプレートの大枠
{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {},
    "variables": {},
    "resources": [],
    "output": []
}
```
- parameters …変数の型やデフォルト値などの定義
- variables …定数の宣言、変数の加工(文字連結やキャストなど)
- resources …リソースの定義(リソースの分けは結構細かい)
- output …デプロイ完了時の戻り値を定義(立てたVMのIPアドレスとか返してあげると便利)

# ARMテンプレートのデプロイ仕様について

テンプレートからデプロイする際は以下のようなコマンドを実行します。

```bash:ARMテンプレートのデプロイ
az group deployment create \
--name "デプロイ名" \
--resource-group "リソースグループ" \
--template-file "テンプレートファイル" \
--parameters "パラメータファイル"
--mode "デプロイモード(任意)"
```
デプロイには必ずリソースグループを指定します。
このリソースグループがデプロイ対象になるわけですが、実行モードが2種類存在します。

- Incremental(増分モード) …テンプレートに書かれていないリソースは**残る**
- Complete（完全モード）…テンプレートに書かれていないリソースは**消える**

大まかに言うとこの差しかないですが、これは管理上大きな違いになります。

例えば、
ポータル画面からテンプレートに書かれていないリソースを作っていた場合、
差分モードだとポータルから作ったリソースは消えませんが、
完全モードでデプロイすると消えてしまいます。
これを「意図しない変更が発生してしまうリスク」という捉え方もできますが、
「実際の構成とコードが完全に一致する」と捉えると大きなメリットだと言えます。

ここまでが基礎知識のおさらいです。

# リソースグループとテンプレートの構成

ここからが本題。

例として、よくある3層アーキテクチャのシステムを作りたいとします。

リソースグループとテンプレートをどう分けるかについて3案考えてみました。


**案1: 全体を1つのリソースグループにして、１つのテンプレートで管理**

![名称未設定ファイル.png](https://qiita-image-store.s3.amazonaws.com/0/79236/3d1dd93b-c3e4-2238-1e8d-527dea94b451.png)

<font color="Blue">メリット:
・リソースグループが1つなので権限管理が楽</font>
<font color="Red">デメリット：
・テンプレートの可読性が落ちる。
・パラメータ数255個制限を気にしないといけない</font>

なぜか"parameters"に指定できる変数は255個までという制限があるので、
それに引っかからないかどうかは設計前に見積もりが必要そうです。

**案2: 全体を１つのリソースにして、3つのテンプレートに分ける。**
これは、1つの親テンプレートから3つの子テンプレートを呼ぶことで実現でき、
Azureの書籍（Microsoft Azure実践ガイド）でサンプルとして載っていた方法です。
https://github.com/ToruMakabe/ImpressAzureBook

![名称未設定ファイル (1).png](https://qiita-image-store.s3.amazonaws.com/0/79236/b757b76f-fd7d-0938-8c0d-79eff3745890.png)

<font color="Blue">メリット：
・リソースグループが1つなので権限管理が楽
・テンプレートが別れるので可読性を維持できる</font>
<font color="Red">デメリット：
・完全モードで実行できないため、変更管理が大変</font>

この方法は、デプロイ実行時に親テンプレートを指定しますが、
内部的には子テンプレートをそれぞれ別に実行することになります。
そのため、完全モードを指定すると、最後に呼ばれた子テンプレートでリソースグループ全体が上書きされてしまうため、差分モードでしか使えません。(そもそも完全モードで実行しようとするとnestedは使えないよというエラーになりました)


**案3: 3つのリソースグループに分け、それぞれテンプレート化する。**

リソースグループとテンプレートの関係性は案1と同じですね。

![名称未設定ファイル (2).png](https://qiita-image-store.s3.amazonaws.com/0/79236/17268464-b547-4eac-d231-21f34315450b.png)

<font color="Blue">メリット：
・テンプレートの可読性が維持できる
・テンプレートそれぞれでデプロイでき変更管理がいくらか楽</font>
<font color="Red">デメリット：
・テンプレート間で依存関係がある場合は、デプロイ順に気をつけないといけない。
・リソースグループごとに権限管理を別々にやらないといけない。</font>

Azure公式ドキュメントによると、
「リソースグループ内のすべてのリソースで、同じライフサイクルを共有する必要がある。 つまり、グループとして同じライフサイクルで、リソースをデプロイ、更新、削除する手法にする必要があります」
とあるのでWEB,API,DBと別々に変更管理するなら、これが正攻法なのかな？と思います。
https://docs.microsoft.com/ja-jp/azure/architecture/cloud-adoption-guide/adoption-intro/resource-group

ただ、ビジネス上の運用の観点からすると、リソースグループが複数別れて権限管理が面倒になるのはかなりのデメリットではないでしょうか。


# 考えてみた結果と感想

どれも一長一短あるので、
作ろうとしているシステムのリソース数や複雑さ、システム特性、デプロイサイクルの単位、運用ルールなどによってどれを採用するか変わって来そうです。

今回、私の場合は案1を採用しました。
私用の環境であること。PaaSの構成であり複雑度が低いこと、
また、変数も255個を超えそうにないことから１枚岩のモノシリックなテンプレートにしてしまいました。

また、ビジネスの現場では、Completeモードで運用しないと後々困るのでは？と思っています。
例えば、緊急の対応でポータルから設定を追加/変更したり、テンプレートの存在を理解していない人が新しいリソースを勝手に作ってしまう等が考えられますが、変更管理ができていないと実態とテンプレートに乖離が増えて形骸化していく恐れがあります。(正直ちょっとした変更ならポータルからポチポチする方が楽だったりしますよね)

これも運用ルールによって変わってくるので難しいですが、
テンプレートからしかデプロイできないようにするのか、
手動変更を許可するが、テンプレートへの反映を必ず行うようにするのか、
テンプレートでの運用は諦めるのか…
悩ましいところです。


# 2018/12/13追記
その後、MSの方や、MS Tech Summitに登壇してるような方に話を聞く機会があったり、
自分でも運用を考えていく中で、一つの結論に辿りつきました。
「完全モードやっぱつれぇわ・・」
間違ってリソースを消してしまうリスクに怯えながら運用するのは耐えられませんでした。

なので初期構築フェーズは完全モードで良いですが、
運用構築フェーズでは増分モードが良いと思います。