TerraformでECR上のDockerイメージをEC2にささっとデプロイ

# やったこと
ちょっとしたWebアプリをAWSに気軽にデプロイできるようにしたかったので、Terraformを使ってECRのDockerイメージをEC2にささっとデプロイしてみたメモ。

ちょっとしたものを気軽にデプロイしたいだけなので、以下のようなかなり手抜きな内容です。

- VPCを適当に構築
- IAMロールでEC2からECRへのアクセスを許可
- 80番ポートのみアクセスを許可したEC2を起動
- User DataでDockerのインストールからECR上のコンテナのデプロイまで実施

# 作ったもの
- シェルスクリプト
    - userdata.sh
- Terraformのテンプレート
    - main.tf
    - variables.tf
    - outputs.tf

# 各種ファイルの内容

## userdata.sh

Dockerのインストールと指定したイメージの起動を行います。
IMAGE_NAMEの部分は適宜修正します。

```bash:userdata.sh
#!/bin/bash -eux

IMAGE_NAME=xxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx

sudo yum install -y docker
sudo systemctl enable docker
sudo systemctl start docker

aws ecr get-login --no-include-email --region ap-northeast-1 | sudo sh
sudo docker run -d -p 80:80 $IMAGE_NAME
```

BASE64にエンコードして、あとでmain.tfに貼り付けます。

```bash
$ cat userdata.sh | base64
IyEvYmluL2Jhc2ggLWV1eAoKSU1BR0VfTkFNRT14eHguZGtyLmVjci5hcC1ub3J0aGVhc3QtMS5hbWF6b25hd3MuY29tL215LW5naW54CgpzdWRvIHl1bSBpbnN0YWxsIC15IGRvY2tlcgpzdWRvIHN5c3RlbWN0bCBlbmFibGUgZG9ja2VyCnN1ZG8gc3lzdGVtY3RsIHN0YXJ0IGRvY2tlcgoKYXdzIGVjciBnZXQtbG9naW4gLS1uby1pbmNsdWRlLWVtYWlsIC0tcmVnaW9uIGFwLW5vcnRoZWFzdC0xIHwgc3VkbyBzaApzdWRvIGRvY2tlciBydW4gLWQgLXAgODA6ODAgJElNQUdFX05BTUUK
```

## main.tf

長いファイルなので、Provider、VPC、IAM、EC2に分けて掲載します。
全体的に[Basic Two-Tier AWS Architecture](https://github.com/terraform-providers/terraform-provider-aws/tree/master/examples/two-tier)を参考にしています。

### Provider

```
# ######## #
# Provider #
# ######## #

provider "aws" {
  version = "~> 1.3"
  region = "${var.aws_region}"
}
```

### VPC

```
# ### #
# VPC #
# ### #

resource "aws_vpc" "default" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_internet_gateway" "default" {
  vpc_id = "${aws_vpc.default.id}"
}

resource "aws_route" "internet_access" {
  route_table_id         = "${aws_vpc.default.main_route_table_id}"
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = "${aws_internet_gateway.default.id}"
}

resource "aws_subnet" "default" {
  vpc_id                  = "${aws_vpc.default.id}"
  cidr_block              = "10.0.0.0/24"
  map_public_ip_on_launch = true
}
```

### IAM

```
# ### #
# IAM #
# ### #

resource "aws_iam_role" "instance_role" {
    name = "instance_role"
    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

resource "aws_iam_policy_attachment" "ecs-role-attach" {
    name = "ecs-role-attach"
    roles = ["${aws_iam_role.instance_role.name}"]
    policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

resource "aws_iam_instance_profile" "instance_role" {
    name = "instance_role"
    role = "${aws_iam_role.instance_role.name}"
}
```

EC2へのIAMロールの割り当てについては、以下を参考にしました。

- https://cross-black777.hatenablog.com/entry/2015/12/04/233206
- https://inokara.hateblo.jp/entry/2015/12/25/092605


### EC2

```
# ### #
# EC2 #
# ### #

resource "aws_security_group" "default" {
  description = "Used in the terraform"
  vpc_id      = "${aws_vpc.default.id}"

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_instance" "instance" {
  instance_type = "t2.micro"
  ami = "${lookup(var.aws_amis, var.aws_region)}"

  vpc_security_group_ids = ["${aws_security_group.default.id}"]
  subnet_id = "${aws_subnet.default.id}"

  iam_instance_profile = "instance_role"

  user_data = "IyEvYmluL2Jhc2ggLWV1eAoKSU1BR0VfTkFNRT14eHguZGtyLmVjci5hcC1ub3J0aGVhc3QtMS5hbWF6b25hd3MuY29tL215LW5naW54CgpzdWRvIHl1bSBpbnN0YWxsIC15IGRvY2tlcgpzdWRvIHN5c3RlbWN0bCBlbmFibGUgZG9ja2VyCnN1ZG8gc3lzdGVtY3RsIHN0YXJ0IGRvY2tlcgoKYXdzIGVjciBnZXQtbG9naW4gLS1uby1pbmNsdWRlLWVtYWlsIC0tcmVnaW9uIGFwLW5vcnRoZWFzdC0xIHwgc3VkbyBzaApzdWRvIGRvY2tlciBydW4gLWQgLXAgODA6ODAgJElNQUdFX05BTUUK"
}
```

user_dataには、先ほどBase64でエンコードしたものを貼り付けています。

## variables.tf

```
# ####### #
# Overall #
# ####### #

variable "aws_region" {
  description = "AWS region to launch servers."
  default     = "ap-northeast-1"
}

# ### #
# EC2 #
# ### #

# Amazon Linux 2
variable "aws_amis" {
  default = {
    us-east-1      = "ami-b70554c8"
    ap-northeast-1 = "ami-e99f4896"
  }
}
```

## outputs.tf

```
output "address" {
  value = "http://${aws_instance.instance.public_ip}"
}
```

# 実行

```bash
$ terraform init
    :
    :
    :
$ terraform apply
    :
    :
    :
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Outputs:

address = http://xxx.xxx.xxx.xxx
```

Outputsに表示されているURLにアクセスすると、無事Nginxのページが表示されました。

![スクリーンショット 2018-08-17 17.54.02.png](https://qiita-image-store.s3.amazonaws.com/0/216010/cf65efd7-62c7-4eab-d385-a14e4b2c44bc.png)

# 片付け

```
terraform destroy
```