[aws] terraform と ansible を使ってインスタンスを構築する

aws に ec2インスタンス (linux) を構築します
windows はちょっと特殊なので、別の機会に。。

初めて使ってみてのメモ書きなので、良い構成ややり方、それはマズイなどありましたらご指摘ください(´･_･`)
## ディレクトリ構成
環境毎に分けようと environments ディレクトリ以下に開発用 (development) の設定を置いています
他の環境でも terraform の module(後述)を利用できるよう、 module は environments 直下に置いています
```
├── environments
│  └── development
│      ├── ansible
│      │  ├── hosts.yml
│      │  ├── linux
│      │  │  ├── nginx
│      │  │  │  ├── nginx.conf
│      │  │  │  └── nginx.repo
│      │  │  └── start-tool.sh
│      │  └── setupLinux.yml
│      ├── conf
│      │  ├── config
│      │  └── credentials
│      ├── main.tf
│      └── run_ansible.sh
└── module
    ├── instance
    │  ├── main.tf
    │  ├── outputs.tf
    │  └── variables.tf
    ├── network
    │  ├── main.tf
    │  ├── outputs.tf
    │  └── variables.tf
    └── security_group
        ├── main.tf
        ├── outputs.tf
        └── variables.tf
```

## ansible の設定
まずは ansible から見ていきます

主にミドルウェアの構築に使っています
最初は terraform 経由で userdata 実行していたのですが、量が増えてくると限界があり ansible のが楽だったためミドルウェアの構築は ansible に任せました

setupLinux.yml に user の作成・sshできるよう鍵の設定、アプリケーションに使用する jdkインストール、nginx インストール+自動起動設定などを記載しています

例:
```
    - name: install jdk
      shell: "amazon-linux-extras install -y java-openjdk11"

    - name: install jdk devel
      yum:
        name: java-11-openjdk-devel
        state: present

    - name: copy Nginx repository
      copy:
        src: "linux/nginx/nginx.repo"
        dest: "/etc/yum.repos.d/nginx.repo"
        mode: 0644
    - name: install nginx
      yum:
        name: nginx
        state: present
```

hosts.yml には接続先のインスタンス情報が入っています
デフォルトで作られている ec2-user で ssh で接続するようにしてます

linuxディレクトリ以下は、その OSに入れるミドルウェアの設定やアプリケーションの起動シェルなどを入れています

## terraform の設定
次に terraform を見ていきます
module のディレクトリがありますが、インスタンスの作成や Elastic IP の設定、セキュリティグループの設定、VPC やサブネットと、、インスタンスの種類が増えると記述が増えていき管理が煩雑になりそうだったため、 module を使用してみました

テンプレート化ができるため、設定値を変えるだけでインスタンスの調整ができます

development 直下の main.tf
例:
```
module "instance" {
  source = "../../module/instance"
  vpc_id = module.network.vpc_id
  subnet_id = module.network.subnet_id
  security_group_id = module.security_group.sg_id
  user_data_template_file = data.template_file.init.rendered
  instance_ami = "XXX"
  instance_type = "XXX"
  instance_envName = "XXX"
  instance_count = 2
}
```

module内の各ディレクトリにあるファイルは以下の通りです
* main.tf
    * リソースの定義を書きます
* variables.tf
    * module側が受け取る引数の設定します
* outputs.tf
    * moduleが返す戻り値を設定します

variables.tf と outputs.tf はまとめることが可能のようです

conf に入っているのは aws のアクセス情報になります
config はリージョン、出力形式
credentials はアクセスキー類が入っています
秘密情報のため git に誤って入らないよう以下の設定をいれてます

```
# クレデンシャル流出防止
brew install git-secrets
git secrets --register-aws --global
git secrets --install ~/.git-templates/git-secrets
git config --global init.templatedir '~/.git-templates/git-secrets'
```

デフォルトは ~/.aws にあると思いますが、プロダクト毎に切り替えられるよう以下で設定しました
```
provider "aws" {
  region                   = "ap-northeast-1"
  shared_config_files      = ["./conf/config"]
  shared_credentials_files = ["./conf/credentials"]
}
```

## terraform から ansible 実行
最後に terraform から ansible の実行をしてくれている run_ansible.sh になります
local-exec を使いました
ansible を実行する際に ip が欲しかったので、resource "aws_eip" のブロックに入れました
割り当てられた ip を shell の引数に渡しています
```
  provisioner "local-exec" {
    command = "sh run_ansible.sh ${self.public_ip}"
  }
```
shell では ip を受け取り hosts.yml を作成し、30秒ほど sleep 入れてから ansible の実行をしインスタンスの構築が完了となります