AWS Backupの自動復元テストをEFSで試してみた

AWS Backupの自動復元テストをEFSで試してみた

Clock Icon2025.05.13

はじめに

こんにちは!
クラウド事業本部コンサルティング部のぐっさんです。

EFSの復元について調べる機会があったので、AWS Backupの機能を使った復元テストを検証してみました。

ざっくり構成図

デフォルト設定(リージョンファイルシステム)で設定しましたが、検証では1つのAZしか使いませんでした。
構成図

前提

以下のリソースに関しては手順に含めず、既存のものとして進めます。

  • VPC
  • サブネット
  • ルートテーブル
  • インターネットゲートウェイ
  • NATゲートウェイ
  • IAMロール

復元テストの料金

テストされる復旧ポイントの数と、復元されるストレージの量によって料金がかかります。
東京リージョンの場合、2025年現在は復旧ポイント毎に1.80USD + 復元されるウォームストレージの容量分の課金となります。

https://aws.amazon.com/jp/backup/pricing/

結果要点

  • デフォルトのバックアップボールトaws/efs/automatic-backup-vault且つデフォルトポリシーだと復元テストに失敗する
  • 復元テストの検証を特に設定しない場合、検証ステータスがタイムアウト or 検証中のままとなる

手順

セキュリティグループの作成

EC2用のセキュリティグループを作成します。
インバウンドルールは特に設けず、デフォルト設定で作成します。
sg_create_1

EFS用のセキュリティグループを作成します。
インバウンドルールで先ほど作成したEC2のセキュリティグループからのNFSアクセスを許可します。
sg_create_2

EFSの作成

コンソールからファイルシステムの作成を行います。今回はカスタマイズ画面から作成します。
efs_create_1

ファイルシステム名を任意に設定します。今回AWS Backupの自動バックアップを行うため、デフォルトのチェックをつけたままにします。
efs_create_2

その他設定はデフォルトのまま、Nameタグのみ付与して次へ
efs_create_3

ネットワークアクセス設定を行います。今回はリージョンファイルシステムを選択したため各AZのプライベートサブネットを指定し、事前に作成したセキュリティグループを設定します。
efs_create_4

ファイルシステムポリシーの設定は今回はせずに次へ
efs_create_5

以下のような確認画面となるため、各種設定が想定通りであればスクロールして「作成」を押下します。
efs_create_6

EC2の作成

コンソールからEC2の作成を行います。任意の名称をつけます。
ec2_create_1

インスタンスタイプは無料利用枠のもので設定しました。今回は検証環境およびセッションマネージャーでアクセス予定のためキーペアは作りません。
ec2_create_2

ネットワーク設定でプライベートサブネットに起動し、事前に作成したセキュリティグループを設定します。
ec2_create_3

ストレージの設定はデフォルトのままでファイルシステムの横の「編集」を押下します。
ec2_create_4

EFSがデフォルトでチェックされていることを確認し、「共有ファイルシステムを追加」を押下します。
ec2_create_5

作成したEFSが選択されていることを確認。必要に応じてマウントポイントを変更します。
今回はデフォルトで設定されたものをそのまま使用します。
セキュリティグループは既に作成・設定済みのため「自動的に作成してアタッチ」のチェックは外します。
ec2_create_6

高度な詳細を開きます。今回セッションマネージャー経由でインスタンスにアクセスするため、AmazonSSMManagedInstanceCoreポリシーを付与したIAMロールをEC2に設定します。
ec2_create_7

最下部までスクロールし、ユーザーデータに自動生成されたスクリプトが入っていることを確認します。「インスタンスを起動」を押下します。
ec2_create_8

ちなみに以下のようなスクリプトが入っていました。必要に応じて変更も可能です。
EFS用のユーティリティやNFSクライアントのインストール、/etc/fstabへの設定追加、マウント実行まで起動時に自動で行ってくれるようです。

