Help us understand the problem. What is going on with this article?

JSON形式ファイルでのEC2インスタンス起動

More than 5 years have passed since last update.

同じ役割の複数台のEC2インスタンスを構成する際、AMIを独自に作ることがあると思う。
それをJSON形式の定義ファイルを用いて実現させてみる。

シナリオ

  1. Amazon Linux AMI からEC2インスタンスA起動
  2. 共通設定とか投入したEC2インスタンスAから元となるAMI(BaseAMI)を作成
  3. BaseAMIから新たにEC2インスタンスBを起動
  4. EC2インスタンスBに設定投入

このうち、1〜3までをやってみた。4とかはChefとかでやると思うので割愛。

1. Amazon Linux AMI からEC2インスタンスA起動

雛形出力

最近のAWS CLIのVer(1.6とか1.7以降?)では、JSON形式出力用のオプション --generate-cli-skeleton がほぼ全てのコマンドについてるのでそれを利用する。

$ aws ec2 run-instances --generate-cli-skeleton > run-instances_base.json

JSONファイル修正

出力された雛形に対して必要な設定を追加していく。
最小限の設定として、以下を設定。IPアドレスの他、EBSを3つ付けてみた。
SecurityGroupは名称だと上手くいかないのでIDで設定。

  • ImageId : ami-4985b048 [Amazon Linux AMI 2014.09.1 (HVM)]
  • KeyName : 自分ので
  • InstanceType : t2.micro
  • AvailabilityZone : 好きなAZで
  • SecurityGroupIds : アクセスできるSGで
  • SubnetId : 好きなSubnetで
  • PrivateIpAddress : 好きなIPで
  • BlockDeviceMappings : 3つ付けてみた
run-instances_base.json
{
    "ImageId": "ami-4985b048",
    "KeyName": "YOUR_KEY_NAME",
    "InstanceType": "t2.micro",
    "Placement": {
        "AvailabilityZone": "ap-northeast-1X"
    },
    "SecurityGroupIds": [
        "sg-XXXXXXXX"
    ],
    "SubnetId": "subnet-XXXXXXXX",
    "PrivateIpAddress": "10.X.X.X",
    "BlockDeviceMappings": [
        {
            "DeviceName": "/dev/xvda",
            "Ebs": {
                "VolumeSize": 30
            }
        },
        {
            "DeviceName": "/dev/xvdba",
            "Ebs": {
                "VolumeSize": 10
            }
        },
        {
            "DeviceName": "/dev/xvdbb",
            "Ebs": {
                "VolumeSize": 10
            }
        }
    ]
}

userdata作成

EC2インスタンス起動時にホスト名を設定させたい、という場合にはuserdataと言う名のシェルスクリプトを実行させることができる。
16KB制限らしいが、そこまで長大なものは書かないので大丈夫かと。
今回はホスト名の設定及びhosts追記と、2つのEBSをLVMで束ねるスクリプトにしてみた。

userdata_base.sh
#!/bin/bash
hostname test-instance-a
sed -i -e "s/HOSTNAME=\(.*\)/HOSTNAME=test-instance-a/" /etc/sysconfig/network
echo "10.X.X.X    test-instance-a" >> /etc/hosts
/sbin/pvcreate /dev/sdb[ab]
/sbin/vgcreate /dev/vgtest /dev/sdb[ab]
/sbin/lvcreate -l 100%FREE -n lvtest vgtest
/sbin/mkfs.ext4 -j /dev/vgtest/lvtest
/bin/mkdir -p /export/test
/bin/mount -t ext4 /dev/vgtest/lvtest /export/test
echo "/dev/vgtest/lvtest /export/test ext4 defaults 0 0" >> /etc/fstab

EC2インスタンスA起動

作成したJSONファイルとuserdataを引数に指定する。file:// というスキーマが必要。
実行に成功すると、結果ばぶわぁーっとJSON形式で出力されるので、変数に入れておく。後々使えるので。

$ RET=$(aws ec2 run-instances --cli-input-json file://run-instances_base.json --user-data file://userdata_base.sh)

Tag付与

run-instances 実行時に合わせて設定する方法が不明なので、ちょっとメンドイ方法で設定。
まず、上記の run-instances 実行結果から、InstanceId を抽出して、その InstanceId を引数にしてTagを付与する。

$ INSTANCE_ID=$(echo ${RET} | python -m json.tool | grep "InstanceId" | awk -F: '{print $2}' | sed -e 's/\"//g' -e 's/,//g')

$ aws ec2 create-tags --resource ${INSTANCE_ID} --tags Key=Name,Value=test-instance-a

2. 共通設定とか投入したEC2インスタンスAから元となるAMI(BaseAMI)を作成

userdataの設定確認

先ほどのuserdataが反映されているかログインして確認する。

$ ssh -i ~/.ssh/XXXX.pem ec2-user@10.X.X.X


$ sudo hostname
test-instance-a

$ sudo df -h /export/test
Filesystem                 Size  Used Avail Use% Mounted on
/dev/mapper/vgtest-lvtest   20G   45M   19G   1% /export/test

設定

他に設定したいものがあれば。
適当に yum update とかパッケージをインストールしておく。
終わったらインスタンスを停止させる。

$ sudo yum -y install dstat git nginx expect
$ sudo yum -y update
$ sudo shutdown -h now

AMI作成

インスタンスが停止したら、先ほど run-instances した時の InstanceId を指定して作成。

$ aws ec2 create-image --instance-id ${INSTANCE_ID} --name test-base-ami
{
    "ImageId": "ami-ac564aad"
}

AMIが出来上がるまでちょっと時間が掛かる。

3. BaseAMIから新たにEC2インスタンスBを起動

JSONファイル修正

さっき使ったのをベースに修正。変更点は以下。

  • ImageId : さっきの create-image 実行結果
  • KeyName : 自分ので
  • InstanceType : t2.micro
  • AvailabilityZone : 好きなAZで
  • SecurityGroupIds : アクセスできるSGで
  • SubnetId : 好きなSubnetで
  • PrivateIpAddress : 好きなIPで
  • BlockDeviceMappings : 記述を削除
run-instances_b.json
{
    "ImageId": "ami-XXXXXXXX",
    "KeyName": "YOUR_KEY_NAME",
    "InstanceType": "t2.micro",
    "Placement": {
        "AvailabilityZone": "ap-northeast-1X"
    },
    "SecurityGroupIds": [
        "sg-XXXXXXXX"
    ],
    "SubnetId": "subnet-XXXXXXXX",
    "PrivateIpAddress": "10.X.X.Z"
}

userdata作成

今回はホスト名の設定及びhosts追記のみ。

userdata_b.sh
#!/bin/bash
hostname test-instance-b
sed -i -e "s/HOSTNAME=\(.*\)/HOSTNAME=test-instance-b/" /etc/sysconfig/network
echo "10.X.X.Z    test-instance-b" >> /etc/hosts

EC2インスタンスB起動 & Tag付与

さっきと同じように実行。

$ RET=$(aws ec2 run-instances --cli-input-json file://run-instances_b.json --user-data file://userdata_b.sh)

$ INSTANCE_ID=$(echo ${RET} | python -m json.tool | grep "InstanceId" | awk -F: '{print $2}' | sed -e 's/\"//g' -e 's/,//g')

$ aws ec2 create-tags --resource ${INSTANCE_ID} --tags Key=Name,Value=test-instance-b

あとはインスタンスが起動するのを待つのみ。
まぁ確認は割愛で。


以上

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away