40. Deploying UI for AI Application on AWS Ec2:Docker+Django+Nginx+Gunicorn

WEB-DEV
One of the options for delivering an AI application is creating a USER INTERFACE so that the clients can use the AI app even without any knowledge of programming. For this time, I’ve decided to try it out on AWS.
To be honest, the deployment process was WAAAY harder than I’d expected. (After a while, I found out that using AWS ECR and ECS instead is more preferable considering scalability, but I was already halfway there so I just went with it)

CODE
I’m using docker-compose with 3 services..
1. backend -> DJANGO app
2. db
3. Nginx

Directory TREE
├─backend
│   ├─.env
│   └─DockerFileBack.prod
│      
├─nginx
│   ├─default.conf
│   └─DockerFile
│
└─docker-compose.prod.yml  
docker-compose.prod.yml

version: "3.3"

services:

  #Container for BACKEND
  backend:

    container_name: backend
    build: 
      context: ./backend
      dockerfile: DockerFileBack.prod

    # Command I want to run every time the container is built
    command: > 
      /bin/bash -c "
      python manage.py makemigrations; 
      python manage.py migrate --noinput;
      python manage.py collectstatic --no-input --clear; #--CHECK DockerFileBack.file
      gunicorn -b 0.0.0.0:8000 PROJECT_NAME.wsgi:application; #Bind gunicorn to port 8000

      " 

    # Exposing a port lets other container access this port
    expose:
      - 8000

    # Path to .env file which has the secret access keys
    env_file: 
      - ./backend/.env
    depends_on:
      - db

  db:
    image: postgres:13.0-alpine
    container_name: db
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    env_file: ./backend/.env


  nginx:
    build: ./nginx

    # Nginx CANNOT serve static files so you'll need to..
    # 1.Create directory "staticfile" -> Check DockerFileBack.prod
    # 2.run collectstatic command like the code in the backend container
    #   This will save the static data to directory in step 1.
    # 3.Set volume name and file path here to the staticfiles directory
    volumes:
      - static_volume:/home/app/web/staticfiles

    #When someone Accesses port 1337 -> connect with the port 80 in DOCKER
    #Later on we'll proxy all request from port 80 to 8000
    ports:
      - "1337:80"
    depends_on:
      - backend

volumes:
  postgres_data:
  static_volume:
DockerFileBack.prod


FROM python:3.9.5

ENV PYTHONUNBUFFERED 1
# create directory
RUN mkdir -p /home/app

# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME

#All the data from collectstatic command(docker-compose.yml) Will be saved here,
RUN mkdir $APP_HOME/staticfiles 
WORKDIR $APP_HOME

COPY . .
RUN pip install --upgrade pip
RUN pip install -r requirements.txt

# copy project
COPY . $APP_HOME

Nginx (Most confusing part for me)
There are 2 files you’ll need to configure.
1. default.conf
2. DockerFile -> Replace the default default.conf inside the container with the one you’ve created in Step1

default.conf

#ANY_NAME should be the same as the location's proxy pass below
upstream ANY_NAME {
   server back:8000;
}

server {

        #If someone comes to port 80..
        listen 80;

        
        #Proxy to ANY_NAME (which is port 8000)
        location / {
        proxy_pass http://ANY_NAME; #ANY_NAME can be any name as long as it is the same as the upstream name
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        }
        
        location /static/ {
        alias /home/app/web/staticfiles/;
        }
}
DockerFile

# Get Image
FROM nginx:1.21-alpine

# remove the default default.conf
RUN rm /etc/nginx/conf.d/default.conf


# replace with the default.conf you've created
COPY default.conf /etc/nginx/conf.d/default.conf