同じ役割の複数台のEC2インスタンスを構成する際、AMIを独自に作ることがあると思う。
それをJSON形式の定義ファイルを用いて実現させてみる。
シナリオ
- Amazon Linux AMI からEC2インスタンスA起動
- 共通設定とか投入したEC2インスタンスAから元となるAMI(BaseAMI)を作成
- BaseAMIから新たにEC2インスタンスBを起動
- 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つ付けてみた
{
"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で束ねるスクリプトにしてみた。
#!/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 : 記述を削除
{
"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追記のみ。
#!/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
あとはインスタンスが起動するのを待つのみ。
まぁ確認は割愛で。
以上