본문 바로가기

문돌이 존버/Django 스터디

Django, Nginx, Gunicorn, Docker 이미지 생성 및 AWS에 배포

반응형

지난 번 Nginx와 Gunicorn에 대해 간략하게 소개했습니다. 오늘은 실제로 Nginx - Gunicorn - Django를 연동하고 Docker 이미지로 만들어 배포하는 과정을 살펴보고자 합니다.

출처: https://yongbeomkim.github.io/django/dj-guni-cent/

먼저 Nginx와 Gunicorn을 설치해야 하는데, 아마 AWS EC2 Ubuntu 20.04를 사용한다면 Nginx는 자동으로 설치되었을 것입니다(아닐 수도 있구요^^). 설치되지 않았다는 가정 하에 설치하는 것부터 해보겠습니다.

sudo apt update
sudo apt upgrade

# nginx 설치
sudo apt install nginx
# 실행
sudo service start nginx

# gunicorn 설치
pip install gunicorn
# 실행 확인
gunicorn --bind 0:8000 myapp.wsgi:application

(추가) gunicorn을 실행할 때는 Django의 manage.py 파일이 있는 디렉토리에서 하셔야 합니다. gunicorn을 통해 가상 서버를 띄워보는 것이기 때문에 python manage.py runserver를 대신한다고 생각하시면 됩니다.

gunicorn 실행 파일은 아래와 같이 작성합니다. 참고로 gunicorn 설치 위치를 찾으실 땐 which gunicorn 을 입력하시면 나옵니다.

vi /etc/systemd/system/gunicorn.service

[Unit]
Description=gunicorn daemon
After=network.target

[Service]
User=사용자명 # ex: ubuntu
Group=그룹명 # 자유롭게 작성
WorkingDirectory=장고 프로젝트 디렉토리
ExecStart=gunicorn 설치 디렉토리 \
        --workers 3 \
        --bind 0.0.0.0:8000 장고 앱.wsgi:application

[Install]
WantedBy=multi-user.target

그리고 gunicorn 서비스를 등록하고 실행하려면 아래와 같이 명령어를 입력합니다.

# 서비스 등록
sudo systemctl start gunicorn
# 서버 재시작시 자동 실행
sudo systemctl enable gunicorn
# 서비스 상태 확인
sudo systemctl status gunicorn.service

# 참고 명령어
# 서비스 중지
sudo systemctl stop gunicorn.service
# 재시작
sudo systemctl restart gunicorn

nginx 파일을 가장 간단하게 설정하는 방법은 아래와 같습니다.

먼저 /etc/nginx/sites-available/ 디렉토리에 가서 vi '장고 프로젝트 이름' 을 치고 아래와 같이 파일을 작성합니다.

server {
    listen 80;
    server_name AWS IP주소;

    location / {
        include proxy_params;
        proxy_pass http://AWS IP주소:8000;

    }
}

위 파일을 해석해보면 클라이언트가 IP주소.80으로 요청을 보내면 http://IP주소:8000으로, 즉 gunicorn으로 연결되어 요청이 처리된다는 의미입니다.

다음으로 위 파일을 /etc/nginx/sites-enabled/ 디렉토리에 옮겨줘야 합니다. sites-available 은 설정을 지정하는 곳이고, 실제 반영을 위해선 sites-enabled 디렉토리에 설정 파일이 있어야 합니다.

sudo ln -s /etc/nginx/sites-available/장고 프로젝트 이름 /etc/nginx/sites-enabled

nginx 설정 파일 문법을 검사하는 방법도 있습니다.

sudo nginx -t

# 정상 메시지
# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# nginx: configuration file /etc/nginx/nginx.conf test is successful

정상적으로 메시지가 출력되면 nginx를 다시 시작합니다.

sudo service restart nginx
# 작동 상황 확인
sudo service nginx status

버전 확인은 아래와 같이 합니다.

sudo dpkg -l nginx

참고로 제가 설정한 파일 구조는 아래와 같습니다. 볼드 처리한 것이 폴더이고, 그렇지 않은 것이 파일입니다. src 폴더는 Django 관련 실행 파일을 담은 폴더입니다.

config
nginx
    ㄴ default.conf
docker-compose.yml
Dockerfile
src
myweb
myapp
ㄴ manage.py
ㄴ requirements.txt

config/nginx/default.conf  파일 내용입니다.

# default.conf
server {
    listen 80;
    location / {
        proxy_set_header Host $host:$server_port; # $host는 nginx 변수로 클라이언트 요청에 있는 host를 가리킴
        proxy_pass http://web:80;
        proxy_redirect off;
    }
    location /static/ {
        alias /src/.static_root/;
    }
    location /media/ {
        alias /src/media/;
    }
    access_log /var/log/nginx/8000_access.log; # nginx 로그 관리
    error_log /var/log/nginx/8000_error.log;
}

