terraformでチームのAWSリソースを管理する

seeds company Xチーム、エンジニアの浅野ともうします。
子供からクリスマスプレゼントとしてミニカーをねだられ、amazonで物色していたのですが、気づいたら自分用にもいくつか同じミニカーを買ってしまっていました。
amazonてホント便利でこわいです。

amazonといえばAWSということで、チームのAWSリソースをterraformのコードで管理している話を書きたいと思います。

# なぜterraformか(化)

### なぜcloudformationでなくterraformか

AWSであれば[cloudformation](https://aws.amazon.com/jp/cloudformation/)でもよいのですが、素のjsonツラいのと個人的に[tao of hashicorp](https://www.hashicorp.com/tao.html)が好きなのでterraformにしました。
golang製なので単一のバイナリで動くのもありがたい。

とはいえcloudformationじゃないと実現できない機能もあるみたいですね。
因みに、terraformから[cloudformationを実行できたりします。](https://www.terraform.io/docs/providers/aws/r/cloudformation_stack.html)サンプルで提供されるcloudformationを試したりするのに便利かもしれません。

### なぜわざわざコード化するのか

画面ポチポチで構成していくのは楽な反面、構成対象が増えた時点で管理しきれなくなります。手動だとミスも有り得ますし。
また合わせてドキュメントもメンテする必要があり、管理コストが更に膨れます。
コード化することでそれ自体が今稼働しているインフラ設定のドキュメントとなることを期待する訳です。

# どのように構成しているか

AWSといえば　[classmethodさん](http://dev.classmethod.jp/) 。AWS関連で調べ物する時にはよく参考にさせていただいているのですが、terraformに関しても下記の記事を大いに参考にさせていただきました。というか、ほぼ同じです。

http://dev.classmethod.jp/devops/directory-layout-bestpractice-in-terraform/

```
├── .envrc
├── Makefile
├── README.md
├── bastion.tf
├── common
│   └── all
│       ├── main.tf
│       └── variables.tf
├── devops
│   ├── prod
│   │   ├── main.tf
│   │   └── variables.tf
│   └── stg
│       ├── main.tf
│       └── variables.tf
├── init
│   ├── igw.tf
│   ├── route-table.tf
│   ├── s3.tf
│   ├── terraform.tfstate
│   ├── terraform.tfstate.backup
│   └── vpc.tf
├── modules
│   ├── audit-trail
│   │   ├── cloudtrail.tf
│   │   ├── cloudwatch.tf
│   │   ├── iam.tf
│   │   ├── s3.tf
│   │   └── variables.tf
│   ├── billing-alert
│   │   ├── cloudwatch.tf
│   │   └── variables.tf
│   └── efs
│       └── efs.tf
├── s3.tf
├── security-group.tf
├── subnet.tf
├── user-data
│   └── bastion.yml
├── variables.tf
└── x
    ├── prod
    │   ├── main.tf
    │   └── variables.tf
    └── stg
        ├── main.tf
        └── variables.tf

```

少しだけ手を入れたのは下記の点です。

* 環境変数の活用
* 初期構築分の設定
* チーム x 環境毎の構成

ソースは[こちら](https://github.com/ntk1000/aws-terraform-template)

### 環境変数の活用

terraformは`TF_VAR_hoge`で設定した環境変数を`"${var.hoge}"`で読み込むことができます。
また、AWSのcredentialsも[環境変数で読み込ませることができます](https://www.terraform.io/docs/providers/aws/index.html)。
基本的にはソース管理対象から外したいが、terraformで使用したい変数は全て環境変数化しています。
下記のような`.envrc`ファイルを用意しておき、プロジェクト直下にcdして操作する時には[direnv](https://direnv.net/)経由で自動的に環境変数が設定されるようにしています。

``` bash:.envrc
# TF_VAR
export TF_VAR_team=seeds

# AWS key
export AWS_ACCESS_KEY_ID=xxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxx
export AWS_DEFAULT_REGION=ap-northeast-1
```

### 初期構築分の設定(initフォルダ以下)

terraformは`.tf`ファイルでインフラの定義を書き、terraformが生成する`.tfstate`ファイルでインフラの状態を保存します。
主に`.tf`ファイルをコード管理対象とし、`.tfstate`は保存先としてS3を指定します。ただ、できればこのバケットもterraformで管理したいのでこの部分だけinitというフォルダに分けておき、init直下のtfstateはコード管理対象に含めてしまっています。
initフォルダ以下は基本的にdestroyしない、特殊なりソース置き場という位置づけです。
(同様の理由からvpc関連のリソースもinit直下に配置しています。)

### チーム x 環境毎の構成

環境(ステージング or 本番)以外にチーム(Xチーム or DevOpsチーム　or チーム共通)という切り口でリソースを分割する必要があったため、`チーム > 環境` の構成として若干変更しました。

# 何をterraform化しているか

### 基本的な方針

コード化する、と広言しつつも基本的には`頑張りすぎない`をテーマに緩くやっています。
具体的には既に画面からポチポチ作ってしまったリソースは空いてる時間で除々にterraform化したり、snsのemail関連などterraformで対応していないリソースについては画面で作っておいて生成されたarnを環境変数で持たせる、などです。

### 対象

しかしながら、今後作成するものやこれまでチームの中で自分しか触れていなかったようなもの(vpcなど)は、原則コード化することでコードレビューを回せるようにしています。

# 今後の予定

まだCIに組み込めていないので commit/push -> pull request -> review -> dry-run -> deploy を自動で回せるようにしたいです。