微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我无法使用Lambda将文件从S3下载到EFS

如何解决我无法使用Lambda将文件从S3下载到EFS

我将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?

解决方法

这是一个非常棘手的问题,所以让我们慢慢来,确保我们涵盖了所有活动部件。如果其中一些是多余的,我深表歉意,但我想确保外行人拥有所有正确的部分。如果您认为我遗漏了什么,请告诉我。

设置:

  1. serverless.yaml
  2. AWS 访问点设置
  3. Lambda 添加了 EFS
  4. 将项目下载到 EFS 驱动器
  5. 验证您的文件是否在 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 访问点设置

    1. 转到 EFS 服务。
    1. 点击接入点。
    1. 创建新的接入点
    1. 根据需要填写字段。以下是我如何配置我的
    • 详情
      • 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 驱动器的服务器。我认为 1054amazon linux 的默认设置,但如果您在 EFS 主机上运行不同的操作系统,则应验证此值。
      • Group ID: 1054(见最后一行)
    • 根目录创建权限
      • Owner User ID: 1054(见最后一行)
      • Owner Group ID: 1054(见最后一行)
      • POSIX permissions to apply to the root directory path777 |了解这些权限会转化为您的 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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。