Building AWS Lambda apps using Make

Introduction

Using AWS Lambda we are able to run micro-service sized applications without any traditional server infastruture. These are called "serverless functions", which run inside ephemeral containers that offer several advantages over the traditional server/host configuration.

We've used AWS Lambda functions for some time now. They're a great way to perform a simple computing at a large scale. And the best part - it comes without the need to manage server instances and other resources.

Lambda allows you to write functions in a variety of different langauges (Java, Node.js, C# and Python). Our functions run on NodeJS.

The latest function we're working on has a single third-party library dependency. This adds an additional step to the development process, since we can't simply paste the function code into the inline editor for testing and deployment. The application package must be manually created via CLI - yet after doing that 2 or 3 times it starts to become redundant. Run a command, wait for it to complete, then run the next and so on...

It was time to automate this process. The solution was to use Make. It's super easy to setup, it's available on Mac and it's grown-up software.

Making things

Our packaging process has the following steps:

  1. Remove any old package.
  2. Install Node non-dev dependencies.
  3. Package the function and dependencies together.

Our Makefile is almost an exact representation of that recipe:

lambda.zip: clean
    rm -rf node_modules/
    npm install --only=production
    zip -r $@ lambda.js node_modules/

clean:
    rm *.zip

It's possible to have several "rules" to make a target in your file. Here, we have two targets: lambda.zip and clean. Simply running make – without params – from the command line will build the ZIP package. However running make clean will just remove all the ZIP files in the directory.

Our lambda.zip target depends on clean to run. But clean depends on nothing. Multiple dependencies are also allowed, if needed. If that's the case, separate them using spaces.

Below the target and its dependencies, there are the commands used to build the target. They must be indented using a tab. The $@ is a reference to the target name.

Going further

We have a third target to test the app. It runs the test command declared in the package.json file.

test:
    rm -rf node_modules/
    npm install
    npm test

Notice the difference in the dependencies install? Here we add all packages, not just the non-dev. That's because we have some libraries that are used for testing purposes.

Since we removed the node_modules directory in both lambda.zip and test targets, we could move it to a separated target and add it as a dependency. We ended up not doing that because it's a single liner and we don't use it alone. In contrast with clean, which is occasionally used with make clean.

Conclusion

This post demonstrates a very simple way to use Make in your development workflow. Its powerful, yet flexible and there are people using it to build far more complex recipes.

If you want to dig deeper and learn more about Make and Makefile structure, there are lots of resources on the web. Though, you'll quickly find articles are about compiling C/C++ programs. This Digital Ocean article is a good starting place to learn how Make works and how it can be used to automate tasks. The man page is also handy, especially after you have some experience.

Thanks for reading! If you have any comments or questions please leave them below.