AWS Lambda part 2 – packaging and deploying

I received positive feedback on my AWS Lambda presentation in London. This post discusses how to package and deploy your lambda function.

I’m sure there are other ways but I wanted something simple. This allows me to maintain separate enviroments (i.e “dev”, “production”).

Makefile

I use Make to create a package (i.e “sample-app.zip”). The dependencies are installed into a virtualenv which are appended to the package.

Create the function

make build-dev
make create-dev

Deploy the package

make build-dev
make update-dev
PROJECT = sample-python-app
FUNCTION = $(PROJECT)
REGION = us-east-1
.phony: clean
clean:
rm -f -r $(FUNCTION)*
rm -f -r site-packages
build-dev: clean
aws s3 cp s3://$(FUNCTION)/settings-dev.yml settings.yml
zip -r $(FUNCTION)-dev.zip . -x *.git* tests/*
mkdir -p site-packages
virtualenv $(FUNCTION)-dev
. $(FUNCTION)-dev/bin/activate
pip install -r requirements.txt
cd site-packages; cp -r $$VIRTUAL_ENV/lib/python2.7/site-packages/ ./
cd site-packages; zip -g -r ../$(FUNCTION)-dev.zip .
create-dev:
aws lambda create-function \
–handler main.lambda_handler \
–function-name $(FUNCTION)-dev \
–region $(REGION) \
–zip-file fileb://$(FUNCTION)-dev.zip \
–role arn:aws:iam::XXXX:role/$(FUNCTION)-dev \
–runtime python2.7 \
–timeout 120 \
–memory-size 512 \
update-dev:
aws lambda update-function-code \
–function-name $(FUNCTION)-dev \
–zip-file fileb://$(FUNCTION)-dev.zip \
–publish \
delete-dev:
aws lambda delete-function –function-name $(FUNCTION)-dev

Lambda deployment package

Make sure you include all the dependencies in the package. You need to copy the contents of site-packages, NOT the directory itself. If you copy site-packages itself, lambda will not be able to find the modules.

The contents will look something similar to:

main.py
netstorage/
netstorage/__init__.py
requests/
requests/__init__.py

Testing locally

Instead of constantly deploying the function, I wanted to test my changes locally.

When creating an AWS lambda function, you need to specify the handler gets executes. In the gist above, I specify it with –handler main.lambda_handler. So testing locally is simple as:

if __name__ == "__main__":
    lambda_handler(None, None)