Blog

Python Lambda Packager

16 Nov, 2018
Xebia Background Header Wave

When creating Lambda functions and deploy the functions using CloudFormation, the python code can be inline or packaged in a zip file. When no third party packages are required or tests are created, inline works fine. For very simple use cases this is ok. If you want to be able to test the python function locally, it should be a separate file (and not part of the CloudFormation template). There are many ways to package Lambda functions, and this is one of the easiest ways. It’s just a single command, and only requires Docker on your machine.

CloudFormation

Consider the following CloudFormation template. You will find out the Version parameter is pretty important. If you update the code, but don’t change anything in the template, the function will not be replaced (the deployment even fails). In this example I just use an auto increment bash script to generate a new zip file and use this prefix when uploading. CloudFormation now thinks the function is new, will deploy the template and replace the function.

Parameters:
  Version:
    content: Lambdas are written in a version directory, which is auto incremented on upload
    Type: String
Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Handler: lambda_function.lambda_handler
      Timeout: 30
      Role: !GetAtt 'LambdaBasicExecutionRole.Arn'
      Runtime: python3.6
      Code:
        S3Bucket: "mybucketname"
        S3Key: !Sub "${Version}/<lambda_name>.zip"
  LambdaBasicExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: lambda.amazonaws.com
          Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

This is the file structure you should consider using. The .gitignore is important to prevent saving the build artifacts ending up in your git repo (it’s a zip file and can grow quite big). You can also add custom dependencies in this folder.

└── src
    └── <lambda_name>
        ├── lambda_function.py
        ├── readme.md
        └── requirements.txt
    └── ...
└── build
    └── <lambda_name>.zip
    └── ...
└── .gitignore
└── version.txt
└── template.yml

Now run the command to package all functions, including the version trick, and upload them to an S3 bucket.

docker run -v $(pwd)/src:/src \
    -v $(pwd)/build:/build \
    binxio/python-lambda-packager

version=`cat version.txt`
version=$[$version+1]
echo $version > version.txt

aws s3 cp --recursive \
  --acl public-read \
  ./build s3://mybucketname/stack/${version}

Now you can deploy the CloudFormation stack using the uploaded Lambdas and example template, using the following command.

version=`cat version.txt`
aws cloudformation deploy \
    --stack-name <stack name> \
    --template-file template.yml \
    --capabilities CAPABILITY_IAM \
    --parameter-overrides version=${version}

Conclusion

It has become really easy to package your Lambda functions including their dependencies.

Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts