Nginx와 Django EC2에 배포하기 (feat. RDS 생성 및 연결)

hwiba·2022년 10월 2일
1
post-thumbnail

E-Commerce 백엔드를 개발하고 서버인프라를 구축하여 AWS EC2에 배포해본 경험을 기록한 글입니다.
해당소스를 보실려면 여기를 클릭해주세요.


AWS EC2?


AWS에는 배포하기 좋은 여러 서비스가 많지만 직접 서버를 생성 및 구축해보고 싶어서 AWS의 EC2(클라우드 컴퓨팅 환경)를 생성하여 서버를 구축 및 실행 시켜보았다.


인프라 구성


배포환경을 구축하기 위해 Nginx, Gunicorn + Django를 도커라이징 및 도커컴포즈를 이용하여 서버를 띄우고, AWS의 RDS를 따로 생성하여 백엔드 서버와 연결하였다.

Nginx, Gunicorn, RDS를 이용하는 이유

Nginx

클라이언트의 요청을 처리해주는 경량 웹서버로서 정적요청은 Nginx에서 자체적으로 처리하고, 동적요청만 Gunicorn + Django에 전달하여 처리하기 위해 사용

Gunicorn

Nginx가 Django에게 동적 요청을 전달할 수 있도록 도와주는 역할, WSGI 서버라고 한다.

RDS

EC2안에 MySQL를 다른 컨테이너와 같이 올리게되면 EC2 인스턴스환경에 부담을 주고, data손실의 위험성이 있어서 RDS를 생성하여 EC2와 연결하였다.


서버 구조


EC2 및 RDS 생성

해당 EC2 인스턴스 및 RDS 생성은 블로그를 참조하여 생성하여 해당 링크만 명시하겠다.

EC2 생성
RDS 생성

AWS는 편하게 간단한 설정만하면 클라우드 컴퓨팅 환경과 데이터베이스를 생성할 수 있어서 편한 것 같다!


  • 생성한 EC2

  • 생성한 RDS


기본 설정 및 도커라이징


EC2에 배포하기전에 여러 설정과 도커파일 및 도커컴포즈파일을 작성해야된다.

Nginx Setting

정적요청을 Nginx에서 자체적으로 처리하고, 동적요청을 gunicorn에게 전달하기 위해서는 밑의 기본 설정을 해줘야된다.

# backend 업스트림 서버 설정
upstream backend {
	# 밑의 docker-compose의 네트워크를 이용해서 backend 컨테이너를 호출할 수 있다.
	server backend:8000;  
}

server {
	listen 80;  # 기본적으로 80번포트에 들어온 요청에 한해서만 처리

	# /media/ 루트로 들어온 요청에한해서는 
    # /backend/.media_root/의 경로에서 요청들어온 자원을 찾아 처리해준다.
	location /media/  {
	    autoindex on;
	    alias /backend/.media_root/;
	}
    
   
    # /static/ 루트로 들어온 요청에한해서는 
    # /backend/static/의 경로에서 요청들어온 자원을 찾아 처리
	location /static/  {
	    autoindex on;
	    alias /backend/static/;
	}

	# 위의 정적 요청을 제외한 동적요청들을 backend 서버에 전달
	location / {
		proxy_pass http://backend;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
	}
}

Nginx Dockerfile

Nginx를 컨테이너로 올리기 위해 도커파일을 작성한다.

FROM nginx:1.19.0-alpine  # Nginx 기본 이미지

# 위의 설정을 복사하여 Nginx컨테이너에 붙여넣기
COPY ./default.conf /etc/nginx/conf.d/default.conf  

Backend

Django Database setting

위에서 생성한 RDS로 설정을 바꿔줘야된다. 나같은 경우에는 .env로 환경변수를 작성해야되기 때문에 데이터베이스에대한 정보는 .env에 작성했다.

"""
RDS MySQL Information
"""
DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.mysql",
        "NAME": os.environ.get("DB_NAME"),
        "USER": os.environ.get("DB_USER"),
        "PASSWORD": os.environ.get("DB_PASSWORD"),
        "HOST": os.environ.get("DB_HOST"),
        "PORT": os.environ.get("DB_PORT"),
    }
