Deploying Your First Dockerized Django REST API on AWS Elastic Beanstalk: A Comprehensive Guide
Tags: api, docker, aws, django
Published: 2023-05-23 09:19:19

Welcome to this comprehensive guide on deploying a Dockerized Django REST API on AWS Elastic Beanstalk. This tutorial is designed to walk you through the process, starting from setting up your Django application to finally deploying it on AWS Elastic Beanstalk.

But first, let's take a moment to understand why this is important.

In an increasingly digital world, web services and APIs play a crucial role in enabling seamless communication between different software applications. Among many frameworks, Django stands out for its robustness and simplicity, making it a preferred choice for many Python developers.

Furthermore, Docker simplifies deployment by packaging applications with all their dependencies into standardized units called containers. This removes common issues such as "it works on my machine but not on the server" problem. This is why Dockerizing your Django REST API not only makes your project more manageable but also ensures it runs the same, regardless of the environment.

AWS Elastic Beanstalk is a popular choice for deployment because it handles all the infrastructure details, letting you focus on just the application. It supports several platforms, including Docker, and automates the process of deployment, capacity provisioning, load balancing, and automatic scaling.

By the end of this tutorial, you will have learned how to set up a Django REST API, Dockerize it, and deploy it on AWS Elastic Beanstalk. This guide is designed for developers who have a basic understanding of Django, Docker, and AWS, but are looking to piece everything together in a production-ready setup.

In the next sections, we will delve deeper into each step, explain the concepts, provide code snippets, and show you exactly what you need to do. Let's dive in!

#1.Creating the API
###Create a virtual environment:

`virtualenv env`
`source env/bin/activate`

###Set up a new Django project
Firstly, we need to install Django and Django REST framework. Make sure you have Python installed on your machine. You can install Django and Django REST framework using pip:

`pip install django`
`pip install djangorestframework`

Now, we can create a new Django project. Let's name it "bookstore":

`django-admin startproject bookstore`

###Create a new Django app:

```python
cd bookstore
python manage.py startapp books
```
###Define the Book model

In books/models.py, define a Book model:

```python
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    publication_date = models.DateField()
    isbn = models.CharField(max_length=20)
    summary = models.TextField()

```

Don't forget to add 'books' to installed apps in bookstore/settings.py:

```python
INSTALLED_APPS = [
    ...
    'rest_framework',
    'books',
]
```
Run migrations to create the corresponding database table:

```python
python manage.py makemigrations
python manage.py migrate

```

###Create a serializer for the Book model
In books/serializers.py, define a BookSerializer:

```python
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = '__all__'

```

###Set up a view for handling REST API requests
In books/views.py, define a BookViewSet:

```python
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer

class BookViewSet(viewsets.ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

```
###Configure the URL routing
In bookstore/urls.py, add a route for the books application:

```python
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from books.views import BookViewSet

router = DefaultRouter()
router.register(r'books', BookViewSet)

urlpatterns = [
    path('', include(router.urls)),
]

```
###Test the API locally
Start the Django development server:

`python manage.py runserver`