#cloud-config
package_update: true
package_upgrade: true
runcmd:
- yum install -y amazon-efs-utils
- apt-get -y install amazon-efs-utils
- yum install -y nfs-utils
- apt-get -y install nfs-common
- file_system_id_1=fs-<EFSのID>
- efs_mount_point_1=/mnt/efs/fs1
- mkdir -p "${efs_mount_point_1}"
- test -f "/sbin/mount.efs" && printf "\n${file_system_id_1}:/ ${efs_mount_point_1} efs tls,_netdev\n" >> /etc/fstab || printf "\n${file_system_id_1}.efs.ap-northeast-1.amazonaws.com:/ ${efs_mount_point_1} nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0\n" >> /etc/fstab
- test -f "/sbin/mount.efs" && grep -ozP 'client-info]\nsource' '/etc/amazon/efs/efs-utils.conf'; if [[ $? == 1 ]]; then printf "\n[client-info]\nsource=liw\n" >> /etc/amazon/efs/efs-utils.conf; fi;
- retryCnt=15; waitTime=30; while true; do mount -a -t efs,nfs4 defaults; if [ $? = 0 ] || [ $retryCnt -lt 1 ]; then echo File system mounted successfully; break; fi; echo File system not available, retrying to mount.; ((retryCnt--)); sleep $waitTime; done;

データ投入

セッションマネージャーを使用してEC2に接続し、まず設定確認を行います。

df -hで/mnt/efs/fs1の設定確認

sh-5.2$ df -h
Filesystem      Size  Used Avail Use% Mounted on
devtmpfs        4.0M     0  4.0M   0% /dev
tmpfs           475M     0  475M   0% /dev/shm
tmpfs           190M  500K  190M   1% /run
/dev/xvda1      8.0G  1.6G  6.4G  20% /
tmpfs           475M     0  475M   0% /tmp
/dev/xvda128     10M  1.3M  8.7M  13% /boot/efi
127.0.0.1:/     8.0E     0  8.0E   0% /mnt/efs/fs1 ★ユーザーデータで設定されたマウントポイントが存在
tmpfs            95M     0   95M   0% /run/user/0

/etc/fstabの中身を確認

sh-5.2$ cat /etc/fstab
#
UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx     /           xfs    defaults,noatime  1   1
UUID=xxxx-xxxx        /boot/efi       vfat    defaults,noatime,uid=0,gid=0,umask=0077,shortname=winnt,x-systemd.automount 0 2

fs-[EFSのID]:/ /mnt/efs/fs1 efs tls,_netdev ★EFSのルートディレクトリをEC2の/mnt/efs/fs1ディレクトリにマウントする設定(EFSマウントヘルパーによる)

マウント設定を確認したらPythonを使用してダミーファイルを作成します。

vi dummy.py
サンプルコードは以下。10MBのランダムデータを10ファイル作成します。

import csv
import os
import random
import string

def generate_random_string(length):
    return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

def create_csv_file(directory, file_name, size_mb):
    target_size = size_mb * 1024 * 1024  # Convert MB to bytes
    current_size = 0

    # Ensure the directory exists
    os.makedirs(directory, exist_ok=True)

    full_path = os.path.join(directory, file_name)

    with open(full_path, 'w', newline='') as csvfile:
        writer = csv.writer(csvfile)

        # Write header
        header = ['id', 'name', 'email', 'description']
        writer.writerow(header)
        current_size = sum(len(field) for field in header) + len(header)  # Account for commas

        row_id = 1
        while current_size < target_size:
            row = [
                str(row_id),
                generate_random_string(10),
                f"{generate_random_string(8)}@example.com",
                generate_random_string(100)
            ]
            writer.writerow(row)
            current_size += sum(len(field) for field in row) + len(row)  # Account for commas
            row_id += 1

    print(f"Created {full_path} with size: {os.path.getsize(full_path) / (1024 * 1024):.2f} MB")

def main():
    file_size_mb = 10
    num_files = 10
    output_directory = input("Enter the directory path to save CSV files: ").strip()

    for i in range(num_files):
        file_name = f"dummy_data_{i+1}.csv"
        create_csv_file(output_directory, file_name, file_size_mb)

if __name__ == "__main__":
    main()

スクリプトを実行します。
python3 dummy.py

※Pythonスクリプトを実行すると、ファイルの出力ディレクトリを求められるため/mnt/efs/fs1を入力しEnterで実行します。
※セッションマネージャーでのデフォルトユーザ(ssm-user)だと書き込み権限がなかったためrootで実行しています。(sudoでも可能です。)