# http로 들어온 요청은 자동으로 https로 리다이렉트
server {
    listen 80;
    server_name domain_name;
    return 301 https://$host$request_uri;
}

# https 설정
server {
    listen 443 ssl;
    server_name domain_name;
    
    ssl on;
    ssl_certificate /etc/nginx/conf.d/django.crt;
    ssl_certificate_key /etc/nginx/conf.d/django.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    
    access_log /var/log/nginx/443_access.log;
    error_log /var/log/nginx/443_error.log;
    
    location / {
        proxy_set_header Host $host:$server_port;
        proxy_pass http://web:80;
        proxy_redirect off;
    }
    location /static/ {
        alias /src/.static_root/;
    }
}
listen 80; -> nginx 컨테이너에서 외부로 향하는 포트
location -> 서버 호스트의 기본 주소 뒤에 붙는 위치 주소 정보
proxy_set_header Host \$host:\$server_port; -> 호스트의 주소와 포트를 고정(설정하지 않으면 django는 호스트 주소와 포트가 무엇인지 몰라 proxy_pass로 들어오는 주소를 사용)
proxy_pass http://web:80; -> 루트 디렉토리로 접근했을 때 web 컨테이너의 80번 포트로 안내

ssl_protocols TLSv1.2 TLSv1.3 -> HTTPS에 사용할 프로토콜을 SSL 대신 TLS 사용
* TLS -> SSL이란 용어가 TLS(Transport Layer Security)로 변경
           주요 버전별로 SSLv2, SSLv3, TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3으로 분류
ssl_prefer_server_ciphers_on -> 클라이언트와 cipher suite 협상 과정에서 서버측에서 지정해 놓은 순서를 우선시하도록 설정

docker-compose.yml 파일 내용입니다.

# docker-compose.yml
version: "3"
services:
  nginx:
    image: nginx:latest
    container_name: ng01
    ports:
        - "80:80"
        - "443:443"
    volumes:
        - ./src:/src
        - ./config/nginx:/etc/nginx/conf.d
    depends_on:
        - web

  web:
    build: .
    container_name: dg01
    command: bash -c "
        python3 manage.py collectstatic --no-input &&
        python3 manage.py makemigrations &&
        python3 manage.py migrate &&
        gunicorn myweb.wsgi:application -b 0:80"
    volumes:
        - ./src:/src
        - ./config/gunicorn:/etc/systemd/system

Dockerfile 파일 내용입니다.

# Dockerfile
FROM ubuntu:20.04 # ec2와 같은 우분투 버전

RUN sed -i 's@archive.ubuntu.com@mirror.kakao.com@g' /etc/apt/sources.list

RUN apt-get -y update && apt-get -y dist-upgrade
RUN apt-get install -y apt-utils dialog libpq-dev

RUN apt-get install -y python3-pip python3-dev

# 우분투에 mysqlclient를 설치하기 위함
RUN apt-get install -y libssl-dev
RUN apt-get install -y mysql-server
RUN apt-get install -y mysql-client
RUN apt-get install -y libmysqlclient-dev

RUN pip3 install --upgrade pip
RUN pip3 install --upgrade setuptools

RUN mkdir /config
ADD /config/requirements.txt /config/
RUN pip3 install -r /config/requirements.txt

RUN mkdir /src
WORKDIR /src
FROM: base 이미지 사용 <- 하나의 Docker 이미지는 base 이미지로부터 시작해서 기존 이미지 위에 새로운 이미지를 중첩하여 여러 단계의 이미지 층(layer)을 쌓는 과정
RUN: 커맨드 실행 like 쉘(shell)
ADD: 호스트 컴퓨터에 있는 디렉토리나 파일을 Docker 이미지 파일 시스템에 복사
<-> COPY와 유사한 기능이지만 ADD의 경우 원격 파일 다운로드 및 압축 해제 등의 기능도 보유
WORKDIR: 작업 디렉토리 전환 like 쉘의 cd 명령문

docker-compose 이미지 빌드 및 실행

# --build 옵션: 도커 이미지를 강제로 다시 빌드(개발 과정에서 이미지가 자수 수정되는 경우 바람직)
docker-compose up --build

# 백그라운드로 실행, 즉 컨테이너 내부 gunicorn 등이 계속 실행되도록
docker-compose up -d --build

도커 이미지 리스트 보기

docker image ps -a

실행중인 컨테이너 접속하기

docker exec -it {이미지 네임 또는 컨테이너 id} /bin/bash

돌아가는 특정 컨테이너 정지

docker-compose stop {컨테이너 id}
참조
https://qwlake.github.io/django/aws/docker/2020/03/17/django-deploy-at-aws-with-docker/
https://cloud-oky.tistory.com/362

 

728x90
반응형