やりたいこと: EC2 インスタンスの Name タグの値を取得し、hostname の変更と、Route53 への登録を cloud-init を使って起動時に自動的に行いたい。
前提条件
- AWS CLI がセットアップされていること。See http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html
- cloud init がインストールされていること (Amazon Linux ならデフォルト。CentOS の場合は yum install -y epel-release && yum install -y cloud-init)
- jq コマンドをインストールしていること。/usr/local/bin/jq においたものとする。
方針
AWS の User-Data を毎回設定するのがダルいので、使わない。スクリプトを仕込んだ状態でイメージを作っておき、以降自動で反映されるようにする
設定
/etc/cloud/cloud.cfg の hostname を更新する行をコメントアウトする。かき消されてしまうため。
cloud_init_modules:
- migrator
- bootcmd
- write-files
- growpart
- resizefs
# - set_hostname
# - update_hostname
# - update_etc_hosts
- rsyslog
- users-groups
- ssh
bootcmd にスクリプトを仕込む。cfg に直接コマンドを書いても良いが、シェルスクリプトに分離したほうが開発が楽。
bootcmd:
- /etc/cloud/cloud.cfg.d/set_hostname.sh
本体のシェルスクリプト。
#!/bin/bash
jq=/usr/local/bin/jq
aws=/usr/local/bin/aws
hosted_zone_id=XXXXXXXX
domain=xxxx.internal
# /root/.aws/credentials および /root/.aws/config があれば不要
# export AWS_ACCESS_KEY_ID=xxxxx
# export AWS_SECRET_ACCESS_KEY=xxxx
# export AWS_DEFAULT_REGION=xxxxx
instance_id=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
json=$($aws ec2 describe-instances --instance-ids $instance_id)
private_ip_address=$(echo $json | $jq -r '.Reservations[0].Instances[0].PrivateIpAddress')
hostname=$(echo $json | $jq -r '.Reservations[].Instances[].Tags[] | select(.Key=="Name").Value')
if [ -z "$hostname" ]; then
echo "Name tag is not set" 1>&2
exit 1
fi
# set hostname
if [ -z $(grep ^HOSTNAME /etc/sysconfig/network) ]; then
echo "HOSTNAME=$hostname" >> /etc/sysconfig/network
else
sed -i "s/^HOSTNAME.*$/HOSTNAME=$hostname/" /etc/sysconfig/network
fi
hostname $hostname
echo "\$ cat /etc/sysconfig/network"
cat /etc/sysconfig/network
# register to Route53
cat > /etc/cloud/cloud.cfg.d/set_hostname.json <<EOF
{
"Comment": "${hostname}",
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": "${hostname}.${domain}",
"Type": "A",
"TTL" : 300 ,
"ResourceRecords": [
{
"Value": "${private_ip_address}"
}
]
}
}
]
}
EOF
echo "\$ cat /etc/cloud/cloud.cfg.d/set_hostname.json"
cat /etc/cloud/cloud.cfg.d/set_hostname.json
echo "\$ $aws route53 change-resource-record-sets --hosted-zone-id $hosted_zone_id --change-batch file:////etc/cloud/cloud.cfg.d/set_hostname.json"
$aws route53 change-resource-record-sets --hosted-zone-id $hosted_zone_id --change-batch file:////etc/cloud/cloud.cfg.d/set_hostname.json
ハマったメモ
ログインしてシェルからスクリプトを実行すると成功するのに、cloud-init で boot プロセス時に処理させると、aws ec2 describe-instances で
A client error (AuthFailure) occurred when calling the DescribeInstances operation: AWS was not able to validate the provided access credentials
Name tag is not set
2015-08-10 15:58:41,538 - util.py[WARNING]: Failed to run bootcmd module bootcmd
2015-08-10 15:58:41,540 - util.py[WARNING]: Running bootcmd (<module 'cloudinit.config.cc_bootcmd' from '/usr/lib/python2.6/site-packages/cloudinit/config/cc_bootcmd.pyc'>) failed
とエラーが出ていた。cf. https://gist.github.com/sonots/5d7b6ff1bff5b78cb2bb
これは時刻設定が間違っていて、hwclock がズレているせいだった。aws cli は時刻があっていないと認証に失敗する。エラーメッセージから全くわからなくてハマってた。
自分の場合は、/etc/sysconfig/clock と /etc/localtime は設定していたが、/etc/adjtime (勝手に設定されると書いている文献もある)の設定がズレており、時刻がズレてしまっていた。
参考
- 再起動で時刻がズレる場合の対処法 http://www.server-memo.net/server-setting/ntp/ntp-time-shift.html
- パソコンの時計 ハードウェア クロックとシステム クロック http://park12.wakwak.com/~eslab/pcmemo/clock/clock3.html
- システム言語の設定ファイル http://webbox0120.com/wb-os/linux-conf.html
- Linuxの時間管理の仕組み http://itblog.posifeel.com/2013/09/26/linux-date-system/