terraform で userdata を渡して ec2 インスタンスを起動し、ホスト名をつける

# やること

* terraform で iam ロールをつくる
* terraform で ec2 インスタンスをつくる
  *  userdata を渡す
     * s3 から shellscript をダウンロードして実行 
         * インスタンスに付与されている Name タグを hostname に設定する

これらを `terraform apply` のみで完了させます。 

# 環境

|name|version|
|:---|:---- |
|ec2|amazon-linux 2015.09|
|terraform|0.5.3|
|ローカル環境|OSX 10.10.5|

※ terraform の現在の最新は 0.6.6 のようです

# 前提

* subnet / routetable / security-group が作成済みであること

# tf ファイルの作成

ec2 インスタンスの構成情報を記述します。作業ディレクトリは `~/terraform/test` とします。

### aws アクセスキー

``` ~/terraform/test/aws.tf
/*
    aws settings
*/

provider "aws" {
    access_key = "************"
    secret_key = "********************"
    region = "ap-northeast-1"
}
```

### 変数 

今回は使いませんが、バケット名を書いたりすると便利そうです。

``` ~/terraform/test/variables.tf
/*
   variables
*/

variable "my-env" {
    default = {
        vpc_id = "vpc-****"
        vpc_cidr = "10.0.0.0/16"
    }
}
```

### iam ロール

s3 へのアクセスと `ec2 describe-instances` を許可します。

``` ~/terraform/test/iam_role.tf
resource "aws_iam_role_policy" "test_policy" {
    name = "test_policy"
    role = "${aws_iam_role.test.id}"
    policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "ec2:Describe*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
      "Action": [
        "s3:*"
      ],
      "Effect": "Allow",
      "Resource": [
          "arn:aws:s3:::my-bucket/*",
          "arn:aws:s3:::my-bucket"
      ]
    }
  ]
}
EOF
}

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

resource "aws_iam_instance_profile" "test_profile" {
  name = "test_profile"
  roles = ["${aws_iam_role.test_role.name}"]
}
```

一旦ここまでで `terraform apply` して iam 設定を作成しておきます。


### userdata

中身はこんな感じで、s3 からダウンロードしたスクリプトを実行するだけのものです。

``` userdata.sh
#!/bin/bash
# for userdata

aws="/usr/bin/aws --region ap-northeast-1"
work_dir="/tmp/userdata"
s3_url="s3://my-bucket/my-folder"
logger="logger -t $0"

${logger} "start scirpt."
mkdir -p "${work_dir}"

### download & run
${aws} s3 cp --recursive "${s3_url}" "${work_dir}"
ls "${work_dir}" | while read script
do
  sh "${work_dir}"/"${script}"
done

${logger} "finished."
exit 0
```

これを `base64` エンコードします。 mac だったら以下です。

```
$ cat userdata.sh | openssl enc -e -base64
IyEvYmluL2Jhc2gKIyBmb3IgdXNlcmRhdGEKCmF3cz0iL3Vzci9iaW4vYXdzIC0t
cmVnaW9uIGFwLW5vcnRoZWFzdC0xIgp3b3JrX2Rpcj0iL3RtcC91c2VyZGF0YSIK
czNfdXJsPSJzMzovL215LWJ1Y2tldC9teS1mb2xkZXIiCmxvZ2dlcj0ibG9nZ2Vy
IC10ICQwIgoKJHtsb2dnZXJ9ICJzdGFydCBzY2lycHQuIgpta2RpciAtcCAiJHt3
b3JrX2Rpcn0iCgojIyMgZG93bmxvYWQgJiBydW4KJHthd3N9IHMzIGNwIC0tcmVj
dXJzaXZlICIke3MzX3VybH0iICIke3dvcmtfZGlyfSIKbHMgIiR7d29ya19kaXJ9
IiB8IHdoaWxlIHJlYWQgc2NyaXB0CmRvCiAgc2ggIiR7d29ya19kaXJ9Ii8iJHtz
Y3JpcHR9Igpkb25lCgoke2xvZ2dlcn0gImZpbmlzaGVkLiIKZXhpdCAw
```

これを次の tf ファイルに貼り付けます。  

### ec2 インスタンス

``` ~/terraform/test/instance.tf
resource "aws_instance" "test-001" {
    ami = "ami-*****"
    instance_type = "t2.micro"
    subnet_id = "subnet-*****"
    private_ip = "10.0.0.5"
    user_data = <<EOF
IyEvYmluL2Jhc2gKIyBmb3IgdXNlcmRhdGEKCmF3cz0iL3Vzci9iaW4vYXdzIC0t
cmVnaW9uIGFwLW5vcnRoZWFzdC0xIgp3b3JrX2Rpcj0iL3RtcC91c2VyZGF0YSIK
czNfdXJsPSJzMzovL215LWJ1Y2tldC9teS1mb2xkZXIiCmxvZ2dlcj0ibG9nZ2Vy
IC10ICQwIgoKJHtsb2dnZXJ9ICJzdGFydCBzY2lycHQuIgpta2RpciAtcCAiJHt3
b3JrX2Rpcn0iCgojIyMgZG93bmxvYWQgJiBydW4KJHthd3N9IHMzIGNwIC0tcmVj
dXJzaXZlICIke3MzX3VybH0iICIke3dvcmtfZGlyfSIKbHMgIiR7d29ya19kaXJ9
IiB8IHdoaWxlIHJlYWQgc2NyaXB0CmRvCiAgc2ggIiR7d29ya19kaXJ9Ii8iJHtz
Y3JpcHR9Igpkb25lCgoke2xvZ2dlcn0gImZpbmlzaGVkLiIKZXhpdCAw
EOF
    iam_instance_profile = "${aws_iam_instance_profile.test_profile.name}"
    security_groups = [
        "sg-*******"
    ]
    ebs_block_device = {
      device_name = "/dev/xvdba"
      volume_type = "standard"
      volume_size = "15"
      encrypted = "true"
      delete_on_termination = "true"
    }
    ebs_block_device = {
      device_name = "/dev/xvdbb"
      volume_type = "standard"
      volume_size = "15"
      encrypted = "true"
      delete_on_termination = "true"
    }
    tags {
        Name = "test-001"
    }
}
```

### ホスト名をつけるスクリプト

s3 にアップロードしておくスクリプトです。

``` set_hostname.sh
#!/bin/bash
# set_hostname.sh
# require awscli and ec2 read access on iam role

set -e
aws="/usr/bin/aws --region ap-northeast-1"
logger="logger -t $0"

get_instance_id()
{
    instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
}

get_tag_name()
{
    tag_name=$(${aws} ec2 describe-instances \
                  --instance-id ${instance_id} \
                  --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value' \
                  --output text)
}

set_hostname()
{
    hostname "${tag_name}"
    local res=$(grep "HOSTNAME=${tag_name}" /etc/sysconfig/network)
    if [ -z "${res}" ]; then
        sed -i -e '/HOSTNAME/d' /etc/sysconfig/network
        echo "HOSTNAME=${tag_name}" >> /etc/sysconfig/network
    fi
}

get_instance_id
get_tag_name
set_hostname
${logger} "finished $0"
exit 0
```

### terraform 実行

```
$ terraform apply

~略~
  ebs_block_device.66500966.delete_on_termination:   "" => "1"
  ebs_block_device.66500966.device_name:             "" => "/dev/xvdba"
  ebs_block_device.66500966.encrypted:               "" => "1"
  ebs_block_device.66500966.iops:                    "" => "<computed>"
  ebs_block_device.66500966.snapshot_id:             "" => "<computed>"
  ebs_block_device.66500966.volume_size:             "" => "15"
  ebs_block_device.66500966.volume_type:             "" => "standard"
  ebs_block_device.7499016.delete_on_termination:    "" => "1"
  ebs_block_device.7499016.device_name:              "" => "/dev/xvdbb"
  ebs_block_device.7499016.encrypted:                "" => "1"
  ebs_block_device.7499016.iops:                     "" => "<computed>"
  ebs_block_device.7499016.snapshot_id:              "" => "<computed>"
  ebs_block_device.7499016.volume_size:              "" => "15"
  ebs_block_device.7499016.volume_type:              "" => "standard"
  ephemeral_block_device.#:                          "" => "<computed>"
  iam_instance_profile:                              "" => "test_profile"
  instance_type:                                     "" => "t2.medium"
  key_name:                                          "" => "<computed>"
  placement_group:                                   "" => "<computed>"
  private_dns:                                       "" => "<computed>"
  private_ip:                                        "" => "10.0.0.5"
  public_dns:                                        "" => "<computed>"
  public_ip:                                         "" => "<computed>"
  root_block_device.#:                               "" => "<computed>"
  security_groups.#:                                 "" => "1"
  security_groups.2820007362:                        "" => "sg-******"
  subnet_id:                                         "" => "subnet-******"
  tags.#:                                            "" => "1"
  tags.Name:                                         "" => "test-001"
  tenancy:                                           "" => "<computed>"
  user_data:                                         "" => "53f8ca1523019339fffee792e0210ded15b39f5a"
  vpc_security_group_ids.#:                          "" => "<computed>"
aws_instance.test-001: Creation complete

Apply complete! Resources: 1 added, 1 changed, 1 destroyed.
```

`ssh -i key ec2-user@10.0.0.5` でログインし、 prompt が変わっていることが確認できました。

```
[ec2-user@test-001 ~]$
```

とっても便利ですね！