In this blog post, we will talk about getting your Django project deployed to Amazon Web Services (AWS) platform. There are different ways you can do that with AWS: one is deployment to EC2 instance running Linux (you just connect to it over SSH and work with Linux server directly), and the other one is deployment to Elastic Beanstalk. The first scenario is close to simple project setup on a local Linux machine with some extra steps involved – for that you can refer to my previous posts which cover most of the steps involved. In this post, we will focus on Elastic Beanstalk deployment scenario, going through all the steps involved in this process when it is performed from Ubuntu.
Before we dive into the deployment process, it is worth saying a few words about AWS Elastic Beanstalk. AWS Elastic Beanstalk is an abstraction layer which allows you to deploy applications to AWS without manually creating individual infrastructure components, such as EC2 severs, ELBs, keypairs or security groups (Beanstalk will create those for you) and later manage a single application entity instead of taking care of grouping and managing a bunch of disparate resources. Though you can create Elastic Beanstalk apps both from AWS web console and command line interface, Elastic Beanstalk really shines when you leverage the command line interface, which makes your deployment process really fast and offers possibilities for scripting and automation. At the same time, use of Elastic Beanstalk does not deprive you from fine-grained control as all underlying infrastructure components are still visible and can be managed through the AWS console. Beanstalk acts as a container for environment(s) (think of your conventional DEV, TEST, PROD trinity 😊) and those environments define specific infrastructure components used by the application.
Now that we are done with the preliminaries, let’s go through the four-step process of deploying a Django project to AWS Elastic Beanstalk (we will cover application of updates to your project as step 5). I will be going through all these steps using an Ubuntu 18.04.2 LTS machine.
Step 1. Setting up a Python virtual environment and installing Django.
We, first, need to get Python 3.6 and virtualenv components installed on our machine using the sudo apt install -y Python3.6 virtualenv command as shown below:
Installing Python 3.6 and virtualenv
With these components in place, lets create a virtual environment named eb-virt specifying the use of Python 3.6 by means of the virtualenv command:
Creating virtual environment using virtualenv command
In the command above, we specify “eb-virt” as the name of our virtual environment, which will result in the creation of “eb-virt” directory in your user’s home directory.
Once we environment created, we need to activate it with the source ~/eb-virt/bin/activate command as shown below:
Activating virtual environment
Once we are in the context of an activated environment, which is indicated by the changed command line prompt prefix that now includes a virtual environment name – (eb-virt), we need to install Django. The latest version of Django is supported by Elastic Beanstalk is 2.1.1, so we will install this version:
Installing Django within virtual environment
Once the installation is completed, we can verify that Django is installed using the pip freeze command:
Running pip freeze command to confirm that Django was installed correctly
When the pip freeze command is executed, it lists all the packages installed within a virtual environment, and we will use it later to configure our Django project for use with Elastic Beanstalk. Now let’s move on to the next step.
Step 2. Creating sample Django project.
Inside of our virtual environment eb-virt we now need to use the django-admin startproject command to create our Django project named “ebdjango”:
Creating Django project
Once executed, this command creates a Django project folder with a django app inside of it:
Django project folder
For convenience, I would recommend you rename the top level project folder from “ebdjango” to “ebdjango-project” as shown below:
Renaming Django project folder
This will help you to distinguish between the top-level project level folder and the Django app sub-folder inside of it.
Let´s now test our Django application locally to make sure that it works. For that, we need to make sure that our virtual environment is activated and then switch to Django project directory using the cd ebdjango-project command, apply initial migrations with the python manage.py migrate command, and, next, run Django server using the python manage.py runserver command:
Applying migrations and starting Django server locally
Once the server is started, we can access the Django app through a web browser, using its default address to confirm that it works. If all worked well, you should see the default Django app page with the rocket icon as shown below:
Default Django app page
After accessing the Django site, just have a look at the console output making sure no errors are logged and if everything is OK there, stop server using the Ctrl + C hot keyboard shortcut in the console window and move on to the next step.
Step 3. Configuring Django project for Elastic Beanstalk.
We now need to configure/prepare our Django app to be deployed to Elastic Beanstalk, which involves a number of adjustments to our application. Let’s get back to our virtual environment (activate it again if it was deactivated) and perform all the required steps.
We first need to use the pip freeze command to list packages which we have installed in our virtual environment and pipe output of this command into requirements.txt file as shown below:
Creating requirements.txt file from output of pip freeze command
Once the requirements.txt file was created, edit it with nano editor and remove everything except for Django==2.1.1 – if your requirements.txt file will have unnecessary/not supported packages your app won’t be running properly on Elastic Beanstalk showing you “Index of /” text instead of default Django page. Here is how your requirements.txt should look like:
Content of requirements.txt file
Next, we need to create a hidden directory .ebextensions within our project directory using the mkdir .ebextensions command and create a django.config file in this directory:
Creating .ebextensions directory and django.config file
Inside of django.config file, the following lines should be added:
Contents of django.config file
Inside of django.config WSGIPath value corresponds to your Django app folder inside of your Django project folder – this is where the wsgi.py script is located. Elastic Beanstalk uses this WSGI script to start the deployed app.
We now finished the configuration of Django project for Beanstalk and can deactivate our virtual environment and move on to the deployment of our app onto AWS Elastic Beanstalk.
Step 4. Deploying configured Django project to AWS using EB CLI.
We will be doing Django app deployment using EB CLI deployment mechanism. Before we can do that, we need to install the awsebcli package using the sudo pip3 install awsebcli command as shown below (in case pip3 is not installed on your machine you can install it using sudo apt install -y python3-pip command).
Installing awsebcli
With EB CLI installed, we can initialize our EB CLI repository (create Elastic Beanstalk app) using the eb init -p python-3.6 django-test-app command as shown below:
Initializing EB CLI repository
The above-mentioned command will prompt you for aws-access-id and aws-secret-key – to generate this ID and secret key, you will need to log on to AWS console (https://console.aws.amazon.com) and once there, click on your name in the top right corner of the page and select “My Security Credentials” as shown below:
AWS Console – Accessing “My Security Credentials”
This will take you to “Your Security Credentials” page of the Identity and Access Management (IAM) dashboard, where you can generate aws-access-id and aws-secret-key clicking on the “Create New Access Key” button:
AWS Console – “Your Security Credentials” page of Identity and Access Management (IAM)
Note that you cannot view or retrieve Access Keys for already created Access Key IDs – you can only view and save Access Key at Access ID creation stage – for that you need to click on the “Show Access Key” link in Create Access Key Dialog and save Access Key in a safe place:
AWS Console – Create Access Key – Show Access Key
Once we initialized our EB CLI repository using the eb init -p python-3.6 django-test-app command, we can create an environment and deploy our application using the eb create command as shown below:
Creating Django environment using eb create command
We can check on the environment creation status using the eb status command as shown below:
Checking environment status with eb status command
It usually takes about 5 minutes to spin up a new environment. We don’t expect to get Green health status at this stage, instead, we just need to capture CNAME value from eb status command output:
Getting environment CNAME from eb status output
Once we have CNAME value, we need to put it into our application settings.py file. For that, open the file for edit using the nano settings.py command (be sure to change directory to app directory inside of project directory) as depicted below:
Opening settings.py file for modification
In the settings.py file, locate ALLOWED_HOSTS = [] line and paste your CNAME value between square brackets and single quotes so that it looks approximately as follows:
Adding CNAME value into ALLOWED_HOSTS
Pres Ctrl + X to save changes and exit nano editor. With this change in place, we are now ready to run the eb deploy command once again. If all previous steps were performed correctly, the eb status command should return you Green health status and you should be able to open your Django app using the eb open command:
Confirming environment status using eb status and eb open commands
As you can see, we now have our Django app deployed and running on AWS Elastic Beanstalk.
You may also run into a situation when you are getting Red health status and see “Index of /” text in the browser as shown below:
Non-working Django app
In this case, make sure your requirements.txt file does not contain unnecessary entries (check step 3). Essentially, that concludes the Django app deployment process and the only thing we still need to look at is how we can apply changes to our Django app.
Step 5. Applying Django app changes/updates.
Now, let’s add Django admin user for our app and deploy these changes to Elastic Beanstalk to illustrate the app update process. We already run initial migration during initial deployment and the Django admin app is already available to us via /admin URL path, but without graphical elements.
As Django admin app uses some images, we need to configure a static files storage via STATIC_ROOT setting in settings.py file. To do that, we need to edit settings.py file and a line STATIC_ROOT = ‘static’ to the very end of it:
Adding STATIC _ROOT setting in settings.py file
Once STATIC_ROOT has been defined, we need to run the python manage.py collectstatic command from the activated virtual environment, making sure we run that on the project folder level as shown below:
Running collectstatic command
Make sure that the collectstatic command produces correct output with no errors. With that in place, let’s add admin user using the python manage.py createsuperuser command, if necessary, activating the virtual environment beforehand, and applying changes to our AWS Elastic Beanstalk app with the eb deploy command.
Creating admin user and deploying app changes
Once that has been done, we just need to run eb deploy again and, if all goes well, you should be able to log into Django admin UI (see sample screenshot below).
Django admin UI
If your Django administration app shows you only the text without graphics and images, make sure that STATIC_ROOT is defined and run the python manage.py collectstatic command.
From this moment on, you can just go through the iterative cycle of doing local changes and applying them using the eb deploy command.
There are few extra things which I want to mention before we wrap up here.
Firstly, we need to take a glance at how things look from the AWS console’s side. On the screenshot below, we can see our Django application (created with eb init command) and, within it, we have Django environments (you create those with eb create command) – just for illustration purposes I’ve added a “production” environment there:
AWS Console Elastic Beanstalk application and environments
You can drill down into each environment to manage associated settings and underlying components or view logs.
Secondly, for development purposes, it would be preferable to minimize costs and, for that, you can easily remove the created Django environments using the eb terminate command. Whenever you need to add them back, you can use the eb create command for that. Running the eb terminate command just removes specified environment (terminates the environment and all AWS resources that run within it) but leaves the Elastic Beanstalk application container intact.
And now we are ready to wrap up for today. As you can see, the AWS Elastic Beanstalk deployment option for Django is quite straightforward and convenient for use. It offers you simplified management which frees up time otherwise spent on server configuration which is also coupled with good customization capabilities and quite cost-efficient.
In my next blog post, I will try to cover some additional settings/options of AWS Beanstalk, namely, switching the database engine from mysql to Postgres, configuring S3 storage for app static and media files and addition of custom URL for your app.
If you need more information or details I would also recommend you to review some official Amazon documentation on the deployment topic: AWS Documentation – Deploying a Django Application to Elastic Beanstalk or look through different other sections of AWS Elastic Beanstalk Documentation.