You should now be able to access the API at [localhost](http://localhost:8000/books/) as shown:

![localhost](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hzm5iv42vyxms2ycahz7.png)
>Note the Local url meaning your api is running from your machine


Awesome! With the Django RESTful API ready, the next step is to Dockerize your application

#2.Dockerising the API
###Download Docker
We will use the CLI to download Docker, By using the Docker CLI, you empower yourself with a powerful toolset to interact with Docker, manage your containers, and orchestrate your applications effectively. It provides a consistent and flexible interface to work with Docker, whether you're running it locally or in cloud-based environments.

For Linux:
`curl -fsSL https://get.docker.com -o get-docker.sh`
`sudo sh get-docker.sh`

For MacOS:
`brew install --cask docker`

For Windows/powershell:
`iex "& { $(irm https://aka.ms/win-docker/cli-latest.ps1) }"`

*Use this command to get Docker running on your System*:
`sudo systemctl start docker`

###Creating a Dockerfile:
Create a new file in your project's root directory (the same directory where manage.py is located) and name it Dockerfile. This file will define how to build the Docker image for your application. Here's a basic Dockerfile for a Django application:

```docker
# Use an official Python runtime as a parent image
FROM python:3.9-slim-buster

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Set the working directory in the container to /app
WORKDIR /app

# Add the current directory files (on your machine) to the container
ADD . /app/

# Install any needed packages specified in requirements.txt
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

# Expose the port server is running on
EXPOSE 8000

# Start the server
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

```
> The Dockerfile provides instructions for building a Docker image for a Django application. It starts with an official Python 3.9 slim image as the base. Environment variables are set to disable bytecode writing and enable unbuffered output.
The working directory is set to /app, and the current directory's files are added to the container. The requirements.txt file is used to install the necessary Python packages.
Port 8000 is exposed to allow incoming connections. Finally, the Django development server is started with the command python manage.py runserver 0.0.0.0:8000.
This Dockerfile allows you to package your Django application and its dependencies into a container, making it portable and easily deployable across different environments.

###Create a requirements.txt file
You also need to create a requirements.txt file that lists the Python dependencies of your project so that Docker can install them. You can generate a requirements.txt using :

`pip freeze > requirements.txt`

###Build the Docker image
Now you can build the Docker image from the Dockerfile. Make sure Docker Desktop is running, and then run the following command in the terminal from the directory that contains the Dockerfile:

`docker build -t bookstore . `

You can use this command to look at your new Django Image:
`docker images`

###Run the application using Docker:
'docker run -p 8000:8000 bookstore'
>You may get a DisallowedHost error which occurs because the ALLOWED_HOSTS setting in your Django project is not configured to allow the given host value '0.0.0.0'.To fix this issue, you can update the ALLOWED_HOSTS setting in your Django project to include '0.0.0.0'

You should now be able to access the API at http://0.0.0.0:8000/ again, this time running inside a Docker container as shown:


![Docker Dep](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8yd155k3k633m8bp7658.png)
>Note the new url which your api is now running as a Docker container

Now your application is Dockerized and ready to be deployed to AWS Elastic Beanstalk.

#3.Deploying Dockerised API on AWS Elastic Beanstalk
Before deploying your app you need to ensure that you have an Dockerhub account which is a cloud-based registry service that allows you to link to code repositories, build your images and test them, store manually pushed images, and link to Docker Cloud so you can deploy images to your hosts. It provides a centralized resource for container image discovery, distribution, change management, and collaboration.

After making your account, You can now login using the CLI:

`docker login`
>It will ask for your Docker Hub username and password.

Tag your image with your Docker Hub username. Docker requires that the image you're pushing includes your Docker Hub username. Use the command:
`docker tag bookstore:latest <your-docker-hub
username>/nice-reads:latest`
>NB: I called my Dockerhub repo nice-reads but you can name it anything you prefer also i have just left the default tag which is latest

Next, After tagging the image, you can push it to Docker Hub using the command:
`docker push <your-docker-hub-username>/nice-reads:latest`
>Please ensure that you replace <your-docker-hub-username> with your Docker Hub username in the commands above.

Great, now that you've pushed your Docker image to Docker Hub, you can deploy it to AWS Elastic Beanstalk.

Install the Elastic Beanstalk Command Line Interface (EB CLI) if you haven't done so yet. You can install it with pip:

`pip install awsebcli`

Initialize your Elastic Beanstalk environment. In the root of your project, run:

`eb init`

>You'll be prompted to select a region, and to provide your AWS Access Key ID and Secret Access Key. If you haven't created these yet, you can create them in the AWS IAM Console. You'll also be asked to choose a platform; you can choose Docker.

Next, Create a Dockerrun.aws.json file in the root of your project. This file is required by AWS Elastic Beanstalk to understand how to run your Docker container. Here is an example of what the file can look like:

```json
{
  "AWSEBDockerrunVersion": "1",
  "Image": {
    "Name": "<your-docker-hub-username>/nice-reads:latest",
    "Update": "true"
  },
  "Ports": [
    {
      "ContainerPort": "8000"
    }
  ]
}

```

With the Dockerrun.aws.json file in place, you can create your Elastic Beanstalk environment:

`eb create`

>The eb create command will ask you for an environment name and a CNAME prefix. The environment name is just a name for you to identify the environment, and the CNAME prefix is used to create a URL to your application.
AWS Elastic Beanstalk will then create an environment for your application with a load balancer, Auto Scaling group, security group, an Amazon S3 bucket for storing your application versions and logs, and CloudWatch alarms that monitor the health of your environment and trigger automatic scaling actions.
It will also pull the Docker image from Docker Hub and run it.

After the command completes, your application should be accessible on the internet. You can get the URL with the command:

`eb open`

This will open our deployed API via the url as shown:


![Eb open](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixrp2xwokrltbxydmc0h.png)
>Note the new url that confirms deployment

Finally you can check the status of you application on Eb by running this command:

`eb status`

Which should look similar to this:

![Status](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3k0lz608pwk8j2o6i7dp.png)


>NB:if you are facing deployment issues related to ALLOWED_HOSTS, you may use ['*'] as a temporary measure, but do not forget to replace it with the actual hostname when moving to production.

#Conclusion
Congratulations! If you've followed along this tutorial, you have successfully deployed your Dockerized Django REST API to AWS Elastic Beanstalk. You can now navigate to your app's URL and enjoy the fully functional, live application.

It's worth checking the status of your environment on the Elastic Beanstalk console. If you see a green checkmark and a status of "Healthy," that means your application is running smoothly.

Remember that you can also keep track of your AWS usage and manage costs by visiting the Billing & Cost Management Dashboard on your AWS console. This is especially important if you're working on large-scale projects or using multiple AWS services.
While there are numerous ways to deploy applications to AWS Elastic Beanstalk, we opted to use the AWS CLI throughout this tutorial. The AWS CLI is a powerful tool that allows you to manage your AWS services from the command line, providing a consistent interface across services. It's also worth noting that this approach enables you to automate processes through scripts, thereby enhancing productivity and reducing manual errors.
To make all this work, you need to have properly configured your AWS account, which includes setting up IAM roles and permissions. AWS provides comprehensive guides on their website to help you navigate these configuration settings.

The Django REST API application used in this tutorial is available on my GitHub repository[BookstoreApp](https://github.com/ki3ani/mybookapp). Feel free to clone it, explore it, and use it as a foundation for your own projects.

In the journey of software development, remember that learning is continuous and the technology landscape is ever-evolving. Today, you've taken a significant step by learning how to deploy a Dockerized Django application on AWS Elastic Beanstalk. Keep exploring, keep learning, and most importantly, enjoy the process. Until next time, happy coding!