AWS-CLIによるAMI作成と削除自動化(JSON取得によるRedmineチケット駆動)


はじめに

本記事では、AWS-CLIによるAMI作成方法と削除方法について記述します。
また、JenkinsとRedmineを使用したAMI作成・削除の自動化の実現例も合わせて記述します。

実現イメージ

チケット起票(Redmine)→チケット内容取得(Jenkins)→取得内容に合わせてAWS-CLI実行(Jenkins)→起票
チケット更新(Jenkins,Redmine)※

※AWS-CLI実行結果を起票されたチケットに対して更新します。(AMIIDやチケットステータスを更新)

AMI作成

コマンド

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削除

コマンド

AMI削除
aws ec2 deregister-image --image-id 削除したいAMIID
SnapShot削除
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の情報を入力※入力内容は自由です)