Amazon S3 Files が GA — S3 バケットをファイルシステムとしてマウント、EFS と比較してみた
2026/4/7、Amazon S3 Files の一般提供(GA)が発表されました。
S3 バケットをファイルシステムとしてマウントできる新機能です。S3 バケットの作成、IAM ロールの準備、S3 Files ファイルシステムの構築までを AWS CLI で行い、Amazon Linux 2023 上にマウント。
マウント後はファイル操作やロックの動作を検証するとともに、EFS との I/O 性能や同期ラグなどを測定しましたので、その結果を紹介します。
S3 Files とは
S3 Files は、S3 バケットのデータに対してファイルシステムインターフェースを提供するサービスです。Amazon EFS をベースに構築されており、NFS v4.2 プロトコルで EC2 や Lambda、EKS、ECS からマウントできます。
- S3 バケットの既存データにそのままファイルとしてアクセスできる
- ファイルシステムへの書き込みは自動的に S3 バケットに同期される
- アクティブに使用するデータのみが高性能ストレージにキャッシュされる
- 最大 25,000 のコンピュートリソースから同時アクセス可能
検証環境
| 項目 | 値 |
|---|---|
| OS | Amazon Linux 2023 (aarch64) |
| インスタンスタイプ | r7gd.medium |
| リージョン / AZ | us-west-2 / us-west-2a |
| VPC | デフォルト VPC |
| AWS CLI | 2.34.26 |
| amazon-efs-utils | 3.0.0 |
手順 1: AWS CLI の更新
S3 Files の CLI コマンド(aws s3files)を使うには AWS CLI 2.34 以上が必要です。最新バージョンへ更新しました。
curl -s "https://awscli.amazonaws.com/awscli-exe-linux-aarch64.zip" -o /tmp/awscliv2.zip
cd /tmp && unzip -qo awscliv2.zip
sudo ./aws/install --update
x86_64 環境の場合は URL を https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip に変更してください。
更新後、aws s3files help でサブコマンド一覧が表示されれば OK です。
$ aws --version
aws-cli/2.34.26 Python/3.14.3 Linux/6.1.161-183.298.amzn2023.aarch64
$ aws s3files help
...
AVAILABLE COMMANDS
o create-file-system
o create-mount-target
o get-file-system
o list-file-systems
o list-mount-targets
...
手順 2: S3 バケットの作成
S3 Files にはバージョニングが有効な S3 バケットが必要です。バケット作成とバージョニング有効化を行いました。
BUCKET_NAME="s3files-demo-$(date +%Y%m%d)-${RANDOM}"
REGION="us-west-2"
# バケット作成
aws s3api create-bucket \
--bucket "${BUCKET_NAME}" \
--region "${REGION}" \
--create-bucket-configuration LocationConstraint="${REGION}"
# バージョニング有効化
aws s3api put-bucket-versioning \
--bucket "${BUCKET_NAME}" \
--versioning-configuration Status=Enabled
手順 3: IAM ロールの作成
S3 Files がバケットにアクセスするための IAM ロールを作成しました。
ポリシー作成
信頼ポリシー
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
cat > /tmp/s3files-trust-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "elasticfilesystem.amazonaws.com"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "${ACCOUNT_ID}"
},
"ArnLike": {
"aws:SourceArn": "arn:aws:s3files:${REGION}:${ACCOUNT_ID}:file-system/*"
}
}
}
]
}
EOF
aws iam create-role \
--role-name S3FilesRole-demo \
--assume-role-policy-document file:///tmp/s3files-trust-policy.json
インラインポリシー
cat > /tmp/s3files-policy.json << EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "S3BucketPermissions",
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:ListBucketVersions"],
"Resource": "arn:aws:s3:::${BUCKET_NAME}",
"Condition": {
"StringEquals": { "aws:ResourceAccount": "${ACCOUNT_ID}" }
}
},
{
"Sid": "S3ObjectPermissions",
"Effect": "Allow",
"Action": [
"s3:AbortMultipartUpload", "s3:DeleteObject*",
"s3:GetObject*", "s3:List*", "s3:PutObject*"
],
"Resource": "arn:aws:s3:::${BUCKET_NAME}/*",
"Condition": {
"StringEquals": { "aws:ResourceAccount": "${ACCOUNT_ID}" }
}
},
{
"Sid": "UseKmsKeyWithS3Files",
"Effect": "Allow",
"Action": [
"kms:GenerateDataKey", "kms:Encrypt", "kms:Decrypt",
"kms:ReEncryptFrom", "kms:ReEncryptTo"
],
"Condition": {
"StringLike": {
"kms:ViaService": "s3.${REGION}.amazonaws.com",
"kms:EncryptionContext:aws:s3:arn": [
"arn:aws:s3:::${BUCKET_NAME}",
"arn:aws:s3:::${BUCKET_NAME}/*"
]
}
},
"Resource": "arn:aws:kms:${REGION}:${ACCOUNT_ID}:*"
},
{
"Sid": "EventBridgeManage",
"Effect": "Allow",
"Action": [
"events:DeleteRule", "events:DisableRule", "events:EnableRule",
"events:PutRule", "events:PutTargets", "events:RemoveTargets"
],
"Condition": {
"StringEquals": { "events:ManagedBy": "elasticfilesystem.amazonaws.com" }
},
"Resource": ["arn:aws:events:*:*:rule/DO-NOT-DELETE-S3-Files*"]
},
{
"Sid": "EventBridgeRead",
"Effect": "Allow",
"Action": [
"events:DescribeRule", "events:ListRuleNamesByTarget",
"events:ListRules", "events:ListTargetsByRule"
],
"Resource": ["arn:aws:events:*:*:rule/*"]
}
]
}
EOF
aws iam put-role-policy \
--role-name S3FilesRole-demo \
--policy-name S3FilesBucketAccess \
--policy-document file:///tmp/s3files-policy.json
ポリシーの内容は 公式ドキュメント に準拠しています。
また、EC2 のインスタンスプロファイルには以下の権限も必要です。
AmazonS3FilesClientFullAccess(またはAmazonS3FilesClientReadOnlyAccess)- S3 バケットへの直接読み取り権限(読み取りパフォーマンス最適化のため)
手順 4: ファイルシステムの作成
ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/S3FilesRole-demo"
aws s3files create-file-system \
--region "${REGION}" \
--bucket "arn:aws:s3:::${BUCKET_NAME}" \
--role-arn "${ROLE_ARN}"
レスポンスの fileSystemId を控えておきます。
FS_ID="fs-0123456789abcdef0" # 出力された fileSystemId に置き換え
手順 5: マウントターゲットの作成
EC2 インスタンスと同じサブネットにマウントターゲットを作成しました。
SUBNET_ID="subnet-xxxxxxxx" # EC2 と同じサブネット
aws s3files create-mount-target \
--region "${REGION}" \
--file-system-id "${FS_ID}" \
--subnet-id "${SUBNET_ID}"
available になるまで数分待ちました。ステータスは以下で確認できます。
aws s3files list-mount-targets \
--region "${REGION}" \
--file-system-id "${FS_ID}" \
--query 'mountTargets[0].{status:status,ip:ipv4Address}'
手順 6: セキュリティグループの設定
マウントターゲットのセキュリティグループに、EC2 からの NFS(TCP 2049)インバウンドを許可する必要がありました。
# マウントターゲットの SG を確認(ENI から取得)
MT_IP="172.31.xx.xx" # マウントターゲットの IP
aws ec2 describe-network-interfaces \
--filters "Name=addresses.private-ip-address,Values=${MT_IP}" \
--query 'NetworkInterfaces[0].Groups[0].GroupId' \
--output text
# EC2 の SG からマウントターゲットの SG への TCP 2049 を許可
MT_SG="sg-xxxxxxxxx" # マウントターゲットの SG
EC2_SG="sg-yyyyyyyyy" # EC2 の SG
aws ec2 authorize-security-group-ingress \
--group-id "${MT_SG}" \
--ip-permissions '[{
"FromPort": 2049,
"ToPort": 2049,
"IpProtocol": "tcp",
"UserIdGroupPairs": [{"GroupId": "'${EC2_SG}'", "Description": "NFS from EC2 for S3 Files"}]
}]'
手順 7: amazon-efs-utils のインストール
S3 Files のマウントヘルパー(mount.s3files)は amazon-efs-utils 3.0.0 以上 に含まれています。
# efs-utils リポジトリの追加
sudo bash -c 'cat > /etc/yum.repos.d/efs-utils.repo << EOF
[efs-utils]
name=efs-utils repository
baseurl=https://amazon-efs-utils.aws.com/repo/rpm/amazon/2023
priority=1
enabled=1
repo_gpgcheck=1
type=rpm
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-efs-utils.gpg
EOF'
sudo curl -fsSL https://amazon-efs-utils.aws.com/efs-utils-armored.gpg \
-o /etc/pki/rpm-gpg/RPM-GPG-KEY-efs-utils.gpg
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-efs-utils.gpg
# インストール
sudo dnf install -y amazon-efs-utils-3.0.0
# botocore も root 向けにインストール(IAM 認証で使用)
sudo python3 -m pip install botocore
$ rpm -q amazon-efs-utils
amazon-efs-utils-3.0.0-1.amzn2023.aarch64
$ which mount.s3files
/sbin/mount.s3files
手順 8: マウントと動作確認
sudo mkdir -p /mnt/s3files
sudo mount -t s3files ${FS_ID}:/ /mnt/s3files
$ df -hT /mnt/s3files
Filesystem Type Size Used Avail Use% Mounted on
127.0.0.1:/ nfs4 8.0E 0 8.0E 0% /mnt/s3files
8.0E(8 エクサバイト)は S3 の実質無制限のストレージ容量を反映しています。
ファイルを作成して S3 側への反映を確認しました。
echo "Hello from S3 Files!" > /mnt/s3files/test.txt
cat /mnt/s3files/test.txt
Hello from S3 Files!
# S3 側で確認(同期に ~1 分かかる場合があります)
sleep 60
aws s3 ls s3://${BUCKET_NAME}/
2026-04-08 07:45:12 21 test.txt
ファイルシステムへの書き込みが S3 バケットに自動同期されていることを確認できました。
EFS との簡易パフォーマンス比較
S3 Files は EFS をベースに構築されています。同一インスタンスに EFS(Elastic スループットモード)もマウントし、簡易的な比較を行いました。
I/O パフォーマンス
各テストは 3 回実行し、中央値を採用しました。読み込みテスト前にはページキャッシュをクリアしています。
| テスト | S3 Files | EFS | 差 |
|---|---|---|---|
| 1GB 書き込み | 4.283s (約 239 MB/s) | 4.224s (約 242 MB/s) | ほぼ同等 |
| 1GB 読み込み | 1.601s (約 639 MB/s) | 1.474s (約 694 MB/s) | S3 Files が約 9% 遅い |
| 1KB×1,000 書き込み | 11.265s | 9.048s | S3 Files が約 24% 遅い |
| 1KB×1,000 読み込み | 4.916s | 3.665s | S3 Files が約 34% 遅い |
大容量ファイルの書き込みはほぼ同等でした。S3 Files は 1MB 以上の読み込みを S3 から直接ストリーミングする設計のため、大容量の読み込みでも差は小さくなっています。小容量ファイルの多数操作では EFS が優位でしたが、S3 Files でも 1 ファイルあたり約 11ms で書き込みが完了しており、実用上は十分な性能でした。
同期ラグ
S3 Files と S3 バケット間の同期は双方向で自動的に行われます。公式ドキュメントによると、ファイルシステムへの書き込みは最大 60 秒間の変更を集約して 1 回の S3 PUT で同期し、S3 バケットへの直接変更は S3 Event Notifications で検知してファイルシステムに反映されます。
| 方向 | 計測方法 | 中央値 |
|---|---|---|
| ファイルシステム → S3 | 書き込み後、head-object でポーリング |
約 63〜66 秒 |
| S3 → ファイルシステム | s3 cp 後、ファイル出現をポーリング |
約 30 秒 |
ファイルシステム → S3 方向は公式ドキュメントの「最大 60 秒間の変更を集約」という仕様と一致しました。S3 → ファイルシステム方向は S3 Event Notifications の配信間隔に依存するため、タイミングによってばらつきがありました。
S3 オブジェクトのメタデータ
S3 に同期されたオブジェクトには、POSIX のパーミッション、オーナー、タイムスタンプが S3 オブジェクトメタデータとして保持されていました。
Metadata:
user-agent: aws-s3-files
file-permissions: 0100644
file-owner: 0
file-group: 0
file-mtime: 1775634941827000000ns
ファイルロックの動作確認
S3 Files は NFS v4.2 のファイルロックをサポートしています。flock による排他ロックの動作を確認しました。
FILE=/mnt/s3files/locktest.txt
echo "test" > $FILE
# プロセス1: 排他ロックを取得して3秒保持
(
flock -x 200
echo "P1 lock acquired at $(date +%T)"
sleep 3
echo "P1 lock released at $(date +%T)"
) 200>$FILE &
sleep 0.5
# プロセス2: 排他ロックを要求(P1が解放するまで待機)
(
echo "P2 waiting at $(date +%T)"
flock -x 200
echo "P2 lock acquired at $(date +%T)"
) 200>$FILE &
wait
P1 lock acquired at 08:15:48
P2 waiting at 08:15:48
P1 lock released at 08:15:51
P2 lock acquired at 08:15:51
排他ロック、非ブロッキングモード(flock -n)ともに期待通りに動作しました。
S3 API からの変更はロックをバイパスする
ファイルシステムで排他ロックを保持した状態で、S3 API から同じファイルを上書きする検証を行いました。
| タイミング | ファイルシステム | S3 API |
|---|---|---|
| ロック取得前 | original content |
original content |
| ロック中に S3 API で上書き後 | OVERWRITTEN BY S3 API |
OVERWRITTEN BY S3 API |
| ロック解放後 | OVERWRITTEN BY S3 API |
OVERWRITTEN BY S3 API |
S3 API はファイルシステムのロックを一切認識せず、ロック保持中でも上書きが成功しました。変更内容はロック保持中のプロセスからも即座に見えました。
まとめ
S3 Files を AWS CLI でゼロから構築し、マウント、EFS との比較、ファイルロックの検証まで行いました。
検証結果
I/O 性能は EFS とほぼ同等で、大容量ファイルの書き込みでは差がなく、小容量ファイルの多数操作でも実用上十分な性能でした。S3 への同期は約 1 分、S3 からファイルシステムへの反映は約 30 秒で完了しました。NFS のファイルロックは正常に動作しましたが、S3 API からの操作はロックをバイパスするため、両方の経路からデータを更新するワークロードでは注意が必要です。
S3 Files が効くユースケース
SDK や CLI で S3 をネイティブに利用することが難しいワークロードに対して、最小限の変更で S3 を活用できる点が最大の価値です。NFS v4.2 対応の既存アプリケーションであれば、マウントポイントの変更だけでコード変更なしに S3 上のデータを扱えます。
S3 のバージョニングが必須のため変更履歴が自動保持され、イレブンナインの耐久性もそのまま活きます。アクティブなデータのみが高性能ストレージにキャッシュされるため、S3 と別途ファイルシステムを併用してデータを二重管理する構成と比べてコスト削減も期待できます。
より高い NFS 性能が必要な場合
S3 Files を採用する際は、同期ラグやファイルロックの制約がワークロードの要件に合っているか、事前に十分な検証をおすすめします。特に小容量ファイルを大量に扱うワークロードでは、S3 への同期に伴う API リクエスト費用が積み上がる可能性がある点にも注意が必要です。検証の結果、レイテンシやスループット、コストが要件を満たせない場合は、Amazon FSx for NetApp ONTAP も有力な選択肢です。マルチプロトコル(NFS / SMB / iSCSI)対応に加え、S3 への自動階層化(FabricPool)機能も備えており、高性能なファイルアクセスと S3 のコスト効率を両立できます。







