A Simpler Way to Manage Lambda Layers with NPM Dependencies

Here at QloudX, we do a lot of Node.js development. And given our obsession with serverless, a lot of that Node.js code ends up in Lambda functions.

Before Lambda layers came along, the NPM packages that our code depends on, had to be a part of the Lambda function ZIP. After layers were introduced, we did what everyone else did: add a layer resource to our SAM template that would create the layer & then attach this to the Lambda function.

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Resources:
  NodeModulesLayer:
    Type: AWS::Serverless::LayerVersion
    Properties:
      LayerName: node_modules
      ContentUri: node_modules-layer/

The downside of this approach is that the layer is rebuilt every time our code is deployed. It also costs money to rebuild this layer (in CodeBuild), which hardly ever changes. So we came up with a better way!

GitHub Actions for Lambda Layers

We created a public GitHub repo, set up an action on it that would install all the NPM packages we want & deploy them to a Lambda layer in our AWS account. This forces us to think of layers as an application-independent resource that can be attached to Lambda functions across apps with the same NPM dependencies.

It’s also free since GitHub Actions run for free on public repositories (up to a limit). Whenever we need to add NPM packages to the layer, we simply add them to an environment variable for the Action & within minutes, a new version of the layer is deployed to AWS.

The Action workflow follows these steps:

  1. Start with an Ubuntu container.
  2. Set up Node.js on it.
  3. Create a directory named nodejs & install all needed NPM packages inside it. The name nodejs is mandated by the Lambda layer spec.
  4. ZIP up the nodejs directory.
  5. And finally, use the AWS CLI to publish a layer version.

The entire Action workflow spec looks like this:

env:
  NPM_PACKAGES: express mysql
on:
  push:
    branches: [ main ]
  workflow_dispatch:
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/setup-node@v2.1.5
    - run: mkdir nodejs && cd nodejs && npm install $NPM_PACKAGES && cd ..
    - uses: TheDoctor0/zip-release@0.4.1
    - uses: ItsKarma/aws-cli@v1.70.0
      with:
        args: >
          lambda publish-layer-version
          --layer-name node_modules
          --compatible-runtimes nodejs
          --zip-file fileb://release.zip
      env:
        AWS_DEFAULT_REGION: ap-south-1
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

How Can I Use This?

If you would like to use this solution, follow these steps:

  1. Fork this GitHub repo.
  2. Go to your fork’s settings & create the secrets AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY.
  3. Change the environment variable NPM_PACKAGES at the top of the Action spec with the NPM packages you need.
  4. As soon as you push this change, the workflow will run & deploy the layer to your account.

About the Author ✍🏻

Harish KM is a Principal DevOps Engineer at QloudX & a top-ranked APN Ambassador. 👨🏻‍💻

With over a decade of industry experience as everything from a full-stack engineer to a cloud architect, Harish has built many world-class solutions for clients around the world! 👷🏻‍♂️

With over 20 certifications in cloud (AWS, Azure, GCP), containers (Kubernetes, Docker) & DevOps (Terraform, Ansible, Jenkins), Harish is an expert in a multitude of technologies. 📚

These days, his focus is on the fascinating world of DevOps & how it can transform the way we do things! 🚀

Leave a Reply

Your email address will not be published.