如何使用 aws cdk 中的自定义资源将文件上传到 s3 存储桶

How to upload a file to an s3 bucket with a custom resource in aws cdk

我需要在创建 zip 文件后将其上传到 s3 存储桶。我知道 s3_deployment 包,但它不适合我的用例,因为我只需要在堆栈创建时上传一次文件。 s3_deployment 包会在每次更新时上传 zip。

我定义了以下自定义资源,但我不确定如何将文件主体传递给自定义资源。我试过以二进制模式打开文件,但是 returns 出错了。

app_data_bootstrap = AwsCustomResource(self, "BootstrapData",
    on_create={
        "service": "S3",
        "action": "putObject",
        "parameters": {
            "Body": open('app_data.zip', 'rb'),
            "Bucket": f"my-app-data",
            "Key": "app_data.zip",
        },
        "physical_resource_id": PhysicalResourceId.of("BootstrapDataBucket")
    },
    policy=AwsCustomResourcePolicy.from_sdk_calls(resources=AwsCustomResourcePolicy.ANY_RESOURCE)
)

我认为这是不可能的,除非您编写自定义脚本并在 cdk deploy 之前运行以将本地文件上传到中间 S3 存储桶。然后您可以编写自定义资源,将 on_create 事件中的中间存储桶的内容复制到通过 CDK 创建的存储桶。

阅读 CDK 文档 s3_deployment 中的这段内容:

This is what happens under the hood:

  1. When this stack is deployed (either via cdk deploy or via CI/CD), the contents of the local website-dist directory will be archived and uploaded to an intermediary assets bucket. If there is more than one source, they will be individually uploaded.

  2. The BucketDeployment construct synthesizes a custom CloudFormation resource of type Custom::CDKBucketDeployment into the template. The source bucket/key is set to point to the assets bucket.

  3. The custom resource downloads the .zip archive, extracts it and issues aws s3 sync --delete against the destination bucket (in this case websiteBucket). If there is more than one source, the sources will be downloaded and merged pre-deployment at this step.

因此,为了执行第 1 步的复制操作,您必须编写一个小脚本来创建一个中间存储桶并将您的本地文件上传到其中。该脚本的示例可以是这样的:

#!/bin/sh
aws s3 mb <intermediary_bucket> --region <region_name>
aws s3 sync <intermediary_bucket> s3://<your_bucket_name>

那么你的自定义资源可以是这样的:

*请注意,这适用于复制一个对象,您可以更改代码以复制多个对象。

import json
import boto3
import cfnresponse

def lambda_handler(event, context):
    print('Received request:\n%s' % json.dumps(event, indent=4))

    resource_properties = event['ResourceProperties']

    if event['RequestType'] in ['Create']: #What happens when resource is created
        try:
            s3 = boto3.resource('s3')
            copy_source = {
                'Bucket': 'intermediary_bucket',
                'Key': 'path/to/filename.extension'
            }
            bucket = s3.Bucket('otherbucket')
            obj = bucket.Object('otherkey')
            obj.copy(copy_source)

        except:
            cfnresponse.send(event, context, cfnresponse.FAILED, {})
            raise
        else:
            cfnresponse.send(event, context, cfnresponse.SUCCESS,
                             {'FileContent': response['fileContent'].decode('utf-8')})
    elif event['RequestType'] == 'Delete': # What happens when resource is deleted
        cfnresponse.send(event, context, cfnresponse.SUCCESS, {})

所有这些的替代方法是在 AWS CDK 的 Github repo 中打开一个问题并要求他们添加您的用例。