実行結果

[root@ip ~]# python3 dummy.py
Enter the directory path to save CSV files: /mnt/efs/fs1
Created /mnt/efs/fs1/dummy_data_1.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_2.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_3.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_4.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_5.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_6.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_7.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_8.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_9.csv with size: 10.07 MB
Created /mnt/efs/fs1/dummy_data_10.csv with size: 10.07 MB

実際にファイルが作成されたことを確認

[root@ip ~]# cd /mnt/efs/fs1/
[root@ip fs1]# ls -lh
total 101M
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_1.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_10.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_2.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_3.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_4.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_5.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_6.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_7.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_8.csv
-rw-r--r--. 1 root root 11M May 12 02:50 dummy_data_9.csv

/mnt/efs/fs1/のサイズが約100MBになったことを確認

[root@ip fs1]# du -sh /mnt/efs/fs1/
101M    /mnt/efs/fs1/

ちなみにcsvの中身は以下のようなランダムの値です。

[root@ip fs1]# cat dummy_data_1.csv |head -2
id,name,email,description
1,JnQPNP3RE2,7CLdD2Hc@example.com,eiLnrTyoBCF8tnKcBAIEvklw92b5gCGivs5mHTFNrMBFz5Q4FsOk9LzftoXX0yVjt3Ker3PCPyBL4XCpq2QKkg4mUCT9dFMTZgtv

復元テストプラン作成

AWS Backupのコンソールから復元テストプランを作成します。
backup_restore_test_1

各種全般設定を入れます。
backup_restore_test_2

※「次の時間以内に開始」の項目でデフォルトは8時間(以内に開始)が設定されています。
検証のため1時間以内に開始で設定していますが、時間枠は長めに設定がおすすめとの注意書きが出ますので実際に利用の際はご注意ください。

ユースケースに応じて、[次の時間以内に開始] の時間枠を長くすることをお勧めします。開始時間枠が短いと、アカウントで作成できるリソースの数と同時に実行できる復元テストジョブの数に対するクォータ制限が原因で、障害が発生する可能性があります。

各種回復ポイントの選択設定を入れてテストプランを作成します。
backup_restore_test_3

主な確認点

  • テストプランの名称にはハイフンが使用できないのでご注意ください。(英数字 or アンダースコア)

  • 復旧ポイントの選択基準について、ドキュメントに以下の記載があります。

古いバージョンへの復元が必要になった場合に備えて、ランダムな選択によって復旧ポイントの全般的な状態をより定期的に測定することをお勧めします。

https://docs.aws.amazon.com/ja_jp/aws-backup/latest/devguide/restore-testing.html

今回、最近の復旧ポイント/ランダムな復旧ポイントをどちらも試しましたが、「最近の復旧ポイント」を選択しても必ずしも作成時間が最新の復旧ポイントが適用されるわけではなさそうでした。
ただ、当日中にバックアップとテストを行なったためかもしれませんので参考までに。そのため、今回の手順ではランダムな復旧ポイントを設定しておきます。

  • EFSはPOTR対応リソースタイプではないため特にチェックはしません。

https://docs.aws.amazon.com/ja_jp/aws-backup/latest/devguide/backup-feature-availability.html#features-by-resource

リソース割り当てを行います。全般設定では割り当て名を入力し、クリーンアップ前の保持期間を24時間に設定します。保護されたリソースにEFSを指定します。
backup_restore_test_4

その他のオプションも特に変更せず、リソースを割り当て作成します。
backup_restore_test_5

バックアッププランの編集(必要に応じて)

EFSの自動バックアップはデフォルト設定の場合日次でUTCの5:00から8時間以内に開始されます。
検証の際にはこれを待たずに確認したいため、必要に応じてプランの編集をします。

AWS Backupのコンソールから「バックアッププラン」を選択し、対象のプラン選択後EFSのバックアップルールを押下します。
backup_plan_1

右上の編集を押下します。
backup_plan_2

バックアップの開始時刻を希望の時刻に設定し、保存します。
backup_plan_3

バックアップが実行されたことを確認

