1. 程式人生 > >AWS Lambda Functions Made Easy

AWS Lambda Functions Made Easy

AWS Lambda Functions Made Easy

A Step by Step Guide with Code Snippets for Packing Your Python 2.7 Function for AWS Lambda

Background

I hope the code in this blog post will save you a lot of time developing serverless functions for AWS Lambda.

Creating simple functions using the Lambda web console is easy. As I found in a recent

hackathon project, introducing dependencies and environment variables is not straightforward and may be error prone. I created the snippets here to cut down my development cycle and avoid interacting with the web interface for every small code tweak. I’m sharing the code here in the hopes that it will be useful to you, as well!

This blog post walks you through creating and packaging an AWS Lambda function for Python 2.7 using the boto3 client, and includes extra sections on invoking Lambda functions, and repackaging and re-uploading while the code is still in development.

Pre-Requisites

  • pip, a tool for installing Python packages.
  • Virtual environments, a tool to create isolated Python environments
  • Boto3. This tutorial assumes that you are familiar with using AWS’s boto3 Python client, and that you have followed AWS's instructions to configure your AWS credentials.

Write A Function

Lambda functions need an entry point handler that accepts the arguments event and context. A basic Lambda function will treat event as a key-value store of arguments to the function, and may ignore context. As an example, in Python:

# file: main.py
def handler(event, context):
plotly_url = event['plotly_url']

The file and function names matter! Both values are used below in Create a Lambda Function. This example assumes a file main.py contains a function handler.

If you’d like, you can use my example Lambda function that I created to help me debug machine learning models running remotely. My function takes a Plotly url, downloads the image, and sends it to me over Slack (created because Plotly plots don’t load image previews in Slack). Clone/fork the repo, or just download main.py and requirements-lambda.txt.

Install Dependencies

To keep function dependencies (in my example plotly and slackclient) separate from development dependencies (like boto3) use separate Python virtual environments. Put all Python dependencies in requirements-lambda.txt. This bash code snippet creates a fresh Python virtual environment and installs dependencies from requirements-lambda.txt:

export VIRTUALENV='venv_lambda'
rm -fr $VIRTUALENV
# Setup fresh virtualenv and install requirements
virtualenv $VIRTUALENV
source $VIRTUALENV/bin/activate
pip install -r requirements-lambda.txt
deactivate

Create .zip File

Zip files are required for Lambda functions that include Python package dependencies, whether the code is uploaded through the web, the Python client, or s3.

This bash snippet creates lambda.zip from main.py and the dependencies in the previous step:

export VIRTUALENV='venv_lambda'
export ZIP_FILE='lambda.zip'
export PYTHON_VERSION='python2.7'
# Zip dependencies from virtualenv, and main.py
cd $VIRTUALENV/lib/$PYTHON_VERSION/site-packages/
zip -r9 ../../../../$ZIP_FILE *
cd ../../../../
zip -g $ZIP_FILE main.py

Create a Basic IAM Role

This Python snippet uses boto3 to create an IAM role named LambdaBasicExecution with basic lambda execution permissions.

import json, boto3
# From https://alestic.com/2014/11/aws-lambda-cli/
role_policy_document = {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
iam_client = boto3.client('iam')
iam_client.create_role(
RoleName='LambdaBasicExecution',
AssumeRolePolicyDocument=json.dumps(role_policy_document),
)

Create a Lambda Function

By now lambda.zip contains a handler and dependencies, and your AWS account has an IAM role with lambda privileges (see previous section).

Environment Variables: If your function depends on environment variables (the example code I provided above requires a few), set them below in the environment_variables dict. These will be easy to edit later in the console.

The following Python snippet will use all of the resources above to create a new AWS Lambda function called myLambdaFunction:

import boto3
iam_client = boto3.client('iam')
lambda_client = boto3.client('lambda')
env_variables = dict() # Environment Variables
with open('lambda.zip', 'rb') as f:
zipped_code = f.read()
role = iam_client.get_role(RoleName='LambdaBasicExecution')
lambda_client.create_function(
FunctionName='myLambdaFunction',
Runtime='python2.7',
Role=role['Role']['Arn'],
Handler='main.handler',
Code=dict(ZipFile=zipped_code),
Timeout=300, # Maximum allowable timeout
Environment=dict(Variables=env_variables),
)

View, edit and test functions on the AWS console.

Invoke Your Function

First, define your test_event (a dictionary that will be passed as the first argument to the function). Then, use the Python snippet below to invoke myLambdaFunction:

import boto3, json
lambda_client = boto3.client('lambda')
lambda_client.invoke(
FunctionName='myLambdaFunction',
InvocationType='Event',
Payload=json.dumps(test_event),
)

(Optional) Re-Upload Code

Inevitably, your code (or my code) won’t work the first time, and you’ll need to tweak it.

Re-run Install Dependencies if any dependencies changed, and re-run Create .zip File to repackage all code.

Use the following Python snippet to update the code for an existing lambda function:

import boto3
lambda_client = boto3.client('lambda')
with open('lambda.zip', 'rb') as f:
zipped_code = f.read()
lambda_client.update_function_code(
FunctionName='myLambdaFunction',
ZipFile=zipped_code,
)