...

Deploy Dockerized Django-Postgres Project On Aws Ec2

Bm-Zi

April 11, 2023

 

Deploy a Django-Postgres-Nginx-Certbot Project into AWS EC2 Server

 

Step 1: Create Django Project

  • Create requirements.txt
  • Create Dockerfile
  • Create docker-compose.yml
  • Create our Django project:
    • docker-compose run –rm app sh -c “django-admin startproject app .”
  • Create Django app (in my case I named my app as main):
    • docker-compose run –rm app sh -c “python manage.py startapp main”
  • Add created app to settings.py

 

Step 2: Check the project is running fine

To check the createed project is ok, you can create a simple app/main/views.py:

from django.shortcuts import render

def index(request):
    return render(request, "home/index.html")

 

And also create a simple app/app/settings.py:

from django.contrib import admin
from django.urls import path

from main import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index),
]

 

Step 3: Adding or Replace Files from Development

After creating a Django project, copy or replace files from development into app/ folder. Then, do the necessary modifications in settins.py and urls.py. This way you replaced your app indeveloped before in dev environment with the simple app that you created in previous step.

 

Step 4: Adding Folder ‘docker’

Create or copy files into ‘docker’ folder located in project root directory, from following link in github:
https://github.com/LondonAppDeveloper/django-docker-deployment-with-https-using-letsencrypt/tree/main/docker

In root directory of your project you will create three docker files:

  • Dockerfile (is used to create base image for dev and prod environment)
  • docker-compose.yml (docker file for services ithat will be started up in dev env)
  • docker-compose.deploy.yml (docker file for services ithat will be started up in prod env)

Step 5: Loading Static Files into Templates

The js, css and images folders contain static files that are loded from STATICFILES_DIRS located in app/app/settings.py file, on running server in development.

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'web/static'),
    os.path.join(BASE_DIR, 'web/media')
]

So to load static data into the templates you need to copy all js, css and images folders into STATICFILES_DIR.

Now run following commands:

docker-compose build
docker-compose run --rm app sh -c "python manage.py makemigrations main"
docker-compose run --rm app sh -c "python manage.py migrate"
docker-compose run --rm app sh -c "python manage.py createsuperuser"
docker-compose up

 

Step 6: Dumping Data From Database

If you keep a backup of database for your project, you can resore it. this way all static data, will be restored into the newly created database in running container:

cat backup.sql | docker exec -i db_container_id psql -U db_user db_name

At this step you will see all text data coming to template from database.

 

Step 7: Loading Media

The settings related to media files and images has to be created and verified in settings.py and urls.py

Examples:

app/app/settings.py

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'web/static'),
    os.path.join(BASE_DIR, 'web/media')
]

STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

MEDIA_URL = "/media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "mediafiles")

app/app/urls.py

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

As to above in settings.py the media files are stored in ‘mediafiles’ folder. So if you restore the media files you can load them into templates. For example, the svg icons for the skills table, are stored in:
app/mediafiles/skills/django.png (skills icon image in home page under bio) app/mediafiles/portfolio/all-codes.png (portfolio image in home page)

 

Using Projects Images inside of Ckeditor

Images will be saved in folder MEDIA_ROOT, which is in our case ‘mediafiles’. The url path will be the path of image in ‘mediafiles’ folder, appended to ‘/media/’.

Example:
image file path: app/mediafiles/projects/some_project/some-picture.png (MEDIA_ROOT)
url path: media/projects/some_peoject/some-picture.png (MEDIA_URL)

 

Create an EC2 Server

  • Login to https://console.aws.amazon.com/
  • Go to VPC that you want to create ec2 server
  • Before create ec2, navigate to EC2 > Key Pairs and import your public key for SSH authentication
  • Launch Instance
  • Use the public IPv4 DNS to connect to the server via ssh as user ec2-user, example:
    • ssh -i  your-key.pem  ec2-user@ec2-6-94-121-107.ca-central-1.compute.amazonaws.com
  • Install Docker, Docker compose and git on ec2
# Install Docker
sudo yum update -y
sudo amazon-linux-extras install -y docker
# If above didn't work, try:
sudo yum install -y docker
docker --version
sudo systemctl enable docker.service
sudo systemctl start docker.service
sudo usermod -aG docker ec2-user
# log out and login to ec2, to take effect the permissions
# Install Docker Compose
wget https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)
sudo mv docker-compose-$(uname -s)-$(uname -m) /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version
# Install git
sudo yum install -y git
# crontab may be is not running, although it is installed. To fix it install cronie
sudo yum install cronie cronie-anacron 

 

Pushing code to github

  • Create a private git repository and copy ssh and clone this empty project in local machine.
  • Copy development code into the cloned folder.
  • Run ‘docker-compose build’ from this folder
  • Remove new volume folder created /var/lib/docker/volumes/new_volume/_data
  • Copy volume folder in “/var/lib/docker/volumes/old_volume/_data” to “/var/lib/docker/volumes/new_volume/”
  • Run “docker-compose up” to be sure all is good
  • Now push the code to github
git remote -v
git status
git add .
git commit 
git push origin main

Now check the code is pushed in github from browser.

 

Deploying from GitHub

Login to ec2 and run:

ssh-keygen -t ed25519 -C "GitHub Deploy Key"

After pushing code to github, go to settings tab > Deploy keys/Add new and paste the content from:

cat ~/.ssh/id_ed25519.pub

Login to ec2:

ssh -i your-aws-key.pem ec2-user@6.94.121.107

Then on EC2 server:

git clone <paste url from github ssh >
git clone git@github.com:bm-zi/portfolio-server.git
ls

 

Setup DNS

You already have a domain registered, so use Route 53 to create a hosted zone.
Once you have a Hosted zone in AWS, you can add a new subdomain by creating a CNAME record.

Add/update DNS server of your registered domain, from NS records in "Hosted Zone" (Usually are 4 urls.).

 

Configure app

On EC2 change to project root directory.

cp .env.sample .env
vi .env

Here are example entries that you must have them defined that will be used as environment variables in your project config files.

DJANGO_SECRET_KEY=yoursecretkey

ALLOWED_HOSTS=localhost,127.0.0.1,your-domain.com

ACME_DEFAULT_EMAIL=youremail@example.com

DOMAIN=your-domain.com

DB_NAME=db_name

DB_USER=db_user

DB_PASS=db_password

 


# Getting the first certificate
docker-compose -f docker-compose.deploy.yml run --rm certbot /opt/certify-init.sh
# if successful:
docker-compose -f docker-compose.deploy.yml down
docker-compose -f docker-compose.deploy.yml up

Now check if the app is up and running in the browser.

 

Automate Certificate Renewal

To renew:

docker-compose -f docker-compose.deploy.yml run --rm certbot sh -c "certbot renew"

In the home directory of your server user (eg: /home/ec2-user/renew.sh):

#!/bin/sh
set -e

cd /home/ec2-user/your-project-folder
/usr/local/bin/docker-compose -f docker-compose.deploy.yml run --rm certbot certbot renew

Then we setup crontab:

crontab -e

0 0 * * 6 sh /home/ec2-user/renew.sh