AWS Backupの自動復元テストをEFSで試してみた
はじめに
こんにちは!
クラウド事業本部コンサルティング部のぐっさんです。
EFSの復元について調べる機会があったので、AWS Backupの機能を使った復元テストを検証してみました。
ざっくり構成図
デフォルト設定(リージョンファイルシステム)で設定しましたが、検証では1つのAZしか使いませんでした。
前提
以下のリソースに関しては手順に含めず、既存のものとして進めます。
- VPC
- サブネット
- ルートテーブル
- インターネットゲートウェイ
- NATゲートウェイ
- IAMロール
復元テストの料金
テストされる復旧ポイントの数と、復元されるストレージの量によって料金がかかります。
東京リージョンの場合、2025年現在は復旧ポイント毎に1.80USD + 復元されるウォームストレージの容量分の課金となります。
結果要点
- デフォルトのバックアップボールト
aws/efs/automatic-backup-vault
且つデフォルトポリシーだと復元テストに失敗する - 復元テストの検証を特に設定しない場合、検証ステータスがタイムアウト or 検証中のままとなる
手順
セキュリティグループの作成
EC2用のセキュリティグループを作成します。
インバウンドルールは特に設けず、デフォルト設定で作成します。
EFS用のセキュリティグループを作成します。
インバウンドルールで先ほど作成したEC2のセキュリティグループからのNFSアクセスを許可します。
EFSの作成
コンソールからファイルシステムの作成を行います。今回はカスタマイズ画面から作成します。
ファイルシステム名を任意に設定します。今回AWS Backupの自動バックアップを行うため、デフォルトのチェックをつけたままにします。
その他設定はデフォルトのまま、Nameタグのみ付与して次へ
ネットワークアクセス設定を行います。今回はリージョンファイルシステムを選択したため各AZのプライベートサブネットを指定し、事前に作成したセキュリティグループを設定します。
ファイルシステムポリシーの設定は今回はせずに次へ
以下のような確認画面となるため、各種設定が想定通りであればスクロールして「作成」を押下します。
EC2の作成
コンソールからEC2の作成を行います。任意の名称をつけます。
インスタンスタイプは無料利用枠のもので設定しました。今回は検証環境およびセッションマネージャーでアクセス予定のためキーペアは作りません。
ネットワーク設定でプライベートサブネットに起動し、事前に作成したセキュリティグループを設定します。
ストレージの設定はデフォルトのままでファイルシステムの横の「編集」を押下します。
EFSがデフォルトでチェックされていることを確認し、「共有ファイルシステムを追加」を押下します。
作成したEFSが選択されていることを確認。必要に応じてマウントポイントを変更します。
今回はデフォルトで設定されたものをそのまま使用します。
セキュリティグループは既に作成・設定済みのため「自動的に作成してアタッチ」のチェックは外します。
高度な詳細を開きます。今回セッションマネージャー経由でインスタンスにアクセスするため、AmazonSSMManagedInstanceCoreポリシーを付与したIAMロールをEC2に設定します。
最下部までスクロールし、ユーザーデータに自動生成されたスクリプトが入っていることを確認します。「インスタンスを起動」を押下します。
ちなみに以下のようなスクリプトが入っていました。必要に応じて変更も可能です。
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のコンソールから復元テストプランを作成します。
各種全般設定を入れます。
※「次の時間以内に開始」の項目でデフォルトは8時間(以内に開始)が設定されています。
検証のため1時間以内に開始で設定していますが、時間枠は長めに設定がおすすめとの注意書きが出ますので実際に利用の際はご注意ください。
ユースケースに応じて、[次の時間以内に開始] の時間枠を長くすることをお勧めします。開始時間枠が短いと、アカウントで作成できるリソースの数と同時に実行できる復元テストジョブの数に対するクォータ制限が原因で、障害が発生する可能性があります。
各種回復ポイントの選択設定を入れてテストプランを作成します。
主な確認点
-
テストプランの名称にはハイフンが使用できないのでご注意ください。(英数字 or アンダースコア)
-
復旧ポイントの選択基準について、ドキュメントに以下の記載があります。
古いバージョンへの復元が必要になった場合に備えて、ランダムな選択によって復旧ポイントの全般的な状態をより定期的に測定することをお勧めします。
今回、最近の復旧ポイント/ランダムな復旧ポイントをどちらも試しましたが、「最近の復旧ポイント」を選択しても必ずしも作成時間が最新の復旧ポイントが適用されるわけではなさそうでした。
ただ、当日中にバックアップとテストを行なったためかもしれませんので参考までに。そのため、今回の手順ではランダムな復旧ポイントを設定しておきます。
- EFSはPOTR対応リソースタイプではないため特にチェックはしません。
リソース割り当てを行います。全般設定では割り当て名を入力し、クリーンアップ前の保持期間を24時間に設定します。保護されたリソースにEFSを指定します。
その他のオプションも特に変更せず、リソースを割り当て作成します。
バックアッププランの編集(必要に応じて)
EFSの自動バックアップはデフォルト設定の場合日次でUTCの5:00から8時間以内に開始されます。
検証の際にはこれを待たずに確認したいため、必要に応じてプランの編集をします。
AWS Backupのコンソールから「バックアッププラン」を選択し、対象のプラン選択後EFSのバックアップルールを押下します。
右上の編集を押下します。
バックアップの開始時刻を希望の時刻に設定し、保存します。
バックアップが実行されたことを確認
AWS Backupのコンソールで対象のボールトを選択し、バックアップの実行を確認します。
復旧ポイントが追加されていることを確認
復元テストの実行確認(失敗例)
まず、失敗のお知らせから。
エラーメッセージ
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
原因はこちらのブログで記載して下さっています。
デフォルトのバックアップボールト 《aws/efs/automatic-backup-vault》を使用しており、
アクセスポリシーもデフォルトです。これを直していきます。
バックアップボールトのコンソールにアクセスポリシーの設定があるため、「編集」を押下します。
参考ブログの通り、以下の設定とします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": [
"backup:DeleteBackupVault",
"backup:DeleteBackupVaultAccessPolicy",
"backup:DeleteRecoveryPoint",
"backup:StartCopyJob",
"backup:StartRestoreJob", ★削除
"backup:UpdateRecoveryPointLifecycle"
],
"Resource": "*"
}
]
}
復元テストの実行確認(成功)
成功の確認
バックアップジョブの一覧に成功ジョブが存在します。(複数回試したため、大量に出力されています)復元にかかった時間も確認できます。
特定のジョブを押下すると詳細を確認できます。
復元テストのステータスは成功しています。ただ、「検証ステータス」が検証中?
検証ステータスについて
今回、復元されたEFSの中身を確認するためにクリーンアップ前の保持期間を設定しましたが、すぐに削除する設定も可能です。この設定で試した時、この「検証ステータス」はタイムアウトになっていました。
復元テストを実行したのちにLambda等を用いて独自のカスタムスクリプトを実行し、AWS BackupのAPIにそのステータスを返すことが可能であり、そのための項目のようです。
単純なRTOの確認のみであればテストリソースはすぐに削除してしまう方がコスト面でも良さそうですが、独自の確認作業が必要な場合には保持期間を設定し結果検証を自動化出来そうです。
関連情報
復元テストの検証
手動で検証を行う場合は、PutRestoreValidationResultをCLI等で実行してこのステータスの更新が出来ます。
EFSの新規作成を確認
新しくEFSが作成されました!
マウントターゲット作成
EC2からアクセスして中身を確認するために、新規EFSにマウントターゲットを作成します。
マウントターゲット作成後、ターゲットの状態が作成中から利用可能になるのを待ちます。
新規作成された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
ステータスの更新を確認
今回は手動で更新してしまいましたが、復元後の検証用スクリプトを作ってみたくなりますね。
手順ではクリーンアップ前に一定時間待機する方法を記載しましたが、すぐに削除する設定では復元テストを終えた後にEFSを確認すると、自動で削除されていました。
単純に、リソース単体の復元時間を定期的に確認する用途であればテスト後すぐ削除で良いかと思います。
参考
まとめ
RTOのテストを気軽に出来る便利な機能でした!
本番データだと容量も多く時間がかかることが想定されます。定期的な実行を行い備えておけると良いですね。
個人的には復元テストの検証を別途試してみたいと思います。