EC2のルートボリュームと追加ボリュームの削除オプションについて

EC2のルートボリュームと追加ボリュームの削除オプションについて、簡単なテストを書いた記事です。
2021.05.23

今回、作業が終わってからEC2に追加したEBSボリュームの削除を忘れてしまったことがありました。
これをきっかけに調べてみたら、EC2のボリュームがルートボリュームかどうかによって、インスタンスを削除するときに一緒にボリュームが残ることもあるということがわかりました。
それから、作成した方法とオプションによって適用が違うこともわかりました。
もちろんDeleteOnTerminationを特定すれば、特に悩む必要のない問題ですが、
興味ができて簡単なテストをしてみたので、これを共有しようと思っています。

共通デフォルトは?

DeleteOnTermination 属性のデフォルト値は、ボリュームがインスタンスのルートボリュームであるか、インスタンスにアタッチされているルート以外のボリュームであるかによって異なります。

ドキュメントによると、ルートボリュームのDeleteOnTerminationのデフォルトは trueで、ルート以外のボリュームはfalseとして指定されています。
それでは実際にはどのように適用されるのか確認してみましょう。

テスト

AWS CLIでテストしてみます。続いてCloudFormationでも同様に適用されるのか確認してみます。

まず結果から

説明で長くなるので、まず結果から言うと

  • AWS CLIで作成すると方法によって削除オプションが異なるように適用される。
  • CloudFormationで作成してもCLIと同じ規則が適用される。
    しかし、上記のデフォルト値はインスタンスの削除だけに限られるため、スタックを削除するとVolume Attachで作成したボリュームは削除される。

でした。

AWS CLIでテスト

インスタンスにボリュームを追加する方法は

  • run-instancesコマンドに--block-device-mappingsオプションを追加
  • attach-volumeコマンドを使用

などがあります。

テストは下記のような方法で進めました。

  • 単純にrun-instancesコマンドに--block-device-mappingsオプションを使用
  • --block-device-mappingsオプションにDeleteOnTerminationを特定
  • attach-volumeコマンド使用

先ずは--block-device-mappingsオプションを使用した方法で作成してみます。
スクリプトは下記の通りです。

# Amazon Linux 2を使用
aws ec2 run-instances \
    --image-id {作成したインスタンスのid} \
    --instance-type t2.micro \
    --block-device-mappings '[{"DeviceName":"/dev/xvda","Ebs":{"VolumeSize":50}},{"DeviceName":"/dev/sde","Ebs":{"VolumeSize":8}}]' \
    --key-name publicTestKey

ルートボリューム1個と追加ボリューム1個を持つインスタンスが作成されました。

ボリューム一覧でもこれを確認することができます。

describe-instancesコマンドでインスタンスの設定値を確認してみます。

aws ec2 describe-instances --instance-ids i-05eadaa67e78d50bd

# result
----
"BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "AttachTime": "2021-05-22T09:28:42+00:00",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-0727684da83e83e16"
                            }
                        },
                        {
                            "DeviceName": "/dev/sde",
                            "Ebs": {
                                "AttachTime": "2021-05-22T09:28:42+00:00",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-0bf9ee0f38c2a1102"
                            }
                        }
                    ],
----

予想とは違い、追加ボリュームであるsdeのDeleteOnTerminationがtrueとして設定されています。
実際にインスタンスを削除するとボリュームも一緒に削除されます。

調べてみると BlockDeviceMappingsオプションはDeleteOnTerminationの適用が異なりました。

インスタンス終了時にボリュームを削除するかどうか (true または false)デフォルト値は、ルートデバイスボリュームでは true、アタッチされたボリュームでは false です。AMI を作成するときは、そのブロックデバイスマッピングがインスタンスからこの設定を継承します。インスタンスを起動するときに、AMI からこの設定を継承します。

つまり、AMIのデフォルト設定によって追加ボリュームの扱いも変わってくるということです。
実際にAMI設定値を確認してみるとBlockDeviceMappingsがtrueになっていました。

# Amazon Linux 2設定値確認
aws ec2 describe-images --image-ids ami-0ca38c7440de1749a

# result
----
"BlockDeviceMappings": [
                {
                    "DeviceName": "/dev/xvda",
                    "Ebs": {
                        "DeleteOnTermination": true,
                        "SnapshotId": "snap-003b466f2f65000b0",
                        "VolumeSize": 8,
                        "VolumeType": "gp2",
                        "Encrypted": false
                    }
                }
            ],
----

もしBlockDeviceMappingsでボリュームを追加するとebsパラメータのDeleteOnTerminationを特定する必要があります。

続いてDeleteOnTerminationattach-volumeを使用する方法で2個の追加ボリュームを作成してみます。

aws ec2 run-instances \
    --image-id ami-0ca38c7440de1749a \
    --instance-type t2.micro \
    --block-device-mappings '[{"DeviceName":"/dev/xvda","Ebs":{"VolumeSize":50}},{"DeviceName":"/dev/sde","Ebs":{"DeleteOnTermination":false, "VolumeSize":8}}]' \
    --key-name publicTestKey

# ボリューム作成
aws ec2 create-volume \
--size 8 \
--availability-zone ap-northeast-1a
# ボリューム連結
aws ec2 attach-volume \
--instance-id {作成したインスタンスのid} \
--volume-id {作成したボリュームのid} \
--device /dev/sdh

