This repo serves as a starting point for building reliable aws lambda functions in python. These examples are focused on not only teaching the basics, but providing examples of common use cases, and discusses the developer workflow that I have learned to use.
Each example will have the basic structure:
.
├── events <-- Sample events
├── src <-- Source code for a lambda function
│ └── service
│ ├── __init__.py
│ └── app.py <-- Lambda function code
├── tests <-- Unit tests
│ ├── __init__.py
│ └── test_handler.py
├── requirements.txt <-- Python dependencies
├── template.yaml <-- SAM template
├── setup.py <-- setup script
└── tox.ini <-- tox configurationMore information on why this is the structure I use for Python projects.
- AWS CLI already configured with Administrator permission
- SAM CLI >=0.7 installed
- Python 3 installed
- Docker installed
- Virtualenvwrapper or roll your own with Python Virtual Environment
You can either use homebrew or use pyenv.
For homebrew
brew unlink pythonbrew install https://raw.githubusercontent.com/Homebrew/homebrew-core/f2a764ef944b1080be64bd88dca9a1d80130c558/Formula/python.rbWe are installing the latest 3.6 formula here, the current on homebrew is 3.7.brew switch python 3.6.5_1
Using virtualenvwapper
mkvirtualenv sf -p python3(sf for salesfeed)workon sf
To exit the env run deactivate.
When in your virtual environment:
> pip install -r requirements.txt toxAdd the interpreter in Preferences->Project->Project Interpreter:
- Hit the setup icon->add and select existing env
- Hit the "..." and select the python executable in the env you created (probably ~/.env/sf/bin/python) and add the interpreter
You will need to mark the src directory as a sources folder. (right click)
AWS Lambda requires a flat folder with the application as well as its dependencies. SAM will use CodeUri property to know where to look up for both application and dependencies:
...
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello_world/
...Create this file and build the proper dependencies.
> make buildSee Serverless Application Model (SAM) HOWTO Guide for more details in how to get started.
The build command in the Makefile uses sam build to build the app. The following happens:
- Moves the python module defined in
template.yamlinto a.aws-sam/builddirectory, ie the event-selector-service - Spins up an aws compatible docker container with a volume mapped to the
buildfolder - Installs dependencies into the fresh container using PyPI. Native dependencies get built here.
We can locally run the lambda in a docker container to test. Build the application first.
> make runWe use Pytest and pytest-mock for testing our code and automate testing with different python versions using Tox.
> toxIf you add a new dependency, add the --recreate flag.
Firstly, we need a S3 bucket where we can upload our Lambda functions packaged as ZIP before we deploy anything - If you don't have a S3 bucket to store code artifacts then this is a good time to create one:
> aws s3 mb s3://BUCKET_NAMEThe lambda is packaged by pulling all source code into a new directory under .aws-sam/build and zipped up.
The zip file is then uploaded an the S3 bucket.
We must first create the lambda function with the zip file and set up all the configuration. Once the lambda exists, we can deploy a new
version by using the aws lambda update-function-code command. This will not change the configuration but replaces the
function code with a new zip file.
Take a look at the AWS lambda docs for more info.
Now would be a good time to take a look at the Makefile to see the individual commands run. The two env vars AWS_USER
and AWS_SALESFEED_S3BUCKET deal with how the resources will be named in AWS.
Move into the function directory. We can now package the function and all its dependencies into a zip file:
> make zipThe path of the zip file created is .aws-sam/package/FUNCTION_NAME.zip. If you want to look at the source code that
gets included in the zip file, take a look inside .aws-sam/build.
Now upload the zip file to S3:
> aws s3 cp .aws-sam/package/FUNCTION_NAME.zip s3://BUCKET_NAMELets create the aws lambda function. You'll need the arn of a valid IAM role
for your new function. Take a look at the
create-function documentation if you
want to configure the function further, such as adding environment variables or placing the lambda inside a vpc.
Alternatively to doing this in your cli, you can create the function inside the aws lambda console.
aws lambda create-function --function-name FUNCTION_NAME --role IAM_ROLE_ARN --handler service.app.lambda_handler --runtime python3.6 --code S3Bucket=S3_BUCKET_NAME,S3Key=FUNCTION_NAME.zipThe function has been created. You can invoke it from your cli:
aws lambda invoke --function-name FUNCTION_NAME --payload '{"key1":"value1", "key2":"value2"}' outfile.txtIf you make further changes to your source code, you can upload an updated zip from S3 using update-function-code so you don't need to delete and recreate your function. Use:
> aws lambda update-function-code --s3-bucket S3_BUCKET_NAME --s3-key FUNCTION_NAME.zip