はじめに
AWSのEC2インスタンスを別リージョンに移設する必要があったため、対象EC2インスタンスID.ソースリージョン、ターゲットリージョンを指定して、AMIを作成し、別リージョンにコピーするスクリプトを作成しました。
前提
- AWS CLIがインストールされていること
- AWS ConfigureでIAM認証情報が設定されていること
スクリプトの概要
このスクリプトは以下の機能を提供します:
- 指定されたEC2インスタンスからAMIを作成
- AMI作成を待って、作成したAMIを別リージョンにコピー
スクリプト
スクリプトファイル内容
#!/bin/bash
set -e
# ヘルプメッセージの表示
show_help() {
cat << EOF
EC2インスタンスを別リージョンにコピーするスクリプト
使用方法:
$(basename $0) [オプション]
オプション:
--instance-id コピー元のEC2インスタンスID(必須)
--source-region コピー元のAWSリージョン(必須)
--target-region コピー先のAWSリージョン(必須)
--ami-name AMIの名前(オプション)
--help このヘルプメッセージを表示
例:
# AMI名を指定する場合
$(basename $0) --instance-id i-1234567890abcdef0 --source-region ap-northeast-1 --target-region us-west-2 --ami-name "custom-ami-name"
# AMI名を指定しない場合(EC2のNameタグから自動生成)
$(basename $0) --instance-id i-1234567890abcdef0 --source-region ap-northeast-1 --target-region us-west-2
EOF
exit 1
}
# エラーメッセージを表示して終了
error_exit() {
echo "エラー: $1" >&2
exit 1
}
# 引数のパース
while [[ $# -gt 0 ]]; do
case $1 in
--help)
show_help
;;
--instance-id)
INSTANCE_ID="$2"
shift 2
;;
--source-region)
SOURCE_REGION="$2"
shift 2
;;
--target-region)
TARGET_REGION="$2"
shift 2
;;
--ami-name)
CUSTOM_AMI_NAME="$2"
shift 2
;;
*)
error_exit "不明な引数: $1"
;;
esac
done
# 必須パラメータのチェック
[[ -z "$INSTANCE_ID" ]] && error_exit "instance-idは必須です"
[[ -z "$SOURCE_REGION" ]] && error_exit "source-regionは必須です"
[[ -z "$TARGET_REGION" ]] && error_exit "target-regionは必須です"
# インスタンスIDの形式チェック
[[ ! "$INSTANCE_ID" =~ ^i-[a-f0-9]{8,}$ ]] && error_exit "無効なインスタンスID形式です: $INSTANCE_ID"
# AWS CLIの存在確認
command -v aws >/dev/null 2>&1 || error_exit "AWS CLIがインストールされていません"
echo "パラメータの確認:"
echo "インスタンスID: $INSTANCE_ID"
echo "ソースリージョン: $SOURCE_REGION"
echo "ターゲットリージョン: $TARGET_REGION"
# EC2インスタンスの存在確認とNameタグの取得
echo "EC2インスタンスの情報を取得中..."
INSTANCE_INFO=$(aws ec2 describe-instances \
--instance-ids "$INSTANCE_ID" \
--region "$SOURCE_REGION" \
--query 'Reservations[0].Instances[0]' \
--output json 2>/dev/null) || error_exit "インスタンスの取得に失敗しました"
# AMI名の設定
if [[ -n "$CUSTOM_AMI_NAME" ]]; then
AMI_NAME="$CUSTOM_AMI_NAME"
else
# Nameタグの取得
INSTANCE_NAME=$(echo "$INSTANCE_INFO" | jq -r '.Tags[] | select(.Key=="Name") | .Value' 2>/dev/null)
if [[ -z "$INSTANCE_NAME" ]]; then
error_exit "指定されたEC2インスタンス($INSTANCE_ID)にNameタグが設定されていません。--ami-nameオプションでAMI名を指定してください。"
fi
AMI_NAME="${INSTANCE_NAME}_AMI"
fi
echo "AMI名: $AMI_NAME"
# AMIの作成
echo "AMIを作成中..."
AMI_ID=$(aws ec2 create-image \
--instance-id "$INSTANCE_ID" \
--name "$AMI_NAME" \
--description "Created from $INSTANCE_ID" \
--region "$SOURCE_REGION" \
--no-reboot \
--output text) || error_exit "AMIの作成に失敗しました"
echo "AMI ID: $AMI_ID"
# AMI状態の待機処理
wait_for_image() {
local image_id=$1
local region=$2
local retries=6
local attempt=1
while [ $attempt -le $retries ]; do
echo "AMI状態確認: 試行 $attempt/$retries"
if aws ec2 wait image-available --image-ids "$image_id" --region "$region"; then
return 0
fi
attempt=$((attempt + 1))
if [ $attempt -le $retries ]; then
echo "リトライします..."
fi
done
return 1
}
# AMI作成完了を待機
echo "AMIの作成完了を待機中..."
if ! wait_for_image "$AMI_ID" "$SOURCE_REGION"; then
error_exit "AMIの作成待機中にエラーが発生しました(6回試行後)"
fi
echo "AMIの作成が完了しました"
# AMIを別リージョンにコピー
echo "AMIを $TARGET_REGION にコピー中..."
COPIED_AMI_ID=$(aws ec2 copy-image \
--source-image-id "$AMI_ID" \
--source-region "$SOURCE_REGION" \
--region "$TARGET_REGION" \
--name "$AMI_NAME" \
--output text) || error_exit "AMIのコピーに失敗しました"
echo "コピーされたAMI ID: $COPIED_AMI_ID"
# AMIコピーの完了を待機
echo "AMIのコピー完了を待機中..."
if ! wait_for_image "$COPIED_AMI_ID" "$TARGET_REGION"; then
error_exit "AMIのコピー待機中にエラーが発生しました(6回試行後)"
fi
echo "処理が正常に完了しました"
echo "ソースAMI ID (${SOURCE_REGION}): ${AMI_ID}"
echo "コピー先AMI ID (${TARGET_REGION}): ${COPIED_AMI_ID}"
使用方法
./copy-ec2.sh [オプション]
オプション:
--instance-id コピー元のEC2インスタンスID(必須)
--source-region コピー元のAWSリージョン(必須)
--target-region コピー先のAWSリージョン(必須)
--ami-name AMIの名前(オプション)
--help このヘルプメッセージを表示
実行例
# AMI名を指定する場合
./copy-ec2.sh --instance-id i-1234567890abcdef0 --source-region ap-northeast-1 --target-region us-west-2 --ami-name "custom-ami-name"
# AMI名を指定しない場合(EC2のNameタグから自動生成)
./copy-ec2.sh --instance-id i-1234567890abcdef0 --source-region ap-northeast-1 --target-region us-west-2
スクリプトの主要な機能
1. パラメータの検証
# 必須パラメータのチェック
[[ -z "$INSTANCE_ID" ]] && error_exit "instance-idは必須です"
[[ -z "$SOURCE_REGION" ]] && error_exit "source-regionは必須です"
[[ -z "$TARGET_REGION" ]] && error_exit "target-regionは必須です"
# インスタンスIDの形式チェック
[[ ! "$INSTANCE_ID" =~ ^i-[a-f0-9]{8,}$ ]] && error_exit "無効なインスタンスID形式です: $INSTANCE_ID"
2. AMI名の設定
AMI名は以下の優先順位で決定されます:
-
--ami-name
オプションで指定された値 - EC2インスタンスのNameタグの値 + "_AMI"
if [[ -n "$CUSTOM_AMI_NAME" ]]; then
AMI_NAME="$CUSTOM_AMI_NAME"
else
INSTANCE_NAME=$(echo "$INSTANCE_INFO" | jq -r '.Tags[] | select(.Key=="Name") | .Value' 2>/dev/null)
if [[ -z "$INSTANCE_NAME" ]]; then
error_exit "指定されたEC2インスタンス($INSTANCE_ID)にNameタグが設定されていません。--ami-nameオプションでAMI名を指定してください。"
fi
AMI_NAME="${INSTANCE_NAME}_AMI"
fi
3. AMIの作成とコピー
AMIの作成とコピーは以下の手順で行われます:
- ソースリージョンでAMIを作成
- AMIの作成完了を待機
- ターゲットリージョンにAMIをコピー
- コピーの完了を待機
# AMIの作成
AMI_ID=$(aws ec2 create-image \
--instance-id "$INSTANCE_ID" \
--name "$AMI_NAME" \
--description "Created from $INSTANCE_ID" \
--region "$SOURCE_REGION" \
--no-reboot \
--output text)
# AMIを別リージョンにコピー
COPIED_AMI_ID=$(aws ec2 copy-image \
--source-image-id "$AMI_ID" \
--source-region "$SOURCE_REGION" \
--region "$TARGET_REGION" \
--name "$AMI_NAME" \
--output text)
まとめ
AMI作成やコピーに時間がかかるため、GUIで作業すると待機時間がかかるため、スクリプトで自動化することで、放置している間に作業が完了するため、便利かなと思い、作成しました。