EC2 インスタンスのブロックデバイスの「終了時に削除」の情報を一覧取得し、一括で「はい」にする

マネジメントコンソールからはインスタンスごとに個別に確認する必要があるブロックデバイスの「終了時に削除」を AWS CLI で一括で取得します。なんなら属性の変更までします。

コンバンハ、千葉(幸)です。

EC2 インスタンスの属性のひとつとして、ブロックデバイスマッピングの「終了時に削除(DeleteOnTermination)」があります。

ここから確認できるものです。

EC2_Management_Console_BlockDevice

この属性は、EC2 インスタンスにアタッチされた EBS ボリュームをインスタンスの終了(削除)時にあわせて削除するかどうかを定義しています。

デフォルトでは、ルートボリュームは true(あわせて削除される)、それ以外は false (ボリュームだけ残る)に設定されます。

今回は、「現状の設定を一覧で確認する」「すべてのインスタンスのブロックデバイスについて一括で true にする」コマンドを確認する機会がありましたのでその内容をご紹介します。

環境情報

mac OS と、AWS CloudShell で動作確認しています。

  • macOS
    • Ventura 13.4.1
    • zsh
    • jq 1.6
    • AWS CLI 2.9.1
  • AWS CloudShell
    • bash
    • Jq 1.5
    • AWS CLI 2.12.2

インスタンスとそのブロックデバイスの情報を一括で確認する

いったん現状確認のため、このような形で情報をまとめたいと考えました。

SpreadSheat_describe-instances

  • インスタンスごとに以下情報を取得する
    • インスタンス ID
    • インスタンス Name
    • ブロックデバイスの情報
      • デバイス名
      • DeleteOnTermination
  • インスタンスごとに1行にまとめたい
  • 各種情報はタブ区切りで出力する
  • ブロックデバイスの情報はカンマ区切りで出力する

上記を満たすコマンド例は以下です。AWS CLI 以外に jq を必要とします。

aws ec2 describe-instances --output json\
  | jq -r '.Reservations[].Instances[] | {
     InstanceId: .InstanceId,
     Name: (.Tags[] | select(.Key == "Name").Value),
     BlockDeviceMappings: [.BlockDeviceMappings[] | [.DeviceName, .Ebs.DeleteOnTermination | tostring] | join(",")]}
      | [.InstanceId, .Name, .BlockDeviceMappings[]]
      | join("\t")'

手元の検証環境で実行した際の例は以下の通り。

i-0f40748bd304c3148     Test-1  /dev/xvda,true  /dev/sdb,false
i-0a23ed292b5b0fb99     Test-2  /dev/xvda,true  /dev/sdb,false   /dev/sdf,false
i-09d719edc7160ec1f     Test-3  /dev/xvda,true  /dev/sdb,false

出力をスプレッドシートに転記し、タブ区切りで列分割して多少手を加えれば冒頭の画像の状態になります。

コマンドはそこまで複雑なものではないですが、ポイントとしては以下のあたりです。

  • [5行目] DeleteOnTerminationの値 (boolean) をtostring関数により文字列に変換
    • 環境によっては join 時にエラーになるため *1
  • [5行目] join関数によりデバイス名と DeleteOnTerminationの値(を文字列にしたもの)をカンマ区切りで結合
  • [7行目] インスタンス ID、インスタンス Name、ブロックデバイス情報をタブ区切りで結合

すべてのインスタンスのすべてのブロックデバイスを DeleteOnTermination = true にする

環境によって、どのボリュームがDeleteOnTermination = trueであるべきかはさまざまです。

あくまで今回は一律で変更する場合の手順確認の意図でコマンドを組み立てています。ここに載せているスクリプトを実行するとリージョン内のすべてのインスタンス・すべてのブロックデバイスが対象になりますので影響にご注意ください。

