【AWS】 EC2コストダウンで躓いた話

# 前置き
AWSを利用するようになって初めは便利さのみ目立っていまいしたが、利用する範囲と時間が
増えていくにあたりコストの問題にぶち当たりました。
利用方法によってはかなりコストがかかる！

ということで、今回はコスト削減の方法とそれを実施した際に問題になったことをお話します。
※今回はEC2（Amazon linux）が対象です。

# コストダウン方法
AWS EC2 は従量課金になりますので、手っ取り早い方法としては、「稼働時間を短縮する」方法が一番簡単です。
ですので、今回は開発／テスト環境を対象として、作業時間の 9:00~19:00 以外はインスタンスをストップするようにしました。

>インスタンスの起動＆停止方法は以下を参考にしてください。
>参考：http://qiita.com/3utama/items/1a40970128648ca03c9f

結果としてはもちろんコストダウンに成功しましたが、ある課題が発生しました。

# 課題と対応
対応後に、朝来て接続しようと思ったら、なんとつながりません！なんでだ...
調べた結果、以下が原因でした。

>PublicIP（Elastic以外）は起動毎に割り当てられる。
>ELB利用の場合は、起動時に再割当てをしなければならない。


上記原因を解決するためには、以下の課題を対応する必要が有ります。

>Publicインスタンスの場合、起動時にRoute53のレコードを新規IPで更新する。
>ELB利用の場合は起動時にELBへ再登録（削除＆登録）を行う。

対応として、以下の対応を実施しました。

>課題解消のために必要な情報のタグを作成
>課題解消用のスクリプトを作成

まずタグですが、以下のタグの追加とNameタグの意味付けを行いました。

- Name        # ドメイン名
- Elb_Name    # ELB名
- Hosted_Zone # Route53に登録されているHosted Zone

この情報を利用して、以下スクリプトを動作させます。
※事前にcli53をインストールして下さい。

```aws.conf
description  "prepare aws environment"
author       "Author <author@author.co.jp>"

start on started elastic-network-interfaces 
stop on runlevel [!2345]

script

  REGION="ap-northeast-1"
  # ホスト名取得
  PUBLIC_HOSTNAME=`/opt/aws/bin/ec2-metadata -p | cut -d ' ' -f 2-`
  # インスタンスID取得
  INSTANCE_ID=`/opt/aws/bin/ec2-metadata -i | cut -d ' ' -f 2`
  # タグ情報取得（Hosted_Zone）
  HOSTED_ZONE=`aws ec2 describe-tags --region $REGION --filters Name=resource-type,Values=instance Name=resource-id,Values=$INSTANCE_ID Name=key,Values=Hosted_Zone --query 'Tags[*].Value' --output text`
  # タグ情報取得（Name）
  NAME=`aws ec2 describe-tags --region $REGION --filters Name=resource-type,Values=instance Name=resource-id,Values=$INSTANCE_ID Name=key,Values=Name --query 'Tags[*].Value' --output text`

  # Route53更新
  cli53 rrcreate $HOSTED_ZONE $NAME CNAME $PUBLIC_HOSTNAME --replace --ttl 60 2>&1 | tee -a /tmp/route53-update.log

  # タグ情報取得（Elb_Name）
  ELB_NAME=`aws ec2 describe-tags --region $REGION --filters Name=resource-type,Values=instance Name=resource-id,Values=$INSTANCE_ID Name=key,Values=Elb_Name --query 'Tags[*].Value' --output text`

  # ELBを利用している場合
  if [ -n $ELB_NAME ]; then
    # ELB設定削除
    aws --region=$REGION elb deregister-instances-from-load-balancer --load-balancer-name=$ELB_NAME --instances=$INSTANCE_ID 2>&1 | tee -a /tmp/elb-update.log
    # ELB設定作成
    aws --region=$REGION elb register-instances-with-load-balancer --load-balancer-name=$ELB_NAME --instances=$INSTANCE_ID 2>&1 | tee -a /tmp/elb-update.log
  fi

end script
```

無事動くようになりました！

# ついで
タグはアカウント共通なので、新規インスタンス作成時に設定、
スクリプトについてはインスタンス作成後にChefでcli53のインストールとシェルの配置をcookできるようにしておけば楽になります。


# 追記
route-53更新でcli53を利用していましたが、最新のAmazonLinuxAMIでpip install cli53しようとするとうまく行かなかったので、
cli53を利用せずにawsCliで更新するように修正しました。

```aws.conf
# Hosted zone id を取得
HOSTED_ZONE_ID=$(aws route53 list-hosted-zones --query HostedZones[?Name==\`"$HOSTED_ZONE".\`].Id --output text | sed -e 's;/hostedzone/;;g')

# route53更新設定のjsonファイルのPublic-DNS固定文字部分を変更
sed -i -e "s/REPLACE-PUBLIC-DNS/$PUBLIC_HOSTNAME/g" conf.json

# route53更新
aws route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file://conf.json 2>&1 | tee -a /tmp/route53-update.log

# jsonファイルのPublic-DNS部分を固定文字に戻す
sed -i -e "s/$PUBLIC_HOSTNAME/REPLACE-PUBLIC-DNS/g" conf.json
```

```conf.json
{
  "Comment": "update route53 record set.",
  "Changes": [
    {
      "Action": "UPSERT",
      "ResourceRecordSet": {
        "Name": "【ドメイン名】",
        "Type": "CNAME",
        "TTL": 60,
        "ResourceRecords": [
          {
            "Value": "REPLACE-PUBLIC-DNS"
          }
        ]
      }
    }
  ]
}

```

以下のコマンドで更新できます。

>aws route53 change-resource-record-sets --hosted-zone-id $HOSTED_ZONE_ID --change-batch file://conf.json

起動時に毎回Public-DNSを置き換えなければいけないので、固定の文字列に変換してうまいことjsonファイルを用意したところうまくいきました。

Hosted zone idを取得するのにちょっとだけ苦労しました。

>HOSTED_ZONE_ID=\$(aws route53 list-hosted-zones --query HostedZones[?Name==\`"$HOSTED_ZONE".\`].Id --output text | sed -e 's;/hostedzone/;;g')

EC2のタグ情報に書いても良かったんですけど、管理上不規則な文字列が並んでいてもわかりづらいので、

- EC2のタグにはHosted zone nameを登録。
- nameからIDを取得。

ってやりたかったので、ちょっと手間でした。


# 追記
現在、[ELBに関連付けられたインスタンスが再起動しても自動で認識してくれる](http://aws.typepad.com/aws_japan/2015/12/support-for-automatic-re-registration-of-ec2-back-end-instances-when-stopped-and-restarted.html)みたいですね。日々進化。