Terraformを2ヶ月学んで覚えたことを自分なりにoutputする(応用編)

## 使用バージョン
- v0.12.16

## 目次
- remote stateについて
- 構造化について
- Standard Module Structurenについて
- コンポーネント化について
- 便利ツールについて
- 参考にするべきサイト

## remote stateについて

tfstateは通常､各プロジェクトに作られるが､providerのストレージに保存することもできる
この機能を使って外部に保存している他のterraformのリソースのoutputを参照し､利用することが可能｡
terraformで作成したリソースについては基本remote stateを参照することをおすすめする｡

```
// 自身のリモートステートの置き場所を設定する
terraform {
  backend "s3" {
    region = "ap-northeast-1"
    bucket = "dev-hoge-terraform"
    key    = "hoge-app.tfstate"
  }
}
```


```
// 参照したいリモートステートを取得する
data "terraform_remote_state" "vpc" {
  backend = "s3"

  config = {
    region = "ap-northeast-1"
    bucket = "dev-hoge-terraform"
    key    = "hoge-vpc.tfstate"
  }
}
```

```
// 使用例
resource "aws_security_group" "hoge_sg" {
	vpc_id = data.terraform_remote_state.vpc.outputs.vpc_id
  name   = "hoge-security-group"
}
```

## 構造化について

Terraformを以下のような単一のファイルで書こうとすると､ファイルが肥大化するに従って､内容の見通しが悪くなってしまい､メンテナンス性が落ちてしまう｡

```
hoge-terraform/
└── main.tf
```

なので､以下のようにリソース以外の定義を別ファイルに分離する

```
hoge-terraform/
├── main.tf // resourceを格納するtfファイル
├── outputs.tf // 出力値(output)のみを格納するtfファイル
└── variables.tf // 入力値(variable)のみを格納するtfファイル 
```

少しはきれいになったが､プロジェクトが大きくなってしまうと､これだけでは内容の見通しが悪くなる｡
そこで､複数リソースをmoduleで分離していく

```
hoge-terraform/
├── main.tf
├── modules
├── outputs.tf
├── rds // rdsに関連するリソースを格納する
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
├── security_groups // security_groupに関連するリソースを格納する
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
└── variables.tf
```

このように分離していくと､プロジェクトが大きくなっても見通しが良くなり､メンテナンス性が上がる｡
このように関連するリソースを分割していくことを構造化という｡



## Standard Module Structureとは

terraformで標準化しているモジュールの実装方式｡以下のようなファイルレイアウトで構成されている

```
hoge-terraform/
├── README.md
├── main.tf
├── modules
├── outputs.tf
├── NestedA
│   ├── README.md
│   ├── main.tf
│   ├── outputs.tf
│   └── variables.tf
├── NestedB
│   ├── README.md
│   ├── main.tf
│   ├── outputs.tf
│   ├── NestedBB
│   │   ├── main.tf
│   │   ├── outputs.tf
│   │   └── variables.tf
│   └── variables.tf
└── variables.tf
```

### [Standard Module Structureのルール](https://www.terraform.io/docs/modules/index.html)

- main.tf, variables.tf, outputs.tf
  - 空であっても最低限用意すべきファイル
  - variablesとoutputsには明示的であってもdescriptionをつけておく(ドキュメント作成に必要)
- README(ドキュメント)
  - 以下の構成で書くことをおすすめする
    - モジュールの概要
    - 使い方
    - 入力値(variables)と出力値(outputs) ｡
- Nested modules
  - ネストしたモジュールはmodule配下にサブディレクトリとして作成する

## コンポーネント化とはなにか?

簡単に言うとterraformでの構築､更新､削除の影響範囲を最小限にすべく､関連するグループに分け､そのグループごとにtfstateを持つようにすること｡

- メリット
  - 変更が最小限にできる
  - terraformの実行時間を減らすことができる
- コンポーネント化で意識するべきこと
  - 安定度
      - 安定度とは変更の程度と依存される度合いを指す
      - 安定度が高いと変更しづらく､他のコンポーネントから依存されるコンポーネントということになる｡
      - 安定度が高いコンポーネントはちゃんと分離するべき｡
      - 変動を想定したコンポーネントが､安定度の高いコンポーネント化に依存するようにする｡
  - ステートフル
      - RDSやS3などのデータストアのことを指す｡
      - 資産として管理されているため､必ずステートフルなリソースは分離しておく｡
  - 循環依存
      - 対象となるコンポーネントが互いに依存しきってしまうことをいう
      - どちらかが変更を行うと､その片方も影響を受けて壊れやすくなってしまう｡
      - terraformには循環依存を検知する機能はないので､安定度が高いコンポーネントに依存させて上げることが重要｡

## Terraformで使っているツール

- [terraform docs](https://github.com/segmentio/terraform-docs)
  - terraformのvariablesとoutputsの情報をもとにドキュメントを自動で生成してくれるツール
  - README作成にもってこい
  - ただ､最新版だと生成できない[不具合](https://github.com/segmentio/terraform-docs/issues/62)があるみたいなので､対応されるまで待つのが吉
- [terraform ignore](https://github.com/github/gitignore/blob/master/Terraform.gitignore)
  - ツールではないが､gitignoreのterraform用フォーマット
- [terraform-landscape](https://github.com/coinbase/terraform-landscape)
  - terraformのplanで表示される内容を整形してくれるツール｡

## 参考にしたサイトまたは書籍
- [Terraform公式ドキュメント](https://www.terraform.io/docs/index.html)
- [pragmatic terraform on aws](https://booth.pm/ja/items/1318735)
- [実践Terraform](https://www.amazon.co.jp/実践Terraform-AWSにおけるシステム設計とベストプラクティス-技術の泉シリーズ（NextPublishing）-野村-友規/dp/4844378139)