Published Dec 25, 2020
In this post we will learn how to create Containerize Flask app w/ AWS Lambda. Skip to code
This is example on how to create flask app container to use w/ AWS Lambda.
This example assumes that you have initialized your dir like below.
.
├── Dockerfile
├── api
│ └── __init__.py
├── .serverless-wsgi
├── entry.sh
├── requirements.txt
└── wsgi.py
In this section we’ll go thru each files listed above.
Docker file for building container
# Define global args
ARG FUNCTION_DIR="/home/lambda/"
ARG RUNTIME_VERSION="3.9"
ARG DISTRO_VERSION="3.12"
ARG SERVERLESS_TAG="1.7.6"
# Stage 1 - bundle base image + runtime
# Grab a fresh copy of the image and install GCC
FROM python:${RUNTIME_VERSION}-alpine${DISTRO_VERSION} AS python-alpine
# Install GCC (Alpine uses musl but we compile and link dependencies with GCC)
RUN apk add --no-cache \
libstdc++
# Stage 2 - build function and dependencies
FROM python-alpine AS build-image
# Install aws-lambda-cpp build dependencies
RUN apk add --no-cache \
build-base \
libtool \
autoconf \
automake \
libexecinfo-dev \
make \
cmake \
libcurl \
git
# Include global args in this stage of the build
ARG FUNCTION_DIR
ARG RUNTIME_VERSION
ARG SERVERLESS_TAG
# Create function directory
RUN mkdir -p ${FUNCTION_DIR}
# Install Lambda Runtime Interface Client for Python
RUN python${RUNTIME_VERSION} -m pip install awslambdaric --target ${FUNCTION_DIR}
# Copy required files
COPY * ${FUNCTION_DIR}
COPY api ${FUNCTION_DIR}/api
# Install the function's dependencies
RUN python${RUNTIME_VERSION} -m pip install -r ${FUNCTION_DIR}/requirements.txt --target ${FUNCTION_DIR}
# Download serverless-wsgi and copy wsgi_handler.py & serverless_wsgi.py
RUN git config --global advice.detachedHead false
RUN git clone https://github.com/logandk/serverless-wsgi --branch ${SERVERLESS_TAG} ${FUNCTION_DIR}serverless-wsgi
RUN cp ${FUNCTION_DIR}serverless-wsgi/wsgi_handler.py ${FUNCTION_DIR}wsgi_handler.py && cp ${FUNCTION_DIR}serverless-wsgi/serverless_wsgi.py ${FUNCTION_DIR}serverless_wsgi.py
# Stage 3 - final runtime image
# Grab a fresh copy of the Python image
FROM python-alpine
# Include global arg in this stage of the build
ARG FUNCTION_DIR
# Set working directory to function root directory
WORKDIR ${FUNCTION_DIR}
# Copy in the built dependencies
COPY --from=build-image ${FUNCTION_DIR} ${FUNCTION_DIR}
# (Optional) Add Lambda Runtime Interface Emulator and use a script in the ENTRYPOINT for simpler local runs
ADD https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie /usr/bin/aws-lambda-rie
RUN chmod 755 /usr/bin/aws-lambda-rie
COPY entry.sh /
RUN chmod +x entry.sh
ENTRYPOINT [ "./entry.sh" ]
CMD [ "wsgi_handler.handler" ]
This file is initializing basic flask app with one route to /
which return hello world.
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "Hello, World!"
This is required json config file for serverless-wsgi framework. Here I have value for app
set to wsgi.app
, which represents the app
variable inside wsgi.py file.
{
"app": "wsgi.app"
}
“It executes the Lambda Runtime Interface Client for Python. If the execution is local, the Runtime Interface Client is wrapped by the Lambda Runtime Interface Emulator.”
#!/bin/sh
if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
exec /usr/bin/aws-lambda-rie /usr/local/bin/python -m awslambdaric $1
else
exec /usr/local/bin/python -m awslambdaric $1
fi
Requirements file for your python app.
werkzeug==1.0.1
flask==1.1.2
serverless-wsgi==1.7.6
Friendly wrapper around flask app for serverless-wsgi.
# -*- coding: utf-8 -*-
"""
wsgi.py: Wsgi init
"""
import api
app = api.app
Once image is built, push to ECR and create new lambda with that image. Create new API Gw and integrate with newly containerized lambda. And that’s all :)
>>> curl -X GET "https://pnjj776bx0.execute-api.us-east-1.amazonaws.com/dev"
>>> Hello, World!