#!/bin/bash
# 機能: EC2インスタンスの一覧を出力し、DeleteOnTerminationがfalseのブロックデバイスをtrueに変更します。

    # EC2インスタンスの一覧を取得
    instances=$(aws ec2 describe-instances --query "Reservations[].Instances[].InstanceId" --output text)

    # 各EC2インスタンスに対して処理を実行
    for instance_id in $instances; do
        echo "Processing Instance: $instance_id"

        # BlockDeviceMappingsのうち、DeleteOnTerminationがfalseのDeviceNameを取得
        device_mappings=$(aws ec2 describe-instances --instance-id "$instance_id" --query "Reservations[].Instances[].BlockDeviceMappings[?Ebs.DeleteOnTermination==\`false\`].DeviceName" --output text)

        # 各BlockDeviceMappingsに対して処理を実行
        for device_name in $device_mappings; do
            echo "  Updating Device: $device_name"

            # DeleteOnTerminationをtrueに変更
            aws ec2 modify-instance-attribute --instance-id "$instance_id" --block-device-mappings "[{\"DeviceName\":\"$device_name\",\"Ebs\":{\"DeleteOnTermination\":true}}]"

            echo "  Update Complete"
        done
    done

    echo "All instances processed"

updateinstances.shという名称でスクリプトを作成し、実行した場合の例は以下の通り。

$ sh updateinstances.sh
Processing Instance: i-0f40748bd304c3148
  Updating Device: /dev/sdb
  Update Complete
Processing Instance: i-0a23ed292b5b0fb99
  Updating Device: /dev/sdb
  Update Complete
  Updating Device: /dev/sdf
  Update Complete
Processing Instance: i-09d719edc7160ec1f
  Updating Device: /dev/sdb
  Update Complete
All instances processed

実行後に状態を確認すると、以下のようにすべてのブロックデバイスで true になっています。

$ aws ec2 describe-instances --output json\
  | jq -r '.Reservations[].Instances[] | {
     InstanceId: .InstanceId,
     Name: (.Tags[] | select(.Key == "Name").Value),
     BlockDeviceMappings: [.BlockDeviceMappings[] | [.DeviceName, .Ebs.DeleteOnTermination | tostring] | join(",")]}
      | [.InstanceId, .Name, .BlockDeviceMappings[]]
      | join("\t")'
i-0f40748bd304c3148	Test-1	/dev/xvda,true	/dev/sdb,true
i-0a23ed292b5b0fb99	Test-2	/dev/xvda,true	/dev/sdb,true	/dev/sdf,true
i-09d719edc7160ec1f	Test-3	/dev/xvda,true	/dev/sdb,true

対象を限定したい場合には以下のようなカスマイズのパターンがあるでしょう。要件に応じて変更してください。

  • aws ec2 describe-instancesでフィルタリングする
    • 特定のタグがついているもの、など
  • instances変数を直接指定する
  • device_mappings変数の値取得時に、特定のデバイス名は除外する

終わりに

EC2 インスタンスとそのブロックデバイスマッピングの情報を一括で取得したい、DeleteOnTermination を一括で true にしたい、という内容でした。

前者の「情報を一括で取得したい」については、階層が異なる情報に関してうまいこと1行にまとめる術が見つかって良かったです。jq を使わず--queryだけで実現できるとより良かったのですが、上手い書き方に辿り着けませんでした。

後者のスクリプトは ChatGPT の助けを借りて作成しました。以下の指示を与えるだけでほぼ完成形を出してくれたので、すごいなぁと感心してしまいました。

以下を満たすbashのスクリプトを作ってください。

- EC2インスタンスの一覧を出力
- EC2インスタンスごとに以下を実行
  - BlockDeviceMappingsのうちDeleteOnTerminationがfalseのDeviceNameを取得
  - aws ec2 modify-instance-attributeでDeleteOnTerminationをtrueに変更

どこかしら参考になれば幸いです。

以上、 チバユキ (@batchicchi) がお送りしました。

脚注

  1. tostringを省略した際に「jq: error (at <stdin>:467): string (",") and boolean (true) cannot be added」というエラーが出たことがありました。