Home

Awesome

License security: bandit

<!-- PROJECT LOGO --> <br /> <div align="center"> <img width="256" height="256" src="https://user-images.githubusercontent.com/110536677/230987784-c8e55f0e-4434-43b4-8b41-08a8ea8cec08.png" alt=""> <h3 align="center">Execute Python Django within AWS Lambda</h3> <p align="center"> This repository contains a Python Django application designed to run seamlessly inside an AWS Lambda environment, leveraging the AWS Lambda Adapter extension. The application is built to efficiently handle serverless workloads and connect to a PostgreSQL database, providing a scalable, cost-effective, and high-performance solution for modern web applications. By using the AWS Lambda Adapter, the Django app can utilize the event-driven nature of Lambda while maintaining its traditional web application structure. </p> <br /> <a href="https://github.com/aws-hebrew-book/reminders/issues">Report Bug</a> · <a href="https://github.com/aws-hebrew-book/reminders/issues">Request Feature</a> </p> </div> <!-- TABLE OF CONTENTS --> <details> <summary>Table of Contents</summary> <ol> <li> <a href="#high-level-architecture">High level architecture</a> </li> <li> <a href="#getting-started">Getting Started</a> <ul> <li><a href="#prerequisites">Prerequisites</a></li> <li><a href="#installation">Installation</a></li> <li><a href="#database-migration">Database migration</a></li> <li><a href="#running-the-app-locally">Running the app locally</a></li> </ul> </li> <li><a href="#behind-the-scenes">Behind the scenes</a></li> <li><a href="#contributing">Contributing</a></li> <li><a href="#license">License</a></li> <li><a href="#contact">Contact</a></li> </ol> </details>

High level architecture

<div align="center"> <img src="https://user-images.githubusercontent.com/110536677/230990815-91c355a5-9f72-4039-9b3f-ba1090b4839d.png" alt="Architecture diagram"> </div>

Getting started

Prerequisites

Installation

Database migration

Like any DJango application there are some minimal migration steps you need to run - 1. DB migration and 2. Admin user creation. In order to run the relevant commands you need to ssh into the bastion first.

git clone https://github.com/aws-hebrew-book/serverless-django.git
curl https://pyenv.run | bash
echo 'export PYENV_ROOT="/$HOME/.pyenv"' >> ~/.bashrc
echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(pyenv init -)"' >> ~/.bashrc
source ~/.bashrc
pyenv install 3.9
pyenv global 3.9
curl -sSL https://install.python-poetry.org | python3 -
cd serverless-django
echo 'export PATH="/$HOME/.local/bin:$PATH"' >> ~/.bashrc
poetry install --only main
poetry self add 'poethepoet[poetry_plugin]'
poetry shell

Running the app locally

Behind the scenes

Lambda Web Adapter

Django for Python operates differently from AWS Lambda, as Django functions as a traditional web server that waits for external connections, while Lambda is event-based. To bridge the gap between these two operation types, the Lambda Web Adapter extension is required. This extension serves as a mediator, translating the http request coming from API Gateway or Lambda URL into a web request that is done against the internal guinicorn process. image

LWA -> Gunicorn -> Django

Gunicorn, short for Green Unicorn, is a Python Web Server Gateway Interface (WSGI) HTTP server that serves Python web applications by managing the communication between the web server and the application.

Django does not include a production-ready web server by default. The built-in development server provided by Django is intended for local development and testing, but it is not designed to handle the performance requirements and security considerations of production environments. That’s where Gunicorn comes in. By integrating Gunicorn with a Django application, developers can deploy their web applications in production.

AWS Lambda does not provide a direct web application interface; instead, services like API Gateway and Lambda URL convert HTTP requests into Lambda event payloads. Gunicorn, however, is not designed to communicate in this format. This is where LWA proves valuable, as it acts as a bridge, translating Lambda events received from API Gateway and Lambda URL into HTTP requests compatible with Gunicorn.

Due to AWS Lambda’s design, which allows processing of only one request at a time, it is necessary to configure Gunicorn with a single listener when setting it up for use with Lambda.

CMD ["gunicorn", "polls.wsgi:application", "-w=1", "-b=0.0.0.0:8000"]

Consuming AWS Services

When migrating an application to the cloud, it presents an excellent opportunity to leverage other cloud services. In this example, we utilize AWS Secret Manager to store the database password and the Django secret key. To retrieve the secret values and integrate them into the Django app, we employ Lambda Power Tools , simplifying the process of securely accessing these sensitive pieces of information.

One of the challenges when using traditional web applications that rely on SQL databases is the requirement to be within a VPC. By default, a Lambda function within a private subnet cannot access the internet and, therefore, cannot access AWS services. There are two ways to address this issue:

  1. Utilize an Internet Gateway and NAT to enable compute resources in the private subnet to access the internet.
  2. Use VPC endpoints, as Secret Manager supports VPC endpoints. The current solution opts for the first option due to its simplicity; however, it is less secure because it exposes the Lambda function to the internet rather than limiting access to specific AWS services.

Serving Static Files

Django is an all-inclusive framework that not only handles backend processes but also supports frontend server-side rendering. This means that web pages can be rendered using the framework, even when developing Single Page Applications (SPAs) and using Django as a REST backend. One issue that requires attention is static file handling, such as serving JS or CSS files. <img width="950" alt="image" src="https://user-images.githubusercontent.com/110536677/231078369-42bd25e9-2c1b-450c-9a55-a51624a8b354.png">

AWS recommends managing static files using S3 and CloudFront. One approach is to use django-storages, define S3 as a storage backend, and then set the S3 as the source for the CloudFront distribution. Alternatively, you can serve static files directly through the web server (using Gunicorn and the AWS Lambda Adapter), which is simpler and, in cases where only the admin panel needs support, is often preferable. To serve static files directly through the web server, simply use Django WhiteNoise and add it as middleware.

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request
<!-- LICENSE -->

License

Distributed under the Apache License Version 2.0 License. See LICENSE for more information.

<!-- CONTACT -->

Contact

Efi Merdler-Kravitz - @TServerless

<p align="right">(<a href="#readme-top">back to top</a>)</p>