rogulski.it

My name is Piotr, a passionate pythonista and this is my blog!

    Have you ever considered AWS Elastic Beanstalk for Django?

    Posted at — Jun 9, 2019

    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:

    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

    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.