본문 바로가기

DevOps/Docker

Python WAS (Django, Wsgi, Nginx) 구축하기 - 로컬

0. 들어가며

docker와 django 배포 작업을 안한지 너무 오래되었고, 기억이 잘 안나서 이 참에 블로그로 정리해보려고 한다.

Python으로 rest api 서비스를 오픈할 수 있지만 Django의 runserver는 단순히 테스트만을 위한 기능이기 때문에 운영 배포 목적으로 하는 서비스에서 사용하면 성능상 문제를 겪게 된다.

Web Application은 Django를 사용할 것이며, 앞단에 Web Server인 Nginx를 리버스 프록시로 두고 Django와 Nginx를 Wsgi(Gunicorn)으로 연동하는 작업을 할 것이다.

Gunicorn을 사용하는 이유는 uWSGI나 Gunicorn 등은 Nginx로 들어오는 HTTP Request를 파이썬이 이해할 수 있게 동시 통역하는 존재들이다. 여기서 Gunicorn(Wsgi)는 멀티 쓰레드를 만들 수 있기 때문에 Request가 많아지더라도 효율적으로 처리할 수 있는 즉, 운영 환경에서 python runserver보다 더 적합하다고 할 수 있다.

 

1. Nginx를 리버스 프록시로 사용

위의 사진처럼 Nginx를 리버스 프록시로 사용할 것이다.

 

Nginx를 HTTP 서버에 대한 리버스 프록시로 구성하려면 도메인의 서버 블록 구성 파일을 열고 해당 파일 내부에 위치 및 프록시 서버를 지정한다.

본인은 nginx.conf에 nginx 설정 옵션과 server에 대한 옵션을 한번에 설정하였다.

# ${PWD}/nginx/nginx.conf

worker_processes auto;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events{
    worker_connections 1024;
}



http{
    server {
        listen 80;
        server_name localhost;

        include mime.types;

        location /static/{
            alias /data/static/;
        }

        location / {
            proxy_pass http://django:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
    }
}

프록시 서버 URL은 proxy_pass 옵션을 사용하여 설정되며 프로토콜, 도메인 이름 또는 IP 주소로 HTTP 또는 HTTPS를 사용할 수 있다.

 

위의 구성은 Nginx에게 모든 요청을 / 위치에 http://django:8000 프록시 서버로 전달하도록 하는 명령어들이다.

 

여기서 만약 클라이언트가 http://localhost에 접속할 경우, Nginx는 이 요청을 http://django:8000으로 요청을 대신 보내준다는 의미이다.

 

(Nginx의 옵션에 대한 설명은 다음 글에 정리하도록 하겠음)

 

 

2. Django 웹 애플리케이션, Mariadb 설정

# ${PWD}/Dockerfile

FROM python:3.9.0
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED=1

COPY ./ /home/django/

WORKDIR /home/django/

RUN apt-get update
RUN apt-get install -y --no-install-recommends gcc
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
# ${PWD}/docker-compose.yml

version: "3"
services: 
    mariadb:
        image: mariadb:10.5
        platform: linux/amd64
        container_name: mariadb
        networks: 
            - docker
        ports:
            - 3306:3306
        volumes: 
            - ${PWD}/database:/var/lib/mysql
        environment:
            MARIADB_ROOT_PASSWORD: 1234
            MARIADB_DATABASE: docker_lab

    django:
        build: .
        container_name: django
        command:
            - bash
            - -c
            - |
              python manage.py migrate
              python manage.py runserver 0.0.0.0:8000
        networks: 
            - docker
        ports: 
            - 8000:8000
        volumes: 
            - ${PWD}:/home/django
        depends_on: 
            - mariadb
        expose:
            - 8000
        restart: always

    nginx:
        image: nginx:latest
        container_name: nginx
        ports:
            - 80:80
        volumes:
            - ${PWD}/nginx/nginx.conf:/etc/nginx/nginx.conf
            - ${PWD}/data/static:/data/static
        networks:
            - docker
        depends_on:
            - django

    
networks: 
    docker:

위는 Django의 Dockerfile이고 django, maraidb, nginx를 하나의 도커 컴포즈 파일로 묶어두었다.

 

nginx 볼륨에 nginx.conf 파일의 경로로 두고 static의 경로는 nginx.conf에 location /static/에 따로 설정한 경로로 둔다.

 

위의 컴포즈 파일을 실행시키면 :8000번 포트뿐만 아닌 80번 포트로도 접근할 수가 있다.

 

 

 

 

3. Gunicorn으로 실행

python runserver말고 gunicorn으로 실행시켜야 한다.

django:
    build: .
    container_name: django
    command:
        - bash
        - -c
        - |
          python manage.py migrate
          gunicorn --bind 0:8000 config.wsgi:application

위 코드처럼 docker-compose.yml 파일에서 command 부분을 수정하면 된다.