# .env File
DB_NAME=RDS database name
DB_USER=RDS User
DB_PASSWORD=RDS Password
DB_HOST=RDS Endpoint

Backend Dockerfile

Django를 컨테이너로 띄워 gunicorn으로 실행시키기 위해 도커파일을 작성한다.

FROM python:3.9

## Turns off buffering for easier container logging
ENV PYTHONUNBUFFERED=1

RUN apt-get -y update

RUN mkdir /backend
ADD . /backend
WORKDIR /backend

RUN python -m pip install --upgrade pip
RUN pip install pipenv && pipenv install --dev --system --deploy

# 컨테이너가 수행될 때 entrypoint가 실행
ENTRYPOINT ["sh", "./entrypoint.sh"]

entrypint

Django가 실행되기전 migration 해주고, collectstatic 명령어를 통해 static file들을 모아준다.

마지막으로 Django의 웹프레임워크를 gunicorn으로 실행하여 Nginx의 요청을 전달받을 수 있도록한다.

python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic --no-input

gunicorn backend.wsgi:application --bind 0.0.0.0:8000 --reload

Docker Compose

backendnginx 2개의 컨테이너를 띄우는 배포용 도커컴포즈 작성을 한다(개발용 도커컴포즈는 따로작성하도록 한다).

여기서 network를 공유하도록 만들어서 nginx에서 컨테이너 이름만으로도 backend 컨테이너를 호출하기위함이다.

또한 이미지나 스태틱파일들이 nginx에서 처리하지 못해서 한참 해멨는데 ㅜ
Nginx에서 컨테이너에서 정적요청을 처리하기위해서는 제일 중요한 해당 자원들이 Nginx컨테이너 있어야된다!
밑의 nginx의 컨테이너의 volume에서 정적자원들의 경로를 명시해준다!!

#docker-compose.prod.yml
version: "3.7"

services:
  backend:
    container_name: backend
    restart: always
    volumes:
      - ./backend:/backend
    environment:
      DJANGO_SETTINGS_MODULE: backend.settings.deploy  # 배포설정으로 환경변수 변경
    env_file:
      - .env
    build: ./backend

    ports:
      - "8000:8000"
    networks:
      - local-net
  nginx:
    container_name: nginx
    build: ./nginx
    volumes:
      - ./backend/.media_root:/backend/.media_root  # 미디어 파일 경로
      - ./backend/static:/backend/static  # 스태틱 파일 경로
    ports:
      - "80:80"
    depends_on:
      - backend
    networks:
      - local-net

networks:
  local-net:
    driver: bridge

EC2에 배포

Install docker in EC2

먼저 docker가 EC2에는 기본적으로 설치되어 있지 않기 때문에 밑의 명령어를 통해 docker를 설치한다.

sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common 
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - 
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable" 
sudo apt update 
apt-cache policy docker-ce
sudo apt install docker-ce

소스 받아오기, 환경변수 작성

git clone

개발한 내용을 EC2에 가져오기 위해서 해당 레포를 클론하여 가져온다.

git clone repo url

.env파일 작성

중요한 환경변수는 깃에 올리지 않기 때문에 위에서 작성한 RDS에대한 정보를 .env을 작성한다.

도커컴포즈 실행

실행

이제 배포용 도커컴포즈 파일을 실행시킬 수 있도록 밑의 명령어를 이용하여 컨테이너를 띄어 서버를 실행시켜보자

docker-compose -f docker-compose.prod.yml up -d --build

결과

  • Nginx컨테이너와 backend 컨테이너가 실행중인 모습

  • 서버가 정상실행되는 모습


배포 후기

Nginx와 Docker를 이용해서 API 프로덕트를 배포한 경험은 처음이었다.

Nginx설정하고 정적요청을 정상적으로 처리하는 것에서 많은 삽질이 있엇고 ㅜ, 도커라이징하고 도커컴포즈를 이용하여 컨테이너를 실행시키는 부분에서 많은 애를 먹어서 힘들었던 것 같다.

하지만 정상적으로 정적요청과 동적요청을 처리하는 서버가 실행되는 모습에 보람을 느꼇다. 휴..

profile
도전하는 사랑하는 개발자

0개의 댓글