How to upload a zip to S3 with CDK

Viewed 757

I'm working on building a CDK library and am trying to upload a zip folder to S3 that I can then use for a Lambda deployment later. I've found a lot of direction online to use aws_s3_deployment.

The problem with that construct is that it loads the contents of a zip rather than a zip itself. I've tried to zip a zip inside a zip and that doesn't work. I've also tried to zip a folder and that doesn't work either. The behavior I see is that nothing shows up in S3 and there are no errors from CDK. Is there another way to load a zip to S3?

2 Answers

What you're looking for is the aws-s3-assets module. It allows you to define either directories (which will be zipped) or regular files as assets that the CDK will upload to S3 for you. Using the attributes you can refer to the assets.

The documentation has this example for it:

import { Asset } from 'aws-cdk-lib/aws-s3-assets';

// Archived and uploaded to Amazon S3 as a .zip file
const directoryAsset = new Asset(this, "SampleZippedDirAsset", {
  path: path.join(__dirname, "sample-asset-directory")
});

// Uploaded to Amazon S3 as-is
const fileAsset = new Asset(this, 'SampleSingleFileAsset', {
  path: path.join(__dirname, 'file-asset.txt')
});

In order to upload the zip file to a given bucket I ended up using BucketDeployment with a custom ILocalBundling. The custom bundler will compress the files and put them in an assets directory for CDK to upload. The important part is to set output_type=BundlingOutput.NOT_ARCHIVED, this way CDK will not try to unzip the file.

@implements(ILocalBundling)
class LocalBundling:
    @member(jsii_name="tryBundle")
    def try_bundle(self, output_dir: str, image: DockerImage,) -> bool:
        cwd = pathlib.Path.cwd()

        print(f"bundling to {output_dir}...")
        build_dir = f"{cwd}/directory/to"
        command = ["zip", "-r", f"{output_dir}/python.zip", f"zip"]
        print(command)
        output = subprocess.run(command, capture_output=True, check=True, cwd=build_dir)
        # print(output.stdout.decode("utf-8"))
        return True

local_bundling = LocalBundling()
s3_deployment.BucketDeployment(
    self,
    f"SomeIdForBucketDeployment",
    sources=[
        s3_deployment.Source.asset(
            "directory/to/zip",
            bundling=BundlingOptions(
                command=['none'],
                image=DockerImage.from_registry("lm"),
                local=local_bundling,
                output_type=BundlingOutput.NOT_ARCHIVED,
            ),
        )
    ],
    destination_bucket=some_bucket,
    destination_key_prefix=some_key_prefix,
)
Related