EC2インスタンス起動時に自動でDNS設定を行う

EC2インスタンスを起動する時に自動でDNS設定を行い、同じ接続先でアクセスできるようにします。

# 背景
EC2インスタンスは起動する度にPublic IPアドレスが変わるため、外からアクセスする時にいちいち接続先を更新しないといけないのが面倒です。

Elastic IPを使うことでインスタンスのPublic IPアドレスを固定することはできます。
が、インスタンス停止中はElastic IPに課金が発生するのであまり使いたくない…

そこで、インスタンス起動時にDNSを更新するようにして、Elastic IPを使わずとも接続先が同じになる仕組みを作ってみました。

# 目的
EC2インスタンス起動時にDNSを設定して、停止前と同じ接続先でアクセスできるようにします。

# 使うサービス
- EC2
- Route53
- IAM(ロールとポリシー)

# 手順
## コンソール上での作業
### 1. Route53でHosted Zoneを作成

Route53でHosted Zoneを作成します。
ドメイン名とHostedZoneIdを控えておきます。

### 2. IAMロールを作成し、EC2インスタンスにアタッチする
ロールがすでにEC2インスタンスにアタッチされていれば必要なし。
ロールの中身は空で問題ないです。

(ロールをEC2にアタッチする参考リンク)
[\[アップデート\] EC2コンソールで既存のEC2インスタンスに対してIAM Roleをアタッチ、変更ができるようになりました](http://dev.classmethod.jp/cloud/aws/replace-attach-iamrole-ec2console/)


### 3. IAMポリシーを作成
EC2インスタンスがRoute53でDNSを更新できるようにIAMポリシー(カスタマー管理ポリシー)を作成します。
DNSの設定に使用するドメインのレコードのみ更新できるよう許可します。
XXXXXXXXXXXXXの部分は1.で作成したホストゾーンのHostedZoneIdに置き換えてください。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "route53:ChangeResourceRecordSets"
            ],
            "Resource": "arn:aws:route53:::hostedzone/XXXXXXXXXXXXX"
        },
        {
            "Effect": "Allow",
            "Action": [
                "route53:ListResourceRecordSets",
                "route53:GetChange"
            ],
            "Resource": "*"
        }
    ]
}
```

### 4. IAMロールにポリシーを追加
EC2インスタンスにアタッチしたIAMロールにポリシーを追加します。

## EC2インスタンス上での作業
### 1. AWSCLIをインストール

http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html
※OSがAmazonLinuxの場合は必要なし。

#### Redhat系OSの場合
```bash
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli
```
#### Ubuntuの場合
```bash
sudo apt-get -y update
sudo apt-get -y upgrade
sudo apt-get -y install python-dev
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli
```
### 2. スクリプト作成とcron設定


```bash
sudo mkdir /var/scripts/
sudo vi /var/scripts/updatedns.sh
sudo chmod 700 /var/scripts/updatedns.sh
sudo vi /etc/rc.local
```

```bash:updatedns.sh
#!/bin/sh

#メタデータから自身のPublicIP取得
publicIp=`curl http://169.254.169.254/latest/meta-data/public-ipv4` 
#DNS設定(Route53で設定したドメイン名と、サブドメインを入れる)
domain=test.example.com

#JSON作成
cat <<EOT > /tmp/dns_recordset.json 
{ "Changes": [{"Action":"UPSERT","ResourceRecordSet":{"Name": "$domain","Type": "A","TTL":600,"ResourceRecords":[{"Value":"$publicIp"}]}}]}
EOT
#DNS更新
aws route53 change-resource-record-sets --hosted-zone-id XXXXXXXXXXXXX --change-batch file:///tmp/dns_recordset.json
#更新に使用したJSONを削除
rm /tmp/dns_recordset.json 
```
ドメイン名やHostedZoneIdの部分はRoute53で作成したものに置き換えてください。

```/etc/rc.local
#以下追記
/var/scripts/updatedns.sh
```


※RedHat系OSの場合は/etc/rc.d/rc.localに実行権限を与える必要があります。


```bash:Redhat系のみ
sudo chmod u+x /etc/rc.d/rc.local
```

ここまで作業すると、rebootで再起動した際やインスタンスを停止→起動した際にDNSが自動で更新されるようになります。


#ホストゾーンとElastic IPの月額料金

Route 53のホストゾーンと、EC2インスタンスが起動していない時にElatic IPにかかる料金を調べてみました。

(参考リンク)
https://aws.amazon.com/jp/route53/pricing/
https://aws.amazon.com/jp/ec2/pricing/on-demand/#Elastic_IP_Addresses



| ホストゾーン |ElasticIP(1日中停止)| ElasticIP(1日あたり16時間稼働)|
|:-------------------:|:-------------------:|:-------------------:|
| 0.5 USD             |               0.005*24時間*30日=3.6 USD |        0.005*8時間*30日=1.2 USD        |

※ElasticIPはap-northeast-1a(東京)で取得した場合を仮定

ホストゾーンは一つ作ってしまえば、その中にいくらレコードを追加しても費用は変わりません。
ドメインの料金は別途必要ですが、使っていない時があるElasticIPがあれば費用の削減にもなりそうですね。

# まとめ
EC2インスタンスを停止→起動した時にDNSを更新して接続先を変えずともアクセスできるようにしました。