cloud-initについて
AmazonLinuxではcloud-initという機能があり、Launch WizardでUser dataに処理を記述することで、Launch直後に特定の処理を自動実行させることができます。
がんばれば起動直後にミドルウェアを一揃いセットアップし、LAMPとしての機能を備えた状態でLaunchさせることなどが可能なようです。
実行させる処理は、以下の様な独自の記法で記述します。
起動時にyum updateする例
repo_upgrade: all
シェルコマンドを実行する例
runcmd:
- [ ls, -l, / ]
- [ sh, -xc, "echo $(date) ': hello world!'" ]
- [ sh, -c, echo "=========hello world'=========" ]
- ls -l /root
- [ wget, "http://slashdot.org", -O, /tmp/index.html ]
ちょっと癖がある書き方でとっつきにくいのですが、実はシェルスクリプトも実行することができます。
今回は、cloud-initを使って、AmazonLinux立ち上げ時に定型的に実行する処理を自動化してみます。
AmazonLinux立ち上げ時の定型処理
AmazonLinuxを起動するときは、だいたい以下の処理を行うことが多いです。
- yum update
- jqをインストール(aws-cliの出力がJSONなのでパースするのに必要です)
- Nameタグに入っている名前でhostnameを設定
- タイムゾーンを修正する
- ルートディスクにresize2fsコマンドを実行する
これらをシェルスクリプトに起こしたものが以下です。 スクリプト内に日本語を書くと実行に失敗するようなのでコメントは入れていません。
#!/bin/bash -ex
RETRYLIMIT=3
RETRYINTERVAL=2
\cp -f /usr/share/zoneinfo/Japan /etc/localtime
sed -i -e "s/ZONE=.*$/ZONE=\"Asia\/Tokyo\"/" /etc/sysconfig/clock
sed -i -e "s/UTC=.*$/UTC=false/" /etc/sysconfig/clock
echo 'ARC=false' >> /etc/sysconfig/clock
service crond restart
yum install jq -y
yum update -y
CMD='curl -s --connect-timeout 5 --max-time 10 http://169.254.169.254/latest/meta-data/placement/availability-zone/'
for i in $(seq 1 ${RETRYLIMIT})
do
RET=$(${CMD} 2>&1)
RESULT=$?
[ ${RESULT} -eq 0 ] && break
[ $i -ge ${RETRYLIMIT} ] && logger "get region failed." && exit 1
sleep ${RETRYINTERVAL}
done
REGION=$(echo ${RET} | sed -e "s/.$//")
CMD='curl -s --connect-timeout 5 --max-time 10 http://169.254.169.254/latest/meta-data/instance-id'
for i in $(seq 1 ${RETRYLIMIT})
do
RET=$(${CMD} 2>&1)
RESULT=$?
[ ${RESULT} -eq 0 ] && break
[ $i -ge ${RETRYLIMIT} ] && logger "get instance-id failed." && exit 1
sleep ${RETRYINTERVAL}
done
INSTANCEID=${RET}
CMD="aws ec2 describe-tags --region ${REGION} --filters "Name=resource-id,Values=${INSTANCEID}""
for i in $(seq 1 ${RETRYLIMIT})
do
RET=$(${CMD} 2>&1)
RESULT=$?
[ ${RESULT} -eq 0 ] && break
[ $i -ge ${RETRYLIMIT} ] && logger "get Name failed" && exit 1
sleep ${RETRYINTERVAL}
done
NAME=$(echo ${RET} | jq '.Tags[] | select(.Key == "Name") | .Value' | tr -d '"' | tr -d "\n")
hostname ${NAME}
sed -i -e "1s/$/ ${NAME}/" /etc/hosts
sed -i -e "s/HOSTNAME=.*$/HOSTNAME=${NAME}/" /etc/sysconfig/network
service rsyslog restart
resize2fs /dev/xvda1
ws-cli実行時にはいちいちリトライ処理を入れています。
これは今までの経験上、実行に失敗して何度も痛い目を見てきたためです。
ぐぐってもメタデータ取得やaws-cli実行に失敗することに言及している例は見たことがないのですが、結構な頻度で失敗すると感じています。どちらもHTTPなので、ネットワークの状況によっては失敗する前提で考えるのが当たり前なのかもしれませんが。。
注意点として、yumを使うためにEIPを割り当てるかLaunch Wizardで「Automatically assign a public IP address to your instances」にチェックを入れてグローバル IPを持たせてインターネットに出られるようにする必要があることと、IAMのポリシーで「ec2:DescribeTags」権限を付与しておく必要があります。
勢いで書いたものですが試しに実行したらとりあえず動いているようです。。