We all heard this expression many times when an application doesn't work in the production environment, "But it works on my machine". One of the main reasons we fall into this situation is that our development environment is different from our staging or production environment. One way to overcome this situation, is to containerize our application using Docker to ensure that development, staging, and production environments match exactly. By doing so, we can also save a lot of DevOps time on preparing each environment, installing packages, libraries, etc.
Now, pairing Docker with AWS can give even more benefits:
AWS provides different ways to run our dockerized application:
We are going to use AWS Elastic Beanstalk for this article. This is an ideal solution if you want to deploy your application quickly with low ops effort.
Before we dive into building and deploying our application make sure you have:
Let's start by installing the necessary packages and setting up our project:
Check if Elastic Beanstalk is installed successfully by running eb --version
Now let's create a requirements file to save all installed packages and their versions and save it in the root of the project:
pip freeze > requirements.txt
Next let's add
to our project and add the following content to it:.gitignore
Initialize git and commit the project:
Run the following command to create a new Django project:
django-admin startproject task_manager .
This generates:
manage.py
task_manager/
folder with settings.py
, urls.py
, etc.Now scaffold the tasks app by running the following command in the task_manager project folder:
python manage.py startapp tasks
You should now see a new
folder alongside tasks/
manage.py
.
Open
and add task_manager/settings.py
to the tasks
,
list.INSTALLED_APPS
In the
file and look for settings.py
and add ALLOWED_HOSTS
to it. This is not a secure practice, and we are doing this for our development. When you have your actual URL, replace this with your app URL to keep it secure*
ALLOWED_HOSTS= ['*']
Let’s create a simple model to represent a task in
.tasks/models.py
Open
and replace its contents with the following:tasks/models.py
Save the file and run Django migration
Now lets register it in admin. Replace the contents of
with the following:tasks/admin.py
Create a superuser and run the dev server:
Visit http://127.0.0.1:8000 and login to http://127.0.0.1:8000/admin to confirm we are all set
Let's use Django’s built-in generic class-based views for a quick CRUD interface.
Replace the content of
with the following:tasks/views.py
We built views for listing, creating, updating, viewing and deleting tasks.
Let's wire these views to URLs and create minimal templates so you can test them.
Create
file with the following content:tasks/urls.py
Add it to the project main URLs
by replacing the content with the following:task_manager/urls.py
In the project root
create a folder called django-docker-eb
and add the following files to ittemplates
base.html
Now create a new folder called
under tasks
and add the following files to ittemplates
task_list.html
task_detail.html
task_form.html
task_confirm_delete.html
Now let's make sure Django can find our templates. Open the
file and look for settings.py
array and add the TEMPLATES
[BASE_DIR / 'templates']
to the
key DIRS
To test our templates run the Django server if its not running already
python manage.py runserver
and visit the http://127.0.0.1:8000/tasks/ and test:
You should see the following page:
In the root of the project, create a
and add the following to itDockerfile
Read the comments for more information about each line
Build your image by running the following command in the root of the project:
docker build -t task-manager:latest .
Run the following command in the root of the project to run database migrations inside a one-off container:
Run the following command in the project root to start your container:
Visit http://localhost:8000/tasks/ and verify that your Task Manager is up and has the same behaviour as before.
Run the following command to stop and remove the container:
docker stop task-manager-dev docker rm task-manager-dev
Before Elastic Beanstalk can pull your container, you need to store it in ECR (Elastic Container Registry).
To store our image in ECR, we need to create a repository first. Run the following command to create a repository:
Take note of the repository URI in the output (e.g.
) We need this for Elastic Beanstalk configuration.123456789012.dkr.ecr.us-east-1.amazonaws.com/task-manager
Run the following command to authenticate your Docker client:
Replace
with the actual URI123456789012
Run the following command to tag your local image:
Run the following command to push the image to ECR:
docker push 123456789012.dkr.ecr.us-east-1.amazonaws.com/task-manager:latest
Your Docker image is successfully pushed to ECR.
Head to the AWS Console, In the search bar look for ECR and click on it. You should see the following page:
Now that your Docker image is in ECR, let’s wire up Elastic Beanstalk to pull the image and deploy our Django application.
First, we need to create a new SSH key pair (you can use an existing one if you prefer)
This will create a new key file called
. Run task-manager-key.pem
to set the proper permissions, and move the pem file tochmod 400 task-manager-key.pem
~/.ssh
.
looks in the eb
CLI
directory for the key file.~/.ssh
We need this key to connect to our instance and run the Django migration command.
In the root of the Django project, run the following command:
Run the following command to create an environment and deploy:
eb create task-manager-env --keyname task-manager-key
This command creates and deploys our application in the Elastic Beanstalk and setup
as our SSH key.task-manager-key
After running the command, you see something like the following in your terminal:
This can take a couple of minutes, wait until it's done.
When it's successfully completed, open the application in your browser by running
you can navigate to eb open
and /tasks/
. The application is not fully functional yet since we didn't run the migrations/admin
You can also go to the AWS Console, search for
and click on theElastic Beanstalk
task-manager-prod
environment. You can find the application URL in the
Domain
section.
Let's ssh into the our environment and run Django migration. In the root of the project run
this should read the ssh key from eb ssh
and connect to the environment. You should see something like the following in your terminal:~/.ssh/task-manager-key.pem
Now now run
to find the docker container id under the sudo docker ps
CONTAINER ID
column.
Next run the
to get a shell inside the container.docker exec -it
bash
Now run
to run the migrations. After finishing the migration, run python manage.py migrate
to get out of the container.exit
Now run
to open the application and try CRUD operations to create, update and delete tasks.eb open
Here are some extra commands you can use:
When you push a new Docker Image, You should run the following command to deploy your application
eb deploy
In this article, we walked through the steps on how to deploy a Django app to AWS with Docker. We saw how simple it is to deploy to ElasticBeansTalk without a complex DevOps process or orchestration tools. Our deployment is scalable and fully managed, and we can keep our focus and time on building our application instead of wasting time on the DevOps tasks.
You can find the project code here
Here are the next steps to push this to the next level
Looking to learn more about Docker, Django and Deploy Django to AWS with Docker? These related blog articles explore complementary topics, techniques, and strategies that can help you master How to Deploy Django to AWS with Docker: Step-by-Step Guide for Scalable Apps.