AWS Backupのコンソールで対象のボールトを選択し、バックアップの実行を確認します。
backup_check_1

復旧ポイントが追加されていることを確認
backup_check_2

復元テストの実行確認(失敗例)

まず、失敗のお知らせから。

backup_warn_1

エラーメッセージ

User: arn:aws:sts::<アカウントID>:assumed-role/AWSServiceRoleForBackupRestoreTesting/AWSBackupRestoreTesting is not authorized to perform: backup:StartRestoreJob on resource: arn:aws:backup:ap-northeast-1:<アカウントID>:recovery-point:
<リカバリポイントID> with an explicit deny in a resource-based policy

原因はこちらのブログで記載して下さっています。

https://dev.classmethod.jp/articles/restore-and-delete-aws-backup/

デフォルトのバックアップボールト 《aws/efs/automatic-backup-vault》を使用しており、
アクセスポリシーもデフォルトです。これを直していきます。

バックアップボールトのコンソールにアクセスポリシーの設定があるため、「編集」を押下します。
backup_warn_2

参考ブログの通り、以下の設定とします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": {
                "AWS": "*"
            },
            "Action": [
                "backup:DeleteBackupVault",
                "backup:DeleteBackupVaultAccessPolicy",
                "backup:DeleteRecoveryPoint",
                "backup:StartCopyJob",
                "backup:StartRestoreJob", ★削除
                "backup:UpdateRecoveryPointLifecycle"
            ],
            "Resource": "*"
        }
    ]
}

backup_warn_3

復元テストの実行確認(成功)

成功の確認
バックアップジョブの一覧に成功ジョブが存在します。(複数回試したため、大量に出力されています)復元にかかった時間も確認できます。
backup_test_success_3

特定のジョブを押下すると詳細を確認できます。
backup_test_success_1

復元テストのステータスは成功しています。ただ、「検証ステータス」が検証中?

検証ステータスについて
今回、復元されたEFSの中身を確認するためにクリーンアップ前の保持期間を設定しましたが、すぐに削除する設定も可能です。この設定で試した時、この「検証ステータス」はタイムアウトになっていました。
backup_test_success_2

復元テストを実行したのちにLambda等を用いて独自のカスタムスクリプトを実行し、AWS BackupのAPIにそのステータスを返すことが可能であり、そのための項目のようです。
単純なRTOの確認のみであればテストリソースはすぐに削除してしまう方がコスト面でも良さそうですが、独自の確認作業が必要な場合には保持期間を設定し結果検証を自動化出来そうです。

関連情報
https://repost.aws/questions/QUcVh1V6AQTDKv7DGjvxTswg/validation-timeout-when-using-restore-testing

復元テストの検証
https://docs.aws.amazon.com/ja_jp/aws-backup/latest/devguide/restore-testing-validation.html

手動で検証を行う場合は、PutRestoreValidationResultをCLI等で実行してこのステータスの更新が出来ます。

EFSの新規作成を確認
新しくEFSが作成されました!
backup_test_success_4

マウントターゲット作成
EC2からアクセスして中身を確認するために、新規EFSにマウントターゲットを作成します。
backup_test_success_5

backup_test_success_6

マウントターゲット作成後、ターゲットの状態が作成中から利用可能になるのを待ちます。
backup_test_success_7

新規作成されたEFSをマウントしてみます。
ユーザーデータのコマンドを流用します。以下のfs-<EFSのID>の部分に実際の新規EFS IDを設定して、EC2で実行します。
fstabの内容を書き換えるのでrootユーザまたはsudoで実施します。

file_system_id_2=fs-<EFSのID>
efs_mount_point_2=/mnt/efs/fs2
mkdir -p "${efs_mount_point_2}"
test -f "/sbin/mount.efs" && printf "\n${file_system_id_2}:/ ${efs_mount_point_2} efs tls,_netdev\n" >> /etc/fstab || printf "\n${file_system_id_2}.efs.ap-northeast-1.amazonaws.com:/ ${efs_mount_point_2} nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev 0 0\n" >> /etc/fstab
mount -a -t efs,nfs4 defaults

マウント実行後に/mnt/efs/fs2を見てみます。

[root@ip ~]# ls -l /mnt/efs/fs2
total 4
drwxr-xr-x. 3 root root 6144 May 12 09:49 aws-backup-restore_2025-05-12T13-39-00-158178432Z

「aws-backup-restore_」から始まるディレクトリがあります。
中には最初に作成したダミーファイルが入っていますね!

[root@ip ~]# ls -l /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/
total 103164
drw--w----. 2 root root     6144 May 12 13:38 aws-backup-lost+found_2025-05-12T13-38-49-104385671Z
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_1.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_10.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_2.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_3.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_4.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_5.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_6.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_7.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_8.csv
-rw-r--r--. 1 root root 10561301 May 12 02:50 dummy_data_9.csv

sha1sumでハッシュ値を確認したところ、それぞれ元のファイルと同じようです。

d7d689ea7a34786ae033aaeeea7476fcf007295f  /mnt/efs/fs1/dummy_data_1.csv
d7d689ea7a34786ae033aaeeea7476fcf007295f  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_1.csv
7716bf6f7ef9aaecea4d2e21834c76cf4de08faf  /mnt/efs/fs1/dummy_data_2.csv
7716bf6f7ef9aaecea4d2e21834c76cf4de08faf  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_2.csv
1cfd5a7441374d42296c6fd230f987b14beae9f9  /mnt/efs/fs1/dummy_data_3.csv
1cfd5a7441374d42296c6fd230f987b14beae9f9  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_3.csv
e9e988bc05bb336da19f717d343e238d7dca00fd  /mnt/efs/fs1/dummy_data_4.csv
e9e988bc05bb336da19f717d343e238d7dca00fd  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_4.csv
81d716f29c27cb316e82f10f014e4285b728f7e6  /mnt/efs/fs1/dummy_data_5.csv
81d716f29c27cb316e82f10f014e4285b728f7e6  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_5.csv
ee8b7c5bda1c83a7d2cedc56426ba27f7f40e07d  /mnt/efs/fs1/dummy_data_6.csv
ee8b7c5bda1c83a7d2cedc56426ba27f7f40e07d  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_6.csv
26bc139130261fc198b98bdfd4b5c59c3720ff73  /mnt/efs/fs1/dummy_data_7.csv
26bc139130261fc198b98bdfd4b5c59c3720ff73  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_7.csv
ca22825689303c078a52e7130d2dfb79e60c9a41  /mnt/efs/fs1/dummy_data_8.csv
ca22825689303c078a52e7130d2dfb79e60c9a41  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_8.csv
e01403417755ceef9f74fa92e0c837615fca9e1b  /mnt/efs/fs1/dummy_data_9.csv
e01403417755ceef9f74fa92e0c837615fca9e1b  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_9.csv
1dce3c6aa0de5efc7f6ce500fa058b6f179c8ee5  /mnt/efs/fs1/dummy_data_10.csv
1dce3c6aa0de5efc7f6ce500fa058b6f179c8ee5  /mnt/efs/fs2/aws-backup-restore_2025-05-12T13-39-00-158178432Z/dummy_data_10.csv

中身の確認を終えたため検証ステータスを更新
CLIで更新してステータスを成功にしてみます。

aws backup put-restore-validation-result --restore-job-id <JOB ID> --validation-status SUCCESSFUL

backup_test_success_8

ステータスの更新を確認
backup_test_success_9

今回は手動で更新してしまいましたが、復元後の検証用スクリプトを作ってみたくなりますね。

手順ではクリーンアップ前に一定時間待機する方法を記載しましたが、すぐに削除する設定では復元テストを終えた後にEFSを確認すると、自動で削除されていました。
単純に、リソース単体の復元時間を定期的に確認する用途であればテスト後すぐ削除で良いかと思います。

参考

https://docs.aws.amazon.com/ja_jp/aws-backup/latest/devguide/restore-testing.html

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AmazonEFS.html

https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/tutorial-efs-volumes.html

まとめ

RTOのテストを気軽に出来る便利な機能でした!
本番データだと容量も多く時間がかかることが想定されます。定期的な実行を行い備えておけると良いですね。
個人的には復元テストの検証を別途試してみたいと思います。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.