Deploy SAM python lambda with Github actions

by Afanasy Barbarov

Continuous integration ideas for Terraform and AWS SAM

Amazon has an excellent framework https://aws.amazon.com/serverless/sam/ to build serverless applications. But there was a problem: one day I spend some time with Terraform to provision infrastructure on AWS. SAM itself allows publishing the lambda from the command line, but having a lot of lambdas and deploying each of it from localhost is not the best idea. Thus I needed to configure builds from a centralized place from one side, and from another - to develop lambda locally using the SAM framework, because of the ability of debugging locally.

I researched the Internet, found a great article - https://mechanicalrock.github.io/2020/01/06/github-actions-for-sam.html. Maybe I'll use it one day:) But I ended up with a very simple build pipeline. The idea is to use SAM CLI to build artifacts and put them to the S3 bucket.

  1. Create a new python app with sam init. Сhose python 3.8 (the script below relates on python 3.8).
  2. Configure github actions like so:
name: CI
on:
  push:
    branches:
    - master
  pull_request:
    branches:
      - master

jobs:
  checkout:
    name: Checkout
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: SAM Build
      run: sam build -u
      env:
        SAM_CLI_TELEMETRY: 0

    - name: Zip lambda output
      run: zip -r ${{ github.sha }}.zip ./*
      working-directory: .aws-sam/build/HelloWorldFunction

    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: eu-west-1

    - name: Copy to S3
      run: aws s3 cp ${{ github.sha }}.zip
       s3://YOUR-S3-BUCKET-NAME/${{ github.sha }}.zip
      working-directory: .aws-sam/build/HelloWorldFunction

The script above will compile lambda inside a docker container and copy the produced output to an S3 bucket. That assumes, that the bucket is already created. The script will run each time you push a commit in an open PR or on push to master branch. Configuring the lambda is out the scope, but you can refer to this Terraform script to get the idea:

provider "aws" {
  profile = "defaul"
}

resource "aws_s3_bucket" "s3_lambda_src" {
  bucket = "YOUR-S3-BUCKET-NAME"
}

resource "aws_lambda_function" "lambda_function" {

  s3_bucket = "YOUR-S3-BUCKET-NAME"
  s3_key    = "SHA-OF-THE-COMMIT.zip"

  function_name = "lambda-function"
  handler       = "app.lambda_handler"
  runtime       = "python3.8"
  timeout       = 180
  role          = aws_iam_role.iam_role_lambda.arn
}

resource "aws_iam_role" "iam_role_lambda" {
  name = "iam_role_lambda"

  assume_role_policy = <<EOF
 {
   "Version": "2012-10-17",
   "Statement": [
     {
       "Action": "sts:AssumeRole",
       "Principal": {
         "Service": "lambda.amazonaws.com"
       },
       "Effect": "Allow",
       "Sid": ""
     }
   ]
 }
 EOF

}

That's all, folks!

Written by Afanasy Barbarov — Tech Lead with 15+ years shipping production systems in Rust, Go, and TypeScript. Facing a similar challenge? Reach out on LinkedIn. Support my work.

More articles

Previous post

Create infrastructure with Amazon CDK.

Read more

Next post

AWS lambda for chemical data extraction.

Read more