Azure Bicep のディレクトリ構成を真剣に考えてみた

# はじめに

皆様いかがお過ごしでしょうか。
以前から Azure の IaC について少しずつ勉強しているところですが、最近はその中でも Bicep をよく触っています。そんな中業務で実践する機会を頂いたため、この機に私なりのベストプラクティスを考えようと思います。

ちなみに、Azure の IaC のツールの比較については、以前に以下の記事を出したためこちらもご覧いただけると大変嬉しいです。

https://qiita.com/s_w_high/items/534a6add2a37b172a6bb

また、Bicep を開発する際のベストプラクティスは Microsoft の公式ドキュメントにもいくつか載っています。こちらでは実際に Bicep ファイルの開発時に従うべき手法を推奨しています。

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/best-practices

そのため、Bicep ファイルの開発時は上記のベストプラクティスを見ながら開発することをお勧めします。
先程私なりのベストプラクティスを...と述べましたが、この公式ドキュメントと同じことを書いてもあまり意味がないため、今回はその Bicep 開発の中で Bicep のファイルそのものではなく、**ディレクトリ構成** にフォーカスします。
手っ取り早く結論を知りたい場合は[ディレクトリ構成のベストプラクティス](#ディレクトリ構成のベストプラクティス)をご参照ください。

私の経験即ではありますが、Java でも React でも何を始めようにもまずディレクトリはどんな構成が良いのか？とよく考えます。大抵の場合は参考になるプロジェクトを探し、それを模倣したりすることから始まりますが、今回の記事が Bicep を開発する皆様にとって意味のあるものになれば幸いです。

# Bicep とは

先程、Azure の IaC ツールについては[私の以前の記事](https://qiita.com/s_w_high/items/534a6add2a37b172a6bb)を掲載しましたが、Bicep については本記事でも簡単に紹介しておきます。

Bicep は、ARM Template の後継として Microsoft が提供している新しい DSL（Domain Specific Language）ベースの IaC ツールです。

ARM Template とは異なり、Bicep は JSON ではなく、独自のより簡潔な構文を提供しており、これにより Azure リソースの管理を容易にしています。

Bicep のコードは ARM Template にコンパイルされるため、同様に ARM REST API を通じて Azure リソースに対する操作を行います。
これにより、ARM Template と同等の Azure リソースのサポートと、新サービスや機能の迅速なサポートを実現しています。

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/overview?tabs=bicep

# ディレクトリ構成の必要性

現代のクラウドインフラ管理で IaC を用いる際、適切なディレクトリ構成とすることは非常に重要です。
Bicep に限った話ではありませんが、IaC でインフラストラクチャをコード化する場合、ディレクトリ構成が適切に設計されているか否かによって、プロジェクトのスケーラビリティ、メンテナンス、チームでの作業効率が大きく変わってきます。

## **なぜディレクトリ構成が重要か**

- **可読性と整理**

適切なディレクトリ構成は、プロジェクト内のファイルを整理し、可読性を高める助けとなります。一覧性が高まることで、特定のリソースや設定を素早く見つけ出すことができ、プロジェクト全体の理解が容易になります。
以下に簡単な例を示します。ファイルが少ない場合はシンプルな構成でも問題ありませんが、ファイルが増えた場合、適切にディレクトリを分けないと可読性が損なわれます。

```: シンプルなディレクトリ構成
/simple-project
├── main.bicep
├── variables.bicep
└── README.md
```

```: 複雑なディレクトリ構成
/complex-project
├── environments
│   ├── dev.bicepparam
│   ├── test.bicepparam
│   └── prod.bicepparam
├── modules
│   ├── vnet.bicep
│   ├── storage.bicep
│   └── compute.bicep
├── main.bicep
└── README.md
```

- **スケーラビリティと成長への対応**

プロジェクトが小規模な段階では単純な構成で問題ないかもしれませんが、プロジェクトが成長するにつれ、リソースや設定の数が増加します。
初期の段階からスケーラブルなディレクトリ構成を採用していることで、後からのリファクタリングを最小限に抑えられます。

| 構成             | シンプルなプロジェクト   | 複雑なプロジェクト                   |
| ---------------- | ------------------------ | ------------------------------------ |
| ファイル数       | 少数                     | 多数                                 |
| ファイル配置     | 単一ディレクトリ         | 環境ごと、リソース別に分割           |
| 変更の影響範囲   | 全体に影響する可能性あり | モジュールごと、環境ごとに限定される |
| スケーラビリティ | 限定的                   | 高スケーラビリティ                   |

- **チーム間の効率的な作業分担**

チームで作業を行う場合、ディレクトリ構成が適切に設計されていればファイルやリソースの担当者間での競合や混乱を防ぐことができます。
各メンバーが担当する部分が明確になり、効率的に作業を進めることができます。

```: 担当者ごとの効率的な作業分担
/project
├── environments
│   ├── dev.bicepparam  <-- 開発チーム担当
│   ├── test.bicepparam <-- テストチーム担当
│   └── prod.bicepparam <-- 本番運用チーム担当
├── modules
│   ├── vnet.bicep     <-- ネットワークチーム担当
│   ├── storage.bicep  <-- ストレージチーム担当
│   └── compute.bicep  <-- コンピュートチーム担当
├── main.bicep
└── README.md
```

## **よくあるディレクトリ構成の問題点**

- **平坦なディレクトリ構成**

すべてのファイルを単一のディレクトリに置く平坦な構成は、小規模な段階では問題ないかもしれませんが、プロジェクトが成長するにつれて管理が難しくなります。ファイルが増えると見つけにくくなり、依存関係の把握が困難になります。

- **無秩序なファイル配置**

ファイル命名が不統一であり、ディレクトリ内に無秩序に配置されている場合、特定の設定やリソースを見つけるのに時間がかかり、誤って不適切なファイルを編集してしまうリスクも高まります。

```:無秩序な構成例
/chaotic-project
├── main.bicep
├── vnet.bicep
├── config.json
├── dev.bicepparam
├── storage.bicep
└── notes.txt
```

- **環境の分離が不十分**

開発、テスト、本番などの異なる環境を管理する場合、環境ごとの設定やリソースが明確に分離されていないと、環境間の干渉や誤用が発生するリスクがあります。

```:環境分離が不十分な構成例
/poor-separation
├── main.bicep
├── dev.bicepparam
├── test.bicepparam
└── prod.bicepparam
```

## **適切なディレクトリ構成の導入による効果**

- **効率的な開発プロセス**

適切なディレクトリ構成を採用することで、開発プロセスが効率化され、設定変更やリソース追加が容易になります。これにより、新たな機能追加や問題解決の速度が向上します。

- **メンテナンス性の向上**

体系的に整理されたディレクトリ構成は、長期的なメンテナンスを容易にし、古い設定や不要なリソースの管理が容易になります。これにより、技術的負債の蓄積を防ぎます。

- **共同作業の円滑化**

明確なディレクトリ構成により、チームメンバー全員がプロジェクトの構造を理解しやすくなり、共同作業が円滑に進行します。コードレビューやペアプログラミングもスムーズに行えます。

# ディレクトリ構成のベストプラクティス

それではディレクトリ構成を検討しますが、前段で記載した通り適切なディレクトリ構成はプロジェクトやチームの規模によって異なります。
そのため、一概に今回検討したディレクトリ構成がすべてのプロジェクトにとって最適かと言えばそうではないことに留意していただきたいです。

そこで今回はある程度規模の大きい（中~大）のプロジェクトを前提とした上で、私の考える Bicep 開発における最適なディレクトリ構成を以下に示します。

```:推奨ディレクトリ構成
/root-directory
│
├── modules                  # 再利用可能なBicepモジュール
│   ├── vnet.bicep           # 仮想ネットワークの定義
│   ├── storage.bicep        # ストレージアカウントの定義
│   └── compute.bicep        # 仮想マシンの定義
│
├── templates                # デプロイ単位のBicepテンプレート
│   ├── app-infra.bicep      # アプリケーションインフラ全体の定義
│   └── data-platform.bicep  # データプラットフォーム全体の定義
│
├── parameters               # 環境ごとのパラメータファイル
│   ├── prod                 # 本番環境
│   │   ├── app-infra.bicepparam
│   │   └── data-platform.bicepparam
│   ├── stg                  # ステージング環境
│   │   ├── app-infra.bicepparam
│   │   └── data-platform.bicepparam
│   └── dev                  # 開発環境
│       ├── app-infra.bicepparam
│       └── data-platform.bicepparam
│
├── pipelines                # CI/CDパイプラインの定義
│   └── azure-pipelines.yml  # Azure Pipelinesの定義
│
├── .gitignore
└── README.md
```

## ディレクトリ構成の詳細解説

| ディレクトリ名 | 説明                                                                                                                                                                                                                                                                                  |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **modules**    | `modules` ディレクトリには、再利用可能な Bicep モジュールを格納します。<br>個別のリソース（例えば、仮想ネットワーク、ストレージアカウント、コンピュートリソースなど）を定義するためのモジュールファイルが置かれます。これらのモジュールは、テンプレートからインポートして使用します。 |
| **templates**  | `templates` ディレクトリは、デプロイメント単位で作成する Bicep テンプレートを格納します。<br>これらのテンプレートファイルは、`modules` ディレクトリで定義されたリソースを読み込み、プロジェクト全体のインフラストラクチャを定義します。                                               |
| **parameters** | `parameters` ディレクトリには、各環境ごとのパラメータファイル（`.bicepparam` ファイル）を配置します。<br>このフォルダ構成により、開発（dev）、ステージング（stg）、本番（prod）などの各環境ごとの設定を簡単に管理できます。 <rr>また、ファイル名は`templates`ディレクトリのBicepファイルと対応付けることで、可読性も向上させます。                                                          |
| **pipelines**  | `pipelines` ディレクトリには、CI/CD パイプラインの定義を配置します。<br>デプロイには該当する Bicep ファイルが必要なため、このパイプライン定義も同じプロジェクトに配置します。これにより、自動デプロイプロセスが効率化されます。                                           |

このディレクトリ構成のメリットは以下となります。

- **整理されている**: リソース、テンプレート、パラメータ、パイプラインが明確に分かれており、管理しやすい。
- **再利用性**: モジュールは再利用可能で、異なるテンプレートから簡単にインポート可能。
- **拡張性**: プロジェクトが成長しても、新しいリソースや環境を追加しやすい。
- **メンテナンス性**: 環境ごとにパラメータが分離されているため、特定の環境の設定変更が容易。

:::note

Bicep ファイルを Azure CLI を用いてデプロイする場合、以下のようなコマンドとなります。

```bash
$ az deployment group create --resource-group <リソースグループ名> --template-file <デプロイするBicepファイル（.bicep）> --parameters <パラメーターファイル（.bicepparam）>
```

そのため、上記のようなディレクトリ構成とすることで以下のようにコマンドとディレクトリ名を対応付けてわかりやすくしている点もポイントです。

- `--template-file`: `templates` ディレクトリの Bicep ファイル（`.bicep`）を指定
- `--parameters`: `parameters` ディレクトリのパラメータファイル（`.bicepparam`）を指定

:::

# おわりに

いかがでしたでしょうか。
今回は Bicep 開発にあたり、推奨するディレクトリ構成を検討してきました。
今回紹介したディレクトリ構成のベストプラクティスは、中〜大規模プロジェクトにおける Bicep 開発を効率的に行うための一つのガイドラインです。この構成を元に、自分たちのプロジェクトやチームの特性に応じて柔軟に調整することで、スケーラビリティ、再利用性、メンテナンス性が向上することを期待できるかと思います。

皆さんがこのベストプラクティスを参考にして、より良い Bicep プロジェクトを実現できることを願っています。また、プロジェクトの要件や環境の変化に応じて、このガイドラインを適宜カスタマイズし、最適なアーキテクチャを追求していただければ幸いです。

最後まで読んでいただき、ありがとうございました！