OOPのカプセル化の考え方を応用したTerraformディレクトリ構成の提案
はじめに
この記事は terraform Advent Calendar 2020 の17日目です。
IaCツールの1つであるTerraformのディレクトリ構成をどうするかについては、Terraformを利用しているエンジニアであれば一度は考えたことがあるのではないでしょうか。
そして、これについては先人の皆様によって様々な提案がなされてきました。
- Terraformなにもわからないけどディレクトリ構成の実例を晒して人類に貢献したい
- Terraformのディレクトリ構成の模索
- Terraformのディレクトリパターン集
- Terraformにおけるディレクトリ構造のベストプラクティス
- etc...
さて、私はCDPであったりデータ分析環境のためのS3やIAM設計に携わっています。
そんな中、以前にnoteに投稿した記事である「データ分析環境のためのaws S3設計」において、
bucketを分割するということは、責任分界点を定義するための行為
と述べました。
これについて オブジェクト指向に通ずるものがあるな... と感じました。
「Terraform上で、projectやproductといった単位でリソースをまとめ、その範囲に於ける責任を明確化し、project/product同士の関係性を定義できれば、より安全にdatalakeやDWHを構成できるのでは?」と思ったのです。
そして、これをコードで実現できないだろうか?と考えたところ、 Terraformのmodule機能が使えるのでは と思いつきました。
本記事では、 オブジェクト指向の考え方をTerraformのmodule構成に応用したディレクトリ構成 を提案します。
※私がCDPやデータ分析環境等のためのaws構成設計を主として取り組んできたため、本記事はその文脈での提案・説明となります。
ですが、きっと他のアプリケーションにも応用が効くのではないかと考えております!
提案内容
構成と、そのメリデメについて述べます。
構成
まず、構成図と構成における原則を述べます。
また、構成例として、github repositoryを公開しましたので参照ください。
構成図
(terraform)
├─ environments
│ ├─ prod # terraform コマンド実行時のroot
│ │ ├─ backend.tf
│ │ ├─ main.tf
│ │ ├─ main_shared.tf -> ../shared/main.tf
│ │ ├─ provider.tf
│ │ └─ variables.tf
│ │ └─ versions.tf -> ../shared/versions.tf
│ ├─ shared
│ │ ├─ main.tf
│ │ └─ versions.tf
│ └─ stg # terraform コマンド実行時のroot
│ ├─ backend.tf
│ ├─ main.tf
│ ├─ main_shared.tf -> ../shared/main.tf
│ ├─ provider.tf
│ ├─ variables.tf
│ └─ versions.tf -> ../shared/versions.tf
├─ modules # 汎用的なmoduleを配置
├─ projects # 分析projectごとに必要なリソースを定義
│ ├─ project_a
│ │ ├─ aws_iam.tf
│ │ ├─ aws_s3.tf
│ │ │ :
│ │ ├─ locals.tf
│ │ ├─ output.tf
│ │ └─ variables.tf
│ ├─ project_b
│ │ :
│ └─ project_z
└─ templates # 汎用的なtemplatesを配置
構成における原則
以下の原則を守ってコーディングを行います。
-
main.tf
(もっと言えばenvironments/{env}
下)にはresourceを定義しない。 - resource定義は原則
projects/{pj}
内部に書く。-
main.tf
には、定義されたproject moduleのインスタンスを定義する。 -
projects/{pj}
には、projectで必要なresourceを定義する。 - 他のprojectに存在するresourceを読みたいときは、
variable
で必要な値を受け取る。 - 外部からアクセスして良いresource(S3のread用IAM poilcyなど)を
output
として定義する。- 書き込み責任がproject内で閉じるようにするために、書き込み権限を持つIAM poilcyは
output
に定義しない。
- 書き込み責任がproject内で閉じるようにするために、書き込み権限を持つIAM poilcyは
-
構成例
projectとして datalake_sample
と adhoc_sample
を持つ例を用意しました。
adhoc_sample
のいくつかのroleは datalake_sample
のs3を参照するような構成です。
提案手法のメリット
projectの責任範囲が明確になります。
「projectにおいて何を作成するのか」
「このデータの管理はどのprojectなのか」
のかが明確になります。
また、 project間の関係性も明確化され、予期せぬアクセスを発見しやすくなります。
特に、書き込みをproject内部で閉じてしまうことで、他のprojectからの書き込み事故を防げます。
提案手法のデメリット
融通がきかない(ちょっと例外的なことをやろうとするとすぐに表現が複雑になる)という欠点があります。
例として、以下のシステムを考えます:
- 「オンプレシステムAからs3にデータを集めdatalakeを作る」 #
datalake_project
とする - 「datalakeを読んで、aws上で処理した結果をオンプレに戻す」 #
adhoc_project
とする - 「オンプレに配置するIAM userは1つにしたい」
このとき、 オンプレに配置するIAM userはどのprojectに配置するべきだろうか? という問題が生まれます。
「datalakeは別にadhoc projectを読みたいわけじゃないし...でも複雑度増すのもなぁ...」
と言った具合に悩ましいのですが、解の例として、以下のように「 dtalake_project
への書き込みを他のprojectに委譲する」というのを考えてみました。
- onpreのためにIAM userを発行するprojectを用意する #
connect_to_onpre_project
とする- iam userを作成し、出力とする
-
datalake_project
にdelegate_identities
なるvariable
を用意し、datalake_project
内部で書き込み権限を付与- 書き込みなどを委譲するidentityを渡すための引数
- この
variable
経由で、connect_to_onpre_project
で生成したiam userを渡す
実際に作成した例がありますのでご確認ください。
ちょっと複雑度が増すなぁ...と思いつつ、結局「何でもやるリソースが存在するとどうしても表現が難しくなる」というのは当然起こることなのかなと思います。
逆に、複雑なことをしようとするとコードも複雑になるため、 設計をシンプルにしようという暗黙的なパワーが働く とも言えるかもしれません。
おわりに
OOPの考え方をTerraformのmodule構成に応用したディレクトリ構成を提案しました。
責任範囲を明確化し、整理してリソースを構成するのにはとても便利な一方で、融通がきかないという欠点もあるかと思います。
また、考慮漏れもあるかと思いますので、本記事に対してのご意見・改善方法などお待ちしております!
今後もより良いTerraformのディレクトリ構成を模索していきましょう!
Author And Source
この問題について(OOPのカプセル化の考え方を応用したTerraformディレクトリ構成の提案), 我々は、より多くの情報をここで見つけました https://qiita.com/hkak03key/items/cecfe063cbb7eac15401著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .