特定のEBSボリュームをgp2からgp3へ一括変換するスクリプトを作ってみた

特定のEBSボリュームをgp2からgp3へ一括変換するスクリプトを作ってみた

EBSボリュームのgp2からgp3への変換は、コスト最適化の重要な施策の一つです。今回は、変換前のスナップショット取得やロールバック対応も考慮した、安全な一括変換スクリプトをご紹介します。
Clock Icon2025.02.26

こんにちは!クラウド事業本部のおつまみです。

今回あるアカウントにて、大量のEBSボリュームに対して、gp2からgp3への変更する必要がありました。
大量のボリュームを手動で変換するのは手間がかかります。
そこで一括変換できるスクリプトを作成しました。

今回はそのスクリプトをご紹介したいと思います!

前提条件

スクリプトを実行する前に、gp2からgp3への変換が適切かどうか検討する必要があります。

基本的にgp3はgp2の上位後継タイプとして位置づけられており、同等の性能を確保する場合、コスト面でgp3の方が有利です。また、変換時に再起動は不要です。
一方変換時には、以下の点に注意が必要です。

  • 旧世代のインスタンスタイプを使用している場合は、変換を避けることを推奨
  • レイテンシーについては、gp2の方が低い傾向にあるため、シングルスレッドの処理が重要な場合はgp2の方が適している可能性あり

変換を検討される際は、以下の記事も参考にしてください。

実装したスクリプト

作成したスクリプトはこちらです。トグルを開くと内容を確認できます。

convert_ebs.sh
#!/bin/bash

# 入力ファイルの確認
if [ -z "$1" ]; then
    echo "エラー: ボリュームIDを含む入力ファイルを指定してください"
    echo "使用方法: $0 <入力ファイル>"
    exit 1
fi

INPUT_FILE=$1

# ファイルの存在確認
if [ ! -f "$INPUT_FILE" ]; then
    echo "エラー: 入力ファイル $INPUT_FILE が存在しません"
    exit 1
fi

# スナップショット作成の選択
read -p "変換前にスナップショットを作成しますか? (y/n): " create_snapshot
case $create_snapshot in
    [Yy]* )
        snapshot_enabled=true
        echo "スナップショットを作成します"
        ;;
    [Nn]* )
        snapshot_enabled=false
        echo "スナップショットを作成せずに処理を続行します"
        ;;
    * )
        echo "エラー: y または n を入力してください"
        exit 1
        ;;
esac

# ボリュームの変換関数
convert_volume() {
    local volume_id=$1

    # ボリュームの現在の状態を確認
    echo "ボリューム $volume_id を確認中..."

    # ボリュームの存在確認とタイプチェック
    volume_info=$(aws ec2 describe-volumes \
        --volume-ids "$volume_id" \
        --query 'Volumes[0].[VolumeType,Tags]' \
        --output json 2>/dev/null)

    if [ $? -ne 0 ]; then
        echo "ボリューム $volume_id が存在しないかアクセスできません"
        return 1
    fi

    volume_type=$(echo "$volume_info" | jq -r '.[0]')

    if [ "$volume_type" != "gp2" ]; then
        echo "ボリューム $volume_id は gp2 ではありません(現在のタイプ: $volume_type)。スキップします..."
        return 2
    fi

    # スナップショットの作成(選択された場合のみ)
    if [ "$snapshot_enabled" = true ]; then
        echo "ボリューム $volume_id のスナップショットを作成中..."

        # ボリュームの名前を取得(存在する場合)
        volume_name=$(aws ec2 describe-volumes \
            --volume-ids "$volume_id" \
            --query 'Volumes[0].Tags[?Key==`Name`].Value' \
            --output text)

        # 日本時間の日時を取得
        jst_date=$(TZ=Asia/Tokyo date '+%Y%m%d-%H%M%S')
        jst_datetime=$(TZ=Asia/Tokyo date '+%Y-%m-%d %H:%M:%S')

        # スナップショットの名前を設定
        if [ -n "$volume_name" ] && [ "$volume_name" != "None" ]; then
            snapshot_name="Backup-${volume_name}-gp2-to-gp3-${jst_date}"
        else
            snapshot_name="Backup-${volume_id}-gp2-to-gp3-${jst_date}"
        fi

        snapshot_id=$(aws ec2 create-snapshot \
            --volume-id "$volume_id" \
            --description "gp2 to gp3 conversion backup - ${jst_datetime} JST" \
            --tag-specifications "ResourceType=snapshot,Tags=[{Key=Name,Value=\"$snapshot_name\"},{Key=Purpose,Value=gp2-gp3-conversion-backup}]" \
            --query 'SnapshotId' \
            --output text)

        if [ $? -ne 0 ]; then
            echo "スナップショットの作成に失敗しました"
            return 1
        fi

        echo "スナップショット $snapshot_id を作成中... (Name: $snapshot_name)"

        # スナップショットの完了を待機
        while true; do
            snapshot_status=$(aws ec2 describe-snapshots \
                --snapshot-ids "$snapshot_id" \
                --query 'Snapshots[0].State' \
                --output text)

            if [ "$snapshot_status" = "completed" ]; then
                echo "スナップショット $snapshot_id の作成が完了しました"
                break
            elif [ "$snapshot_status" = "error" ]; then
                echo "スナップショットの作成に失敗しました"
                return 1
            fi
            echo "スナップショット作成中... 現在の状態: $snapshot_status"
            sleep 10
        done
    fi

    # gp2からgp3への変換を実行
    echo "ボリューム $volume_id を gp2 から gp3 に変換中..."
    aws ec2 modify-volume \
        --volume-id "$volume_id" \
        --volume-type gp3

    if [ $? -eq 0 ]; then
        echo "ボリューム $volume_id の変換を開始しました"

        # 変換状態の監視
        while true; do
            status=$(aws ec2 describe-volumes-modifications \
                --volume-ids "$volume_id" \
                --query 'VolumesModifications[0].ModificationState' \
                --output text)

            case $status in
                "optimizing"|"modifying")
                    echo "ボリューム $volume_id: 変換処理中..."
                    sleep 5
                    ;;
                "completed")
                    # 実際のボリュームタイプを確認
                    current_type=$(aws ec2 describe-volumes \
                        --volume-ids "$volume_id" \
                        --query 'Volumes[0].VolumeType' \
                        --output text)

                    if [ "$current_type" = "gp3" ]; then
                        echo "ボリューム $volume_id: gp3への変換が完了しました"
                        if [ "$snapshot_enabled" = true ]; then
                            echo "作成したスナップショットID: $snapshot_id (ロールバック用に保持してください)"
                        fi
                        return 0
                    else
                        echo "ボリューム $volume_id: 変換に失敗しました(タイプが $current_type のまま)"
                        if [ "$snapshot_enabled" = true ]; then
                            echo "スナップショット $snapshot_id を使用して復元できます"
                        fi
                        return 1
                    fi
                    ;;
                "failed")
                    echo "ボリューム $volume_id: 変換に失敗しました。状態: $status"
                    if [ "$snapshot_enabled" = true ]; then
                        echo "スナップショット $snapshot_id を使用して復元できます"
                    fi
                    return 1
                    ;;
                *)
                    echo "ボリューム $volume_id: 予期しない状態です: $status"
                    if [ "$snapshot_enabled" = true ]; then
                        echo "スナップショット $snapshot_id を使用して復元できます"
                    fi
                    return 1
                    ;;
            esac
        done
    else
        echo "ボリューム $volume_id の変換開始に失敗しました"
        return 1
    fi
}

# メイン処理
echo "EBSボリューム変換プロセスを開始します..."
echo "入力ファイル $INPUT_FILE からボリュームIDを読み込みます"

# 結果をカウント
success_count=0
fail_count=0
skip_count=0

# ファイルの各行を処理
while IFS= read -r volume_id || [ -n "$volume_id" ]; do
    # 空行とコメントをスキップ
    [[ -z "$volume_id" || "$volume_id" =~ ^[[:space:]]*# ]] && continue

    # 先頭と末尾の空白を削除
    volume_id=$(echo "$volume_id" | tr -d '[:space:]')

    convert_volume "$volume_id"
    result=$?

    case $result in
        0)
            ((success_count++))
            ;;
        1)
            ((fail_count++))
            ;;
        2)
            ((skip_count++))
            ;;
    esac
done < "$INPUT_FILE"

# 結果サマリーの表示
echo
echo "変換結果サマリー:"
echo "変換成功: $success_count"
echo "変換失敗: $fail_count"
echo "スキップ: $skip_count"

スクリプトの説明

外部ファイルで指定したEBSボリュームをgp2からgp3に一括変換するスクリプトです。
主な機能は以下の通りです。

主な機能

  1. 選択的な変換
    • 指定したボリュームのみを変換
    • 外部ファイルでボリュームIDを管理
  2. スナップショット管理
    • 変換前のスナップショット取得(オプション)
    • ボリューム名もしくはボリュームIDでのスナップショット名付け
  3. 変換状態の監視
    • リアルタイムでの進捗表示
    • 変換完了の確実な検知
    • エラー時の適切な通知
  4. 結果管理
    • 変換成功/失敗/スキップの集計
    • 処理結果のサマリー表示

スクリプトの使用手順

1. CloudShellの起動

AWSマネジメントコンソールの右上にあるCloudShellアイコンをクリックして起動します。

コンソールのホーム___コンソールのホーム___ap-northeast-1

2. スクリプトの準備

CloudShellで以下のコマンドを実行し、スクリプトファイルを作成します。作成後、実行権限を付与します。

# スクリプトファイルの作成
cat << 'EOF' > convert_ebs.sh
[スクリプト本体をここにペースト]
EOF

# 実行権限の付与
chmod +x convert_ebs.sh

3. 変換対象ボリュームの準備

変換したいボリュームのIDを記載したテキストファイルを作成します。

# volume_ids.txtの作成
cat << EOF > volume_ids.txt
vol-xxxxxxxxxxxxxxxxx
vol-yyyyyyyyyyyyyyyyy
vol-zzzzzzzzzzzzzzzzz
EOF

# 作成したファイルの確認
cat volume_ids.txt

4. スクリプトの実行

以下のコマンドを実行し、スクリプトを実行します。

./convert_ebs.sh volume_ids.txt

5. 実行時の流れ

まず、変換前にスナップショットを作成するかどうか聞かれます。スナップショットが必要な場合はy、不要な場合はnを入力します。本番環境の場合は念の為、スナップショットを取得していくことを推奨します。(6時間経過後にgp3 → gp2への変更が可能となります。)

変換前にスナップショットを作成しますか? (y/n):

変換処理状況が自動で表示されます。

EBSボリューム変換プロセスを開始します...
入力ファイル volume_ids.txt からボリュームIDを読み込みます
ボリューム vol-xxxxxxxxxxxxxxxxx を確認中...
ボリューム vol-xxxxxxxxxxxxxxxxx のスナップショットを作成中...
スナップショット snap-yyyyyyyyyyyyyyy を作成中... (Name: Backup-test-vol-xxxxxxxxxxxxxxxxx-yyyymmdd-hhmmss)
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット snap-yyyyyyyyyyyyyyy の作成が完了しました
ボリューム vol-xxxxxxxxxxxxxxxxx を gp2 から gp3 に変換中...
{
    "VolumeModification": {
        "VolumeId": "vol-xxxxxxxxxxxxxxxxx",
        "ModificationState": "modifying",
        "TargetSize": 10,
        "TargetIops": 3000,
        "TargetVolumeType": "gp3",
        "TargetThroughput": 125,
        "TargetMultiAttachEnabled": false,
        "OriginalSize": 10,
        "OriginalIops": 100,
        "OriginalVolumeType": "gp2",
        "OriginalMultiAttachEnabled": false,
        "Progress": 0,
        "StartTime": "yyyy-mm-ddThh:mm:ss+00:00"
    }
}
ボリューム vol-xxxxxxxxxxxxxxxxx の変換を開始しました
ボリューム vol-xxxxxxxxxxxxxxxxx: 変換処理中...
ボリューム vol-xxxxxxxxxxxxxxxxx: gp3への変換が完了しました
作成したスナップショットID: snap-yyyyyyyyyyyyyyy (ロールバック用に保持してください)

全ボリュームの変換処理が完了すると、結果サマリーが表示されます。

変換結果サマリー:
変換成功: X
変換失敗: Y
スキップ: Z

「変換成功」は指定したgp2ボリュームがgp3への変換を完了し、ボリュームタイプの確認でgp3となっているケースがカウントされます。
「変換失敗」はボリュームが存在しない場合、APIアクセスエラー、スナップショット作成失敗、変換プロセスの失敗など、正常に完了しなかったケースがカウントされます。
「スキップ」は指定したボリュームがgp2以外の場合(例:gp3、io1、io2など)にカウントされます。

6. 実行結果の確認

変換後、以下のコマンドで結果を確認できます

# 変換したボリュームの状態確認
aws ec2 describe-volumes --volume-ids $(cat volume_ids.txt) --query 'Volumes[*].[VolumeId,VolumeType,State]' --output table

# 作成されたスナップショットの確認(スナップショットを作成した場合)
aws ec2 describe-snapshots --filters "Name=tag:Purpose,Values=gp2-gp3-conversion-backup" --query 'Snapshots[*].[SnapshotId,VolumeId,Tags[?Key==`Name`].Value|[0]]' --output table

スナップショット名は以下どちらかの命名規則で保存されます。

  • ボリュームに有効なNameタグがある場合:Backup-{ボリューム名}-gp2-to-gp3-{日時(JST)}
  • ボリュームにNameタグがない場合:Backup-{ボリュームID}-gp2-to-gp3-{日時(JST)}

7. スナップショットの削除

一定期間経過し、gp3に変換したことによる不具合が出ていなければ、オプションで取得したスナップショットは削除します。

# スナップショットの削除
for snapshot_id in $(aws ec2 describe-snapshots --filters "Name=tag:Purpose,Values=gp2-gp3-conversion-backup" --query 'Snapshots[*].SnapshotId' --output text); do
    echo "Deleting snapshot: $snapshot_id"
    aws ec2 delete-snapshot --snapshot-id $snapshot_id
done

万一、gp3変換後に不具合が生じた場合は以下を実施してください。

やってみた

作成したスクリプトで検証します。

1.テスト用ボリュームの作成

CloudShellで以下コマンドを実行し、テスト用ボリュームを作成します。

# 変換対象のgp2ボリューム作成(Nameタグ付き)
aws ec2 create-volume \
    --volume-type gp2 \
    --size 10 \
    --availability-zone ap-northeast-1a \
    --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=test-vol-1},{Key=Convert,Value=true}]'

# 変換対象のgp2ボリューム作成(Nameタグなし)
aws ec2 create-volume \
    --volume-type gp2 \
    --size 10 \
    --availability-zone ap-northeast-1a \
    --tag-specifications 'ResourceType=volume,Tags=[{Key=Convert,Value=true}]'

# 変換しないgp2ボリューム作成(Nameタグ付き)
aws ec2 create-volume \
    --volume-type gp2 \
    --size 10 \
    --availability-zone ap-northeast-1a \
    --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=test-vol-no-convert},{Key=Convert,Value=false}]'

# スキップ確認用のgp3ボリューム作成(Nameタグ付き)
aws ec2 create-volume \
    --volume-type gp3 \
    --size 10 \
    --availability-zone ap-northeast-1a \
    --tag-specifications 'ResourceType=volume,Tags=[{Key=Name,Value=test-vol-gp3},{Key=Convert,Value=true}]'

4つのEBSボリュームが作成されました。test-vol-no-convert以外のボリュームを指定して、gp2→gp3変換スクリプトを実行します。

ボリューム___EC2___ap-northeast-1

2.スクリプト・変換対象ボリュームの準備

使用手順2,3に従ってスクリプトファイルおよびボリューム一覧を準備します。

実行結果
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ cat << 'EOF' > convert_ebs.sh
> #!/bin/bash
> 
> # 入力ファイルの確認
> if [ -z "$1" ]; then
>     echo "エラー: ボリュームIDを含む入力ファイルを指定してください"
>     echo "使用方法: $0 <入力ファイル>"
>     exit 1
> fi
> 
> INPUT_FILE=$1
> 
> # ファイルの存在確認
> if [ ! -f "$INPUT_FILE" ]; then
>     echo "エラー: 入力ファイル $INPUT_FILE が存在しません"
>     exit 1
> fi
> 
> # スナップショット作成の選択
> read -p "変換前にスナップショットを作成しますか? (y/n): " create_snapshot
> case $create_snapshot in
n>     [Yy]* )
>         snapshot_enabled=true
>         echo "スナップショットを作成します"
>         ;;
>     [Nn]* )
 >         snapshot_enabled=false
>         echo "スナップショットを作成せずに処理を続行します"
>         ;;
>     * )
>         echo "エラー: y または n を入力してください"
>         exit 1
>         ;;
> esac
> 
> # ボリュームの変換関数
> convert_volume() {
>     local volume_id=$1
>     
>     # ボリュームの現在の状態を確認
>     echo "ボリューム $volume_id を確認中..."
>     
>     # ボリュームの存在確認とタイプチェック
>     volume_info=$(aws ec2 describe-volumes \
>         --volume-ids "$volume_id" \
>         --query 'Volumes[0].[VolumeType,Tags]' \
>         --output json 2>/dev/null)
>     
>     if [ $? -ne 0 ]; then
>         echo "ボリューム $volume_id が存在しないかアクセスできません"
>         return 1
>     fi
>     
>     volume_type=$(echo "$volume_info" | jq -r '.[0]')
>     
>     if [ "$volume_type" != "gp2" ]; then
>         echo "ボリューム $volume_id は gp2 ではありません(現在のタイプ: $volume_type)。スキップします..."
>         return 2
>     fi
> 
>     # スナップショットの作成(選択された場合のみ)
>     if [ "$snapshot_enabled" = true ]; then
>         echo "ボリューム $volume_id のスナップショットを作成中..."
>         
>         # ボリュームの名前を取得(存在する場合)
>         volume_name=$(aws ec2 describe-volumes \
>             --volume-ids "$volume_id" \
>             --query 'Volumes[0].Tags[?Key==`Name`].Value' \
>             --output text)
>         
>         # 日本時間の日時を取得
>         jst_date=$(TZ=Asia/Tokyo date '+%Y%m%d-%H%M%S')
>         jst_datetime=$(TZ=Asia/Tokyo date '+%Y-%m-%d %H:%M:%S')
>         
>         # スナップショットの名前を設定
>         if [ -n "$volume_name" ] && [ "$volume_name" != "None" ]; then
>             snapshot_name="Backup-${volume_name}-gp2-to-gp3-${jst_date}"
>         else
>             snapshot_name="Backup-${volume_id}-gp2-to-gp3-${jst_date}"
>         fi
>         
>         snapshot_id=$(aws ec2 create-snapshot \
>             --volume-id "$volume_id" \
>             --description "gp2 to gp3 conversion backup - ${jst_datetime} JST" \
>             --tag-specifications "ResourceType=snapshot,Tags=[{Key=Name,Value=\"$snapshot_name\"},{Key=Purpose,Value=gp2-gp3-conversion-backup}]" \
>             --query 'SnapshotId' \
>             --output text)
> 
>         if [ $? -ne 0 ]; then
>             echo "スナップショットの作成に失敗しました"
>             return 1
>         fi
> 
>         echo "スナップショット $snapshot_id を作成中... (Name: $snapshot_name)"
> 
>         # スナップショットの完了を待機
>         while true; do
>             snapshot_status=$(aws ec2 describe-snapshots \
>                 --snapshot-ids "$snapshot_id" \
>                 --query 'Snapshots[0].State' \
>                 --output text)
>             
>             if [ "$snapshot_status" = "completed" ]; then
>                 echo "スナップショット $snapshot_id の作成が完了しました"
>                 break
>             elif [ "$snapshot_status" = "error" ]; then
>                 echo "スナップショットの作成に失敗しました"
>                 return 1
>             fi
>             echo "スナップショット作成中... 現在の状態: $snapshot_status"
>             sleep 10
>         done
>     fi
>     
>     # gp2からgp3への変換を実行
>     echo "ボリューム $volume_id を gp2 から gp3 に変換中..."
>     aws ec2 modify-volume \
>         --volume-id "$volume_id" \
>         --volume-type gp3
> 
>     if [ $? -eq 0 ]; then
>         echo "ボリューム $volume_id の変換を開始しました"
>         
>         # 変換状態の監視
>         while true; do
>             status=$(aws ec2 describe-volumes-modifications \
>                 --volume-ids "$volume_id" \
>                 --query 'VolumesModifications[0].ModificationState' \
>                 --output text)
>             
>             case $status in
>                 "optimizing"|"modifying")
>                     echo "ボリューム $volume_id: 変換処理中..."
>                     sleep 5
>                     ;;
>                 "completed")
>                     # 実際のボリュームタイプを確認
>                     current_type=$(aws ec2 describe-volumes \
>                         --volume-ids "$volume_id" \
>                         --query 'Volumes[0].VolumeType' \
>                         --output text)
>                     
>                     if [ "$current_type" = "gp3" ]; then
>                         echo "ボリューム $volume_id: gp3への変換が完了しました"
>                         if [ "$snapshot_enabled" = true ]; then
>                             echo "作成したスナップショットID: $snapshot_id (ロールバック用に保持してください)"
>                         fi
>                         return 0
>                     else
>                         echo "ボリューム $volume_id: 変換に失敗しました(タイプが $current_type のまま)"
>                         if [ "$snapshot_enabled" = true ]; then
>                             echo "スナップショット $snapshot_id を使用して復元できます"
>                         fi
>                         return 1
>                     fi
>                     ;;
>                 "failed")
>                     echo "ボリューム $volume_id: 変換に失敗しました。状態: $status"
>                     if [ "$snapshot_enabled" = true ]; then
>                         echo "スナップショット $snapshot_id を使用して復元できます"
>                     fi
>                     return 1
>                     ;;
>                 *)
>                     echo "ボリューム $volume_id: 予期しない状態です: $status"
>                     if [ "$snapshot_enabled" = true ]; then
>                         echo "スナップショット $snapshot_id を使用して復元できます"
>                     fi
>                     return 1
>                     ;;
>             esac
>         done
>     else
>         echo "ボリューム $volume_id の変換開始に失敗しました"
>         return 1
>     fi
> }
> 
> # メイン処理
> echo "EBSボリューム変換プロセスを開始します..."
> echo "入力ファイル $INPUT_FILE からボリュームIDを読み込みます"
> 
> # 結果をカウント
> success_count=0
> fail_count=0
> skip_count=0
> 
> # ファイルの各行を処理
> while IFS= read -r volume_id || [ -n "$volume_id" ]; do
>     # 空行とコメントをスキップ
>     [[ -z "$volume_id" || "$volume_id" =~ ^[[:space:]]*# ]] && continue
>     
>     # 先頭と末尾の空白を削除
>     volume_id=$(echo "$volume_id" | tr -d '[:space:]')
>     
>     convert_volume "$volume_id"
>     result=$?
>     
>     case $result in
>         0)
>             ((success_count++))
>             ;;
>         1)
>             ((fail_count++))
>             ;;
>         2)
>             ((skip_count++))
>             ;;
>     esac
> done < "$INPUT_FILE"
> 
> # 結果サマリーの表示
> echo
> echo "変換結果サマリー:"
> echo "変換成功: $success_count"
> echo "変換失敗: $fail_count"
> echo "スキップ: $skip_count"
> EOF
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ 
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ # 実行権限の付与
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ chmod +x convert_ebs.sh
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ ll
total 66164
drwxr-xr-x. 3 cloudshell-user cloudshell-user     4096 Feb 25 19:21 aws
-rw-r--r--. 1 cloudshell-user cloudshell-user 67721962 Feb 26 02:35 awscliv2.zip
-rwxr-xr-x. 1 cloudshell-user cloudshell-user     7833 Feb 26 02:39 convert_ebs.sh
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ # volume_ids.txtの作成
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ cat << EOF > volume_ids.txt
> vol-0a9752d8695a2a361 
> vol-02da57b42c1f6b0e9
> vol-0e567c76a60b71528
> EOF
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ 
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ # 作成したファイルの確認
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ cat volume_ids.txt
vol-0a9752d8695a2a361 
vol-02da57b42c1f6b0e9
vol-0e567c76a60b71528

3.スクリプトの実行

使用手順4,5に従ってスクリプトを実行します。
今回は3ボリューム(うち1ボリュームはスキップ)だったため、2~3分で処理が完了しました。

実行結果
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ ./convert_ebs.sh volume_ids.txt
変換前にスナップショットを作成しますか? (y/n): y
スナップショットを作成します
EBSボリューム変換プロセスを開始します...
入力ファイル volume_ids.txt からボリュームIDを読み込みます
ボリューム vol-004373c1f59e29646 を確認中...
ボリューム vol-004373c1f59e29646 のスナップショットを作成中...
スナップショット snap-041788273d8cbe3b1 を作成中... (Name: Backup-vol-004373c1f59e29646-gp2-to-gp3-20250226-115247)
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット snap-041788273d8cbe3b1 の作成が完了しました
ボリューム vol-004373c1f59e29646 を gp2 から gp3 に変換中...
{
    "VolumeModification": {
        "VolumeId": "vol-004373c1f59e29646",
        "ModificationState": "modifying",
        "TargetSize": 10,
        "TargetIops": 3000,
        "TargetVolumeType": "gp3",
        "TargetThroughput": 125,
        "TargetMultiAttachEnabled": false,
        "OriginalSize": 10,
        "OriginalIops": 100,
        "OriginalVolumeType": "gp2",
        "OriginalMultiAttachEnabled": false,
        "Progress": 0,
        "StartTime": "2025-02-26T02:53:42+00:00"
    }
}
ボリューム vol-004373c1f59e29646 の変換を開始しました
ボリューム vol-004373c1f59e29646: 変換処理中...
ボリューム vol-004373c1f59e29646: gp3への変換が完了しました
作成したスナップショットID: snap-041788273d8cbe3b1 (ロールバック用に保持してください)
ボリューム vol-097ec3db03ae36526 を確認中...
ボリューム vol-097ec3db03ae36526 のスナップショットを作成中...
スナップショット snap-03cf1d0b1d5165fad を作成中... (Name: Backup-test-vol-1-gp2-to-gp3-20250226-115351)
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット作成中... 現在の状態: pending
スナップショット snap-03cf1d0b1d5165fad の作成が完了しました
ボリューム vol-097ec3db03ae36526 を gp2 から gp3 に変換中...
{
    "VolumeModification": {
        "VolumeId": "vol-097ec3db03ae36526",
        "ModificationState": "modifying",
        "TargetSize": 10,
        "TargetIops": 3000,
        "TargetVolumeType": "gp3",
        "TargetThroughput": 125,
        "TargetMultiAttachEnabled": false,
        "OriginalSize": 10,
        "OriginalIops": 100,
        "OriginalVolumeType": "gp2",
        "OriginalMultiAttachEnabled": false,
        "Progress": 0,
        "StartTime": "2025-02-26T02:54:25+00:00"
    }
}
ボリューム vol-097ec3db03ae36526 の変換を開始しました
ボリューム vol-097ec3db03ae36526: 変換処理中...
ボリューム vol-097ec3db03ae36526: gp3への変換が完了しました
作成したスナップショットID: snap-03cf1d0b1d5165fad (ロールバック用に保持してください)
ボリューム vol-0fa73d9b501d6eb02 を確認中...
ボリューム vol-0fa73d9b501d6eb02 は gp2 ではありません(現在のタイプ: gp3)。スキップします...

変換結果サマリー:
変換成功: 2
変換失敗: 0
スキップ: 1
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ 

4.実行結果の確認

使用手順6に従って実行結果を確認します。

[cloudshell-user@ip-xx-xx-xx-xx tmp]$ # 変換したボリュームの状態確認
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ aws ec2 describe-volumes --volume-ids $(cat volume_ids.txt) --query 'Volumes[*].[VolumeId,VolumeType,State]' --output table
-----------------------------------------------
|               DescribeVolumes               |
+------------------------+------+-------------+
|  vol-004373c1f59e29646 |  gp3 |  available  |
|  vol-0fa73d9b501d6eb02 |  gp3 |  available  |
|  vol-097ec3db03ae36526 |  gp3 |  available  |
+------------------------+------+-------------+
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ 
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ # 作成されたスナップショットの確認(スナップショットを作成した場合)
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ aws ec2 describe-snapshots --filters "Name=tag:Purpose,Values=gp2-gp3-conversion-backup" --query 'Snapshots[*].[SnapshotId,VolumeId,Tags[?Key==`Name`].Value|[0]]' --output table
----------------------------------------------------------------------------------------------------------------
|                                               DescribeSnapshots                                              |
+------------------------+------------------------+------------------------------------------------------------+
|  snap-041788273d8cbe3b1|  vol-004373c1f59e29646 |  Backup-vol-004373c1f59e29646-gp2-to-gp3-20250226-115247   |
|  snap-03cf1d0b1d5165fad|  vol-097ec3db03ae36526 |  Backup-test-vol-1-gp2-to-gp3-20250226-115351              |
+------------------------+------------------------+------------------------------------------------------------+
[cloudshell-user@ip-xx-xx-xx-xx tmp]$ 

今回指定したボリュームだけgp3に変更されていることが確認できました。
またスナップショットも問題なく作成されています。

なお、結果はコンソール上でも確認できます。

  • ボリューム
    Cursor_と_ボリューム___EC2___ap-northeast-1

  • スナップショット
    Cursor_と_スナップショット___EC2___ap-northeast-1

最後に

今回は、特定のEBSボリュームをgp2からgp3へ一括変換するスクリプトをご紹介しました!

コスト最適化は重要ですが、性能への影響も考慮する必要があります。このスクリプトを使用することで、スナップショットを取得しながら安全に変換作業を進められます。みなさんのコスト最適化の一助となれば幸いです。

以上、おつまみ(@AWS11077)でした!

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.