はじめに
本記事では、AWS-CLIによるAMI作成方法と削除方法について記述します。
また、JenkinsとRedmineを使用したAMI作成・削除の自動化の実現例も合わせて記述します。
実現イメージ
チケット起票(Redmine)→チケット内容取得(Jenkins)→取得内容に合わせてAWS-CLI実行(Jenkins)→起票
チケット更新(Jenkins,Redmine)※
※AWS-CLI実行結果を起票されたチケットに対して更新します。(AMIIDやチケットステータスを更新)
AMI作成
コマンド
aws ec2 create-image --instance-id EC2インスタンスID --name "任意のAMI名" --reboot
説明
--instanceid:AMIの元となるEC2インスタンスIDを指定してください。インスタンスIDはAWSコンソールまたはAWS-CLIだとdescribe-instancesで参照できます。
--name:作成するAMIの名前を指定します。文字の範囲ですが、ASCIIコードまでしか対応されていなかった気がします。曖昧ですみません…
--reboot/--no reboot:AMI作成時にインスタンスを再起動するかを指定します。--no rebootでインスタンスが稼働中にAMIを作成することができます。ただし、公式ドキュメントには以下のように記載されています。可能な限り--rebootを指定して、インスタンスとAMIが同じ状態であることを担保したほうが良いと思います。
[No reboot] を選択した場合、Amazon では作成されたイメージのファイルシステムの整合性を保証できません。
AMI削除
コマンド
aws ec2 deregister-image --image-id 削除したいAMIID
aws ec2 delete-snapshot --snapshot-id AMIに紐づくSnapShotIDを指定
説明
--image-id:削除したいAMIIDを指定します。
SnapShot削除:AMIに紐づくSnapShotを削除しない限り、課金されます。
実装例
Jenkins側(シェルの実行)
#!/bin/bash
#JSON形式でチケット情報を取得(終了チケットを含めて取得)
JSON=$(curl -v -H "Content-Type: application/json" -X GET --data-binary "@issue.json" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定" http://RedmineURLをここに指定/issues.json?status_id=%2a)
#チケットID取得
TicketId=$(echo ${JSON} | jq '.issues[].id')
#チケットステータス取得
TicketStatus=$(echo ${JSON} | jq '.issues[].status | .id')
#チケット進捗率取得
TicketDoneRatio=$(echo ${JSON} | jq '.issues[].done_ratio')
#インスタンスID取得
InstanceId=$(echo ${JSON} | jq '.issues[].description' | sed -e 's/\\r\\n/,/g' | awk -F, '{print $1}' | awk -F: '{print $2}')
#AMI名取得
AmiName=$(echo ${JSON} | jq '.issues[].subject' | sed -e 's/[\" ,]//g')
#取得した値を配列化
TICKET_ID=(`echo ${TicketId}`)
TICKET_STATUS=(`echo ${TicketStatus}`)
TICKET_DONE_RATIO=(`echo ${TicketDoneRatio}`)
INSTANCE_ID=(`echo ${InstanceId}`)
AMI_NAME=(`echo ${AmiName}`)
COUNT=0
for rec in ${TICKET_ID[@]}
do
#チケットステータスが新規のチケットを対象とする
if [ ${TICKET_STATUS[$COUNT]} -eq "1" ]; then
#チケットステータスが新規のみAMI作成
#AMI作成
RET=$(aws ec2 create-image --instance-id ${INSTANCE_ID[$COUNT]} --name "${AMI_NAME[$COUNT]}" --reboot)
#作成したAMIIDを取得
AmiId=$(echo ${RET} | python -m json.tool | grep "ImageId" | awk -F: '{print $2}' | sed -e 's/[\" ,]//g')
#AMIの元となるインスタンスのタグ情報取得
NameTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Name").Value')
ApplicationTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Application").Value')
CostcenterTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Costcenter").Value')
OwnerTag=$(aws ec2 describe-instances --instance-ids ${INSTANCE_ID[$COUNT]} | jq '.Reservations[].Instances[] | .Tags[] | select(.Key=="Owner").Value')
#作成したAMIにタグを付与
aws ec2 create-tags --resources ${AmiId} --tags Key=Name,Value=${NameTag}
aws ec2 create-tags --resources ${AmiId} --tags Key=Application,Value=${ApplicationTag}
aws ec2 create-tags --resources ${AmiId} --tags Key=Costcenter,Value=${CostcenterTag}
aws ec2 create-tags --resources ${AmiId} --tags Key=Owner,Value=${OwnerTag}
#チケットIDをタグに追加
aws ec2 create-tags --resources ${AmiId} --tags Key=TicketId,Value=${TICKET_ID[$COUNT]}
#作成したAMIIDをチケットの履歴に追加
curl -v -H "Content-Type: application/json" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定" -X PUT -d '{"issue":{"notes":"AmiId:'$AmiId'"}}' http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.json
#チケットステータスを"進行中"に更新
curl --include http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.xml -X PUT -d '<issue><status_id>2</status_id></issue>' -H "Content-Type: text/xml" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定"
#チケットステータスが進行中かつ進捗率が0%のチケットを対象とする
elif [ ${TICKET_STATUS[$COUNT]} -eq "5" ] && [ ${TICKET_DONE_RATIO[$COUNT]} -eq 0 ]; then
#チケットステータスが"終了"かつ進捗率が"0%"の場合、AMI削除
#AMI情報取得
AmiList=$(aws ec2 describe-tags --filters "Name=resource-type,Values=image" "Name=key,Values=TicketId" "Name=value,Values=${TICKET_ID[$COUNT]}")
#AMIID取得
DeleteAmiId=$(echo ${AmiList} | jq '.Tags[].ResourceId' | sed -e 's/[\" ,]//g')
#SnapShot情報取得
SnapShotId=$(aws ec2 describe-images --image-ids $DeleteAmiId | jq '.Images[].BlockDeviceMappings[].Ebs | .SnapshotId' | sed -e 's/[\" ,]//g')
#取得した値を配列化
SNAPSHOT_ID=(`echo ${SnapShotId}`)
#AMI削除
aws ec2 deregister-image --image-id $DeleteAmiId
#スナップショット削除
#INT=0
for item in ${SNAPSHOT_ID[@]}
do
aws ec2 delete-snapshot --snapshot-id ${SNAPSHOT_ID[$INT]}
INT=`expr $INT + 1`
done
#進捗率を"100%"に更新
curl --include http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.xml -X PUT -d '<issue><done_ratio>100</done_ratio></issue>' -H "Content-Type: text/xml" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定"
#削除した旨をチケットの履歴に追加
curl --include http://RedmineURLをここに指定/issues/${TICKET_ID[$COUNT]}.xml -X PUT -d "<issue><notes>deleted the AMI.</notes></issue>" -H "Content-Type: text/xml" -H "X-Redmine-API-Key: RedmineAPIキーをここに指定"
fi
COUNT=`expr $COUNT + 1`
done
Redmine側
###チケット記述ルール(チケットテンプレートを活用)
題名:作成したいAMI名を入力
説明:
InstanceId:i-XXXXXXXX(作成したいAMIの元となるEC2インスタンスIDを入力)
Description:開発環境のAMIです。(AMIの情報を入力※入力内容は自由です)