この記事は何か
DataSyncを利用して、EFSとS3のデータ転送を行う際に、つまづきポイントがあったので、簡単にまとめる。
今回DataSyncは初利用だったので、見事にハマったなーという思いと、公式ドキュメントに明記されていなかった部分なので、もしも同じ部分でつまづいた人がいたら、参考になれば嬉しい。
DataSyncとは
AWSが提供するオンラインデータ転送のサービス。
昨年からAWSのストレージサービス間ならエージェント不要でデータ転送が可能となった。めでたい。
つまり、EC2やECSなどのリソースは不要で、マネージドサービスだけでデータの転送が可能
何をしようとしたか
EFSのデータを定期的にS3転送する
極力マネージドサービスで完結したかったので、DataSync TaskでEFSのデータをS3に定期的に転送しようとした
EFSの設定状況
- VPC内に配置されている
- File System Policyが設定され許可したIAMRoleしかMountやWriteができないように制御している
- ECSで稼働中のサービスからマウントされている
進め方
初のDataSyncの利用だったので、素直に公式ドキュメントをみてリソースの作成と設定を試みた。
参考にしたドキュメント
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_DataSync.html
https://docs.aws.amazon.com/datasync/latest/userguide/create-efs-location.html
https://docs.aws.amazon.com/datasync/latest/userguide/create-s3-location.html
リソース作成、実行、そして失敗
EFSからS3へのデータ同期となるので、SourceLocationとしてEFS、DestinationLocationとしてS3のlocationをそれぞれ作成し、後はDataSyncのTaskを作成すれば良いと理解。
IAMRoleやSecurityGrouoなどはつまづきがちな部分は公式でもきっちりフォローされているので大きなトラブルはなさそうと思い、作業をスタート。なお、リソースの作成はCloudFormationで行った。
- Source Location(EFS)の作成
DataSyncLocationEFS:
Type: AWS::DataSync::LocationEFS
Properties:
Ec2Config:
SecurityGroupArns:
- !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:security-group/${EC2SecurityGroupDataSyncEFS}'
SubnetArn: !Sub
- 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:subnet/${SubnetId}'
- SubnetId: ${SubnetId}
EfsFilesystemArn: !GetAtt EFSFileSystemSessions.Arn
Subdirectory: '/dirctory'
- Destination Location(S3)の作成
DataSyncLocationS3:
Type: AWS::DataSync::LocationS3
Properties:
S3BucketArn: !GetAtt S3BucketImageData.Arn
S3Config:
BucketAccessRoleArn: !GetAtt IAMRoleDataSyncLocationS3.Arn
S3StorageClass: STANDARD
- DataSync Taskの作成
DataSyncEFStoS3:
Type: AWS::DataSync::Task
Properties:
DestinationLocationArn: !GetAtt DataSyncLocationS3.LocationArn
Name: !Sub 'EFStoS3'
Schedule:
ScheduleExpression: "cron(55 * * * ? *)"
SourceLocationArn: !GetAtt DataSyncLocationEFS.LocationArn
- IAM Roleの作成
IAMRoleDataSyncLocationS3:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: 'Allow'
Principal:
Service: 'datasync.amazonaws.com'
Action: 'sts:AssumeRole'
Policies:
- PolicyDocument:
Statement:
- Effect: 'Allow'
Action:
- 's3:GetBucketLocation'
- 's3:ListBucket'
- 's3:ListBucketMultipartUploads'
Resource:
- !GetAtt S3BucketImageData.Arn
- Effect: 'Allow'
Action:
- 's3:AbortMultipartUpload'
- 's3:DeleteObject'
- 's3:GetObject'
- 's3:ListMultipartUploadParts'
- 's3:GetObjectTagging'
- 's3:PutObjectTagging'
- 's3:PutObject'
Resource: !Sub '${S3BucketImageData.Arn}/*'
PolicyName: 'datasync-location-s3'
- Security GroupでDataSyncタスクのSubnetからEFSに対して2049のポートアクセスを許可
- EFS側のFile System Policyに今回作成したDataSync TaskのIAMRoleを追加
ここまででリソース作成が完了した形....が、いざタスクを実行すると失敗
具体的にはDataSyncのタスクで以下のエラーが発生した。
Task failed to access location loc-XXXXXXXXXXX: x40016: mount.nfs: Connection timed out
原因調査
エラーメッセージを見るとコネクションタイムアウトとあるので、ネットワーク的な部分で遮断されているように見える。
エラーメッセージが表示されるケースも調べたが、やはり所属するSubnetかSecurity Groupの設定ミスが原因とあり、ネットワーク周りの設定ミスが原因に見えた。
ネットワーク的な問題と思いSubnetの指定ミスやSecurity Groupの設定ミスを疑い確認したが、少なくとも設定ミスはなさそう
問題の切り分けのためにSecurity Groupの制限を緩めたりしてみたけれど、エラーは変わらず
ネットワークの制限を緩めてもエラーが変わらなかったので、おそらくネットワークではないどこかでつまづいていると思い、サポートに問い合わせを投げた
失敗の原因
サポートからの返答を抜粋。
DataSync のタスクが EFS をマウントする際に Connection timed out にてエラーが発生する事象について調査のご報告をいたします。
お客様の設定状況を拝見いたしましたところ、DataSync ロケーションの設定や、EFS マウントターゲットのセキュリティグループやサブネット等の設定に問題は見受けられませんでした。
一方で、調査の結果、当該 EFS に設定されたファイルシステムポリシーが原因となり、当該エラーが発生している可能性が考えられました。
DataSync では、大変恐縮ではございますが、現時点において EFS のアクセスポリシーでの制限をサポートいたしておりません。
また、こちらの制約に関して現在有効なワークアラウンドはなく、EFS のファイルシステムポリシーを削除いただく、あるいは、DataSync を利用せずにコマンドラインツール等にて EFS からデータを転送いただくことが代替案となります。
つまり、 EFSのファイルシステムポリシーを利用しているとDataSyncが使えない という結論。完全に盲点だった。
検証のため、ファイルシステムポリシーを削除したところ、問題なくDataSyncのTaskが成功したので、まさにこのサポートの回答通りの挙動だった。
代替案
DataSyncを利用した代替案はないので(File System Policyを削除すればできるけれど、それを削除するわけにはいかなかったので)、LambdaでEFSからS3にデータ転送を行うスクリプトを書いて定期的に実行することにした。
今回、この同期のスクリプトは本筋ではないので割愛。
まとめ
DataSyncを利用したEFSからのデータ転送やEFSへのデータ転送を行う際、File System Policyを利用している場合は現時点だとできないので、気をつけよう!
反面、今回のようにFile System Policyが利用されているEFSでなければ、S3への定期的なデータ転送が自前のスクリプトなしでできたので、DataSyncがNoOps的な側面で嬉しい機能であることに間違いないなと思えた。