问题描述
我将Lambda连接到EFS,我想使用Lambda从S3将小文件下载到EFS。
我将Lambda函数连接到文件系统,并添加了具有777权限的访问点。
我在Lambda中有这个小的python函数,可以下载到挂载中:
import json
import boto3
import time
import os
s3 = boto3.client('s3')
def lambda_handler(event,context):
s3.download_file('my_bucket','img.jpg','/mnt/my-efs/img.jpg')
return{
"statusCode": 200
}
我在1分钟后超时(这应该少于一秒钟)。
如果我为/tmp/img.jpg
下载,则可以使用。即使我将文件从/tmp/
复制到/mnt/my-efs/
也可以。
我为Lambda用户提供了此IAM:
AmazonEC2FullAccess
AmazonS3FullAccess
AmazonVPCFullAccess
AWSLambdaVPCAccessExecutionRole
AmazonElasticFileSysstemClientReadWriteAccess
AmazonElasticFileSysstemClientFullAccess
为什么不能使用Lambda将文件从S3下载到EFS?
解决方法
这是一个非常棘手的问题,所以让我们慢慢来,确保我们涵盖了所有活动部件。如果其中一些是多余的,我深表歉意,但我想确保外行人拥有所有正确的部分。如果您认为我遗漏了什么,请告诉我。
设置:
serverless.yaml
- AWS 访问点设置
- Lambda 添加了 EFS
- 将项目下载到 EFS 驱动器
- 验证您的文件是否在 EFS 中
1. serverless.yaml
我使用的是无服务器,所以这就是我的 serverless.yaml
文件的样子。
iamRoleStatements:
- Effect: Allow
Action:
- elasticfilesystem:ClientMount
- elasticfilesystem:ClientWrite
- elasticfilesystem:ClientRootAccess
Resource:
- arn:aws:elasticfilesystem:us-west-2:123456789:file-system/fs-123456789
这些是我将文件从 S3 下载到 EFS 驱动器位置所需的最低权限。同样,该项目使用无服务器,因此如果您不使用无服务器,所有这些都可以转换为 cloudFormation 模板。
在处理函数下...
functions:
myFunc:
handler: handler.handle
package:
exclude:
- env/**
- node_modules/**
description: Lambda to download S3 file to SFTP EFS folder.
events:
- s3:
bucket: some-bucket
event: s3:ObjectCreated:*
rules:
- prefix: some-folder/
- suffix: .jpg
existing: true
fileSystemConfig:
localMountPath: /mnt/my-efs
arn: arn:aws:elasticfilesystem:us-west-2:123456789:access-point/fsap-12345678910
注意:我从 serverless.yaml
文件中遗漏了很多内容,只包含了与 EFS 设置有关的部分。
2. AWS EFS 访问点设置
-
- 转到 EFS 服务。
-
- 点击接入点。
-
- 创建新的接入点
-
- 根据需要填写字段。以下是我如何配置我的
-
详情
-
File System:
选择一个下拉选项 -
Name - optional
选择一个名字 -
Root directory path - optional:
这将映射到您在 EC2 或 SFTP 服务器上的底层文件系统。我使用的是 sftp 服务器,所以我只需在 sftp 服务器上输入地址。sftp.companyX.com/images
。此位置将映射到 EFS 配置窗口中您的 Lambda 设置中的Local Mount Path
集(我们将在第 3 步中详细介绍)。
-
-
POSIX 用户
-
User ID:
1054
|找到您的/etc/passwd/
文件并验证此文件是否适用于托管 EFS 驱动器的服务器。我认为1054
是 amazon linux 的默认设置,但如果您在 EFS 主机上运行不同的操作系统,则应验证此值。 -
Group ID:
1054
(见最后一行)
-
-
根目录创建权限
-
Owner User ID:
1054
(见最后一行) -
Owner Group ID:
1054
(见最后一行) -
POSIX permissions to apply to the root directory path
:777
|了解这些权限会转化为您的iamRoleStatements.Action
值;如果它们不同,则应适当设置此777
。
-
3. EFS 的 Lambda 添加
-
EFS File System:
(从下拉列表中选择) -
Local Mount Path:
| 非常重要/mnt/my-efs
。这部分是非常不直观的 IMO。无论您想要什么位置,此位置都会映射到您在构建接入点时配置的Root directory path
(上面的步骤 2.4)。这意味着,如果您将名为img.jpg
的 s3 文件下载到/mnt/my-efs/.
,它将将该文件放入sftp.company.com/images/img.jpg
。
4.将项目下载到 EFS 驱动器
- 显然,这可以通过多种方式完成。您的原始代码看起来非常好。作为示例,我只是将其扩展为从 S3 事件对象中提取文件位置。如果不明显,则每当 S3 存储桶获取新上传(添加到存储桶的新对象)时,都会触发 S3 事件。
def download_files_to_efs(self,event):
"""
Locates the S3 file name (i.e. S3 object "key" value) the initiated the Lambda call,then downloads the file
into the locally attached EFS drive at the target location.
:param: event | S3 event record
:return: dict
"""
key = event.get('Records')[0].get('s3').get('object').get('key') # some-bucket/some-folder/img.jpg
efs_loci = f"/mnt/my-efs/images/{key.split('/')[-1]}" # '/mnt/my-efs/images/img.jpg
result = self.s3.download('some-bucket',key,efs_loci)
if result:
print('Download Success...')
else:
print('Ask Stack Overflow :/')
return { 'status_code': 200 }
5.验证您的文件在 EFS 中
- 要验证下载是否有效,您只需从 Lambda 内的 EFS 位置打印文件,然后检查内置 CloudWatch 日志以查看结果是否符合预期。
def get_files_from_path(file_path):
"""
Returns the files found at the file_path
:param file_path: string
:return list:
"""
# NOTE: file_path = '/my-efs/
found_files = []
for _,_,f in os.walk(file_path):
found_files.append(f)
if found_files:
print('efs files: ',found_files)
return found_files
这里特别注意!请注意,我没有从 /mnt/my-efs/
读取,而是从 /my-efs
读取,这是因为 EFS /
目录映射到 Lambda 环境中的 /mnt
目录。
完成?
注意:如果我遗漏了某些内容,请随时发表评论,如果可以,我也会添加。不幸的是,我无法共享该存储库,因为它是一个与工作相关的项目(受保护)。
,除了@Tobiah 的回答。我从 aws 得到了这个答案:
要从 Lambda 函数访问 S3 服务,我们需要访问互联网或 S3 VPC 端点。
现在,为了让 lambda 函数从 VPC 内部访问互联网,我们需要通过 NAT 网关或 NAT 实例路由流量。将 lambda 放置在 VPC 的公共子网中不会让 lambda 获得互联网访问权限。 [1] 您可以将私有子网附加到 lambda 函数,该函数具有到在 VPC 的公共子网内启动的 NAT 网关或 NAT 实例的默认路由。请参阅此文档 [2] 以获取分步指南。请注意,使用 NAT 网关会产生额外费用。 [3] 或者使用 S3 VPC 端点将 lambda 连接到 S3。请参阅此文档 [4] 以获取分步指南。 另外,关于在 EFS 中加密文件,请参阅此文档[5]。
[1] dotenv
[2] https://docs.aws.amazon.com/lambda/latest/dg/configuration-vpc.html#vpc-internet
[3] https://aws.amazon.com/premiumsupport/knowledge-center/internet-access-lambda-function/
[4] https://aws.amazon.com/vpc/pricing/
[5] https://docs.aws.amazon.com/vpc/latest/privatelink/vpc-endpoints-s3.html