接続が完了できたらインスタンスの情報を確認してみましょう。

----
"BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "AttachTime": "2021-05-22T13:15:05+00:00",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-035175b43ea9cb27f"
                            }
                        },
                        {
                            "DeviceName": "/dev/sde",
                            "Ebs": {
                                "AttachTime": "2021-05-22T13:15:05+00:00",
                                "DeleteOnTermination": false,
                                "Status": "attached",
                                "VolumeId": "vol-008218eb85553d2c7"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdh",
                            "Ebs": {
                                "AttachTime": "2021-05-22T13:18:41+00:00",
                                "DeleteOnTermination": false,
                                "Status": "attached",
                                "VolumeId": "vol-0796ef4d6ef545145"
                            }
                        }
                    ],
----

DeleteOnTerminationを特定したボリュームは当然、削除オプションがfalseになっています。
そしてattach-volumeで連結したボリュームは共通デフォルトの通りに削除オプションがfalseに設定されています。
実際にインスタンスを削除した後、ボリューム一覧を確認すると2個のぶりゅーむは残っています。

CloudFormationでテスト

AWS CLIでテストしながら各オプションがどのように適用されるのかを確認できました。
また、CloudFormationで作成してもDeleteOnTerminationのデフォルトは共通デフォルトの通りに設定されるはずです。
そうすると下記のような結果になると思います。

  • まずAMI設定に従う
  • DeleteOnTerminationを特定したら一緒に削除されない
  • ボリュームを別に作成して連結すると一緒に削除されない(デフォルトがfalseだから)

それでは上記の仮定を含めたテンプレートを作成してテストしてみましょ。
予想通りならxvdaとsdcは削除され、sddとsdhは残るはずです。

AWSTemplateFormatVersion: 2010-09-09
Description: TEST EC2 Environment

Resources:
  EC2:
    Type: "AWS::EC2::Instance"
    Properties:
      AvailabilityZone: "ap-northeast-1a"
      KeyName: publicTestKey
      ImageId: ami-0ca38c7440de1749a
      InstanceType: t2.micro
      BlockDeviceMappings:
        - DeviceName: /dev/xvda
          Ebs:
            VolumeSize: 50
        - DeviceName: /dev/sdc
          Ebs:
            VolumeSize: 8
        - DeviceName: /dev/sdd
          Ebs:
            VolumeSize: 8
            DeleteOnTermination: false
  NewVolume:
    Type: AWS::EC2::Volume
    Properties:
      Size: 8
      AvailabilityZone: "ap-northeast-1a"

  AttachVolume:
    Type: AWS::EC2::VolumeAttachment
    Properties:
      InstanceId: !Ref EC2
      VolumeId: !Ref NewVolume
      Device: /dev/sdh

スタックの作成が完了できたら、インスタンスの設定値を確認してみましょ。

aws ec2 describe-instances --instance-ids i-0d138e84db5772538
----
"BlockDeviceMappings": [
                        {
                            "DeviceName": "/dev/xvda",
                            "Ebs": {
                                "AttachTime": "2021-05-22T14:29:16+00:00",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-09b1f046afa7b24d5"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdc",
                            "Ebs": {
                                "AttachTime": "2021-05-22T14:29:16+00:00",
                                "DeleteOnTermination": true,
                                "Status": "attached",
                                "VolumeId": "vol-05e1b21cbe5380cc2"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdd",
                            "Ebs": {
                                "AttachTime": "2021-05-22T14:29:16+00:00",
                                "DeleteOnTermination": false,
                                "Status": "attached",
                                "VolumeId": "vol-0dc98cd7455d75b3f"
                            }
                        },
                        {
                            "DeviceName": "/dev/sdh",
                            "Ebs": {
                                "AttachTime": "2021-05-22T14:30:10+00:00",
                                "DeleteOnTermination": false,
                                "Status": "attached",
                                "VolumeId": "vol-0bcc5937885929018"
                            }
                        }
                    ],
----

予想通りにCLIと同じ結果が出ました。
実際にインスタンスを直接に削除すると2個のついかぼりゅーむは削除されません。
ですがインスタンスを直接に削除しなくてCloudFormationでスタックを削除すると
DeleteOnTerminationを設定したボリュームだけ残っています。
(インスタンスを終了した後にスタックを削除しても同じ結果です。)

これは追加したボリュームがスタックのリソースとして管理されるのかの問題です。
作成したスタックのリソースタブを確認するとType: AWS::EC2::Volumeで作成したボリュームはリソースに表れていますが
DeviceName: /dev/sddで作成したボリュームは表れていません。
Type: AWS::EC2::Volumeで作成したボリュームを残したいのなら``"DeletionPolicy" : "Snapshot"``` を設定します。
詳細な内容はドキュメントを参考してください。)

感想

最初に語りました通にDeleteOnTerminationオプションを意識してtrueかfalseかを設定すれば特にに問題にならない内容です。
ですがBlockDeviceMappingsを使用するのが気を使うことがもっとあるという点が分かりました。

最後にTrusted Advisor習慣のように一度確認するとAWSのベストプラクティスはもちろん
自分も知らないうちに残してしまったボリュームが確認できますので、一度確認することをお勧めします。

最後まで読んでいただきまして、ありがとうございました。