Have you ever considered AWS Elastic Beanstalk for Django?

June 8, 2019

AWS
ElasticBeanstalk
Python
Django

Introduction

AWS Elastic Beanstalk is easy-to-use Amazon service for deploying and scaling web applications in couple languages including Python.

The best solution if you are short on time with setting the whole server setup and on DevOps resources. AWS EB takes care of everything for you: HTTP server, language interpreter, operating system, host, load balancer and everything what you really need if it comes to a modern web app.

This post will contain a simple guide for Django setup using AWS Elastic Beanstalk with database configuration and all stuff which you will need to kick off with a project!

Source code can be found on my github.

Setup:

  • AWS and Elastic Beanstalk configuration and RDS DB
  • Django project creation
  • Django migrations & collect static & Django admin

Instructions

  1. Install aws cli
brew install awsebcli
  1. Configure access to AWS account
aws configure
  1. Create a django project
django-admin startproject django_eb
  1. Initialize elastic beanstalk app. It will create .elasticbeanstal directory with config.yml
eb init
  1. Create an elastic beanstalk environment. This will be also available to see in AWS console
eb create <environment_name>
Note: 
- Unfortunately looks like only US regions only are supported for Elastic Beanstalk... At least for me, only US regions worked... For other regions, I got an error message that account is blocked and to contact support.
  1. Create a .ebextensions directory with will contain all eb configs and django.config file inside
    .
    ├── .ebextensions
    │   └── django.config
    ├── .elasticbeanstalk
    │   └── config.yml
    ├── django_eb
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    ├── manage.py
    ├── requirements.txt
  1. Update django.config file with:
    • Migration command: Will do a migration on deploy
    • Create admin command: To init Django admin without a login on the machine
    • Collect static command: Generate static files for Django on the machine
    container_commands:
      01_migrate:
        command: "source /opt/python/run/venv/bin/activate && python manage.py migrate --noinput"
        leader_only: true
      02_create_admin:
        command: "source /opt/python/run/venv/bin/activate && python manage.py createadmin"
      03_collectstatic:
        command: "source /opt/python/run/venv/bin/activate && python manage.py collectstatic --noinput"
        leader_only: true

    option_settings:
      aws:elasticbeanstalk:container:python:
          WSGIPath: django_eb/wsgi.py
      aws:elasticbeanstalk:application:environment:
        DJANGO_SETTINGS_MODULE: django_eb.settings
      aws:elasticbeanstalk:container:python:staticfiles:
        "/static/": "www/static/"
  1. Create a Django command to create admin from code using custom command.
    from django.core.management.base import BaseCommand
    from django.contrib.auth.models import User

    from django_eb import settings


    class Command(BaseCommand):

        def handle(self, *args, **options):
            if not User.objects.filter(username=settings.DEFAULT_ADMIN_NAME).exists():
                User.objects.create_superuser(
                    settings.DEFAULT_ADMIN_NAME, 
                    settings.DEFAULT_ADMIN_EMAIL, 
                    settings.DEFAULT_ADMIN_PASSWORD,
                )
Make sure that command is placed in right directory: `<app_name>/management/commands/createadmin.py` file. 
    .
    ├── .ebextensions
    │   └── django.config
    ├── .elasticbeanstalk
    │   └── config.yml
    ├── django_eb
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   ├── wsgi.py
    │   ├── management
    │   ├── __init__.py
    │   └── commands
    │       ├── __init__.py
    │       └── createadmin.py
    ├── manage.py
    ├── requirements.txt
  1. Add config variables to the settings.py
    DEFAULT_ADMIN_PASSWORD = os.environ.get('DEFAULT_ADMIN_PASSWORD')
    DEFAULT_ADMIN_NAME = os.environ.get('DEFAULT_ADMIN_NAME')
    DEFAULT_ADMIN_EMAIL = os.environ.get('DEFAULT_ADMIN_EMAIL')

    STATIC_ROOT = 'www/static/'
  1. Setting up a database: Go to your AWS account -> Elastic Beanstalk -> Configuration

rds database

  1. AWS eb automatically will add environment variables to the instance so the only thing what should be done is to update DATABASE in settings.py
    if 'RDS_DB_NAME' in os.environ:
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.postgresql',
                'NAME': os.environ['RDS_DB_NAME'],
                'USER': os.environ['RDS_USERNAME'],
                'PASSWORD': os.environ['RDS_PASSWORD'],
                'HOST': os.environ['RDS_HOSTNAME'],
                'PORT': os.environ['RDS_PORT'],
            }
        }
  1. By default, Amazon instance runs on Amazon Linux (distribution evolved from RedHat and CentOS). To run postgresql we need to install yum packages otherwise error Error: pg_config executable not found will be raised.

    Add packages.config file to the .ebextensions:

    packages:
      yum:
        git: []
        postgresql93-devel: []
  1. Now, when the whole setup is completed we are ready to deploy our application
    eb deploy

success

Troubleshooting

  • RDS database configuration in AWS panel will be only possible when Elastic Beanstalk instance will be working and the app health will be ok
  • If you are getting an error: account is currently blocked and not recognized as a valid account try to change the region to US
  • Remember to add psycopg2 in your requirements.txt to get PostgreSQL working
  • RDS database is not a scalable as the Elastic Beanstalk, consider to use Aurora service
  • Add your generated host into ALLOWED_HOSTS settings, otherwise you will get invalid host error

Summary

I'm mostly building web apps on top of Google Could Platform with special care of App Engine. I decided to give a try to AWS for my next project and I can already see great potential.

This configuration with reading documentation took me about 1h. After this 1h I've got working and deployed Django application and I was ready to start implementing a domain features.

Awesome thing in AWS is that you can use all their services using IAM permissions in each service. Google services aren't so great... so if you would like to use Google Memory Store with App Engine Standard you can already stop, check this article to get more info.

If you would like to get more information about the AWS Elastic Beanstalk, please check their documentation. They are also having a great tutorial how to set up Django on EBS but with a little less information.

Built with love to Python logo React logo Gatsby logo · Piotr Rogulski