aws / aws-cdk

The AWS Cloud Development Kit is a framework for defining cloud infrastructure in code
https://aws.amazon.com/cdk
Apache License 2.0
11.7k stars 3.93k forks source link

lambda: allow bundling of lambda layer #26332

Open JonWallsten opened 1 year ago

JonWallsten commented 1 year ago

Describe the feature

We are missing the bundling functionality when creating LayerVersions in the CDK v2.

Use Case

We have a lambda layer that uses imports from sibling/root folders (let say a shared util folder in root), but since they will not be included in the same output folder as the layer, these imports will be missing in runtime. The same goes for node_modules. The modules used would have to be part of the assets target folder. Bundling the layer takes care of this issue by making sure the imports are included in the bundle. It also just includes the modules use since esbuild offers some treeshaking.

Proposed Solution

Offer the same bundling as the NodeJsFunction (also requested for Lambda @ Edge here: https://github.com/aws/aws-cdk/issues/14215).

Other Information

No response

Acknowledgements

CDK version used

2.87.0

Environment details (OS name and version, etc.)

Windows 10 x64. Node 18.12.x.

pahud commented 1 year ago

Thank you for your feature request. Can you share more details about what your directory structure looks like?

JonWallsten commented 1 year ago

@pahud: It could look something like this:

.
├── .dist/
│   ├── assets/
│   │   ├── lambda-edge/
│   │   │   └── auth-guard.js
│   │   └── lambda-layer/
│   │       ├── auth.js
│   │       ├── common.js
│   │       └── index.js
│   ├── lib/
│   │   ├── api-stack.js
│   │   └── lambda-stack.js
│   └── utils/
│       ├── auth.js
│       └── common.js
├── assets/
│   ├── lambda-edge/
│   │   └── auth-guard.ts
│   └── lambda-layer/
│       ├── auth.ts
│       ├── common.ts
│       └── index.ts
├── lib/
│   ├── api-stack.ts
│   └── lambda-stack.ts
├── utils/
│   ├── auth.ts
│   └── common.ts
└── README.md

Where in this case the .dist/assets/lambda-layer/index.js would have local imports to `.dist/utils/common.js looking like this: import * from '../../utils/common'; But the Code.fromAssets('./dist/assets/lambda-layer') would not include that file.

But the same goes for any node_modules. They would not be part of the assets folder either. So I guess I should update the ticket.

pahud commented 1 year ago

OK now I get it.

Unfortunately lambda layer only support Code with no bundling capabilities. Please help us prioritize with upvotes 👍.

pahud commented 1 year ago

btw

Why not just Code.fromAssets('./dist') ?

pahud commented 1 year ago

probably related to https://github.com/aws/aws-cdk/issues/26107#issuecomment-1634334071

JonWallsten commented 1 year ago

@pahud: Using the full ./dist folder with code from all different stacks/utils/etc for a single LambdaLayer would probably not be a good idea.

jk2l commented 3 months ago

not sure is this issue outdated, i have bundling work for layer

        self.oracle_19_1_layer = lambda_.LayerVersion(
            self,
            "OracleDependency",
            layer_version_name="oracle-dependency-19_1",
            code=lambda_.Code.from_asset(
                "./assets/lambda/oracle-19.1",
                bundling=cdk.BundlingOptions(
                    image=lambda_.Runtime.PYTHON_3_9.bundling_image,
                    command=[
                        "bash",
                        "-c",
                        " && ".join(
                            [
                                f"pip install -r requirements.txt -t /{cdk.AssetStaging.BUNDLING_OUTPUT_DIR}/python/lib/python3.9/site-packages",
                                f"cp -r ./lib /{cdk.AssetStaging.BUNDLING_OUTPUT_DIR}/lib",
                            ]
                        ),
                    ],
                ),
            ),
            compatible_runtimes=[lambda_.Runtime.PYTHON_3_9],
            license="Available under the MIT-0 license.",
            description="A layer of oracle dependency",
        )
pahud commented 3 months ago

@jk2l Awesome!

@JonWallsten does it work for you?

JonWallsten commented 3 months ago

I'm using Typescript so this particular code would not work. I'm on vacation, but I think I'm using esbuild to generate the bundle and then use Code.fromAsset.

cranberyxl commented 1 month ago

I would also be interested in using some of the Bundling functionality for create a lambda layer, specifically, the node modules part of the code. We have cases come up where we need to externalize a node module. We end up running a script npm install --cpu=x64 --os=linux --libc=glibc --no-package-lock --no-save --prod --prefix=./dist/sharp/nodejs sharp before cdk install to install the lambda version of a module and then pointing to the code use something like AssetCode.fromAsset('dist/sharp'). However, this does not scale well for other externals. If we could use the nodeModules code that is alreayd written in bundling it would be easy to create a layer purely in cdk where Bundling.nodeModules(['sharp']) would just run that bit of the code from Bundling:


    const sharpLayer = new LayerVersion(this, 'sharpLayer', {
      code: Bundling.nodeModules(['sharp']),
      compatibleRuntimes: [Runtime.NODEJS_18_X, Runtime.NODEJS_20_X],
      license: 'Apache-2.0',
      description: 'Sharp layer',
    });