ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Django - Nginx - Gunocorn - postgresql with Docker
    공부/Django 2023. 3. 4. 02:50

    Django - APP Server

    Gunicorn - WSGI (Web Server Gateway Interface)

    Nginx - Web Server

     

    Django의 runserver는 개발용으로 만 사용하라고 공식문서에도 적혀 있다. 그동안 runserver가 모든것을 해결 했지만, 이제는 그림에서 보이는 로직으로 구성을 해야만 한다.

     

    여기서 해당 이미지를 설명하면,

    Nginx는 클라이언트에서 1차적인 요청을 받아서 static(CSS, JS, 정적파일, 이미지 등)을 서버에 요청하는 것이 아닌 바로 전달해주는 역할을 한다.

    Gunicorn은 Nginx가 처리하지 않은 요청들을 앱서버로 연결하는 중간다리 역할을 한다. (구니콘이 runserver 역할을 대신한다.)

    Django는 App Server로 Gunicorn에서 받는 요청들을 처리하는 역할이라고 보면 쉬울 것 같다.

     

    그럼, 내가 왜 도커를 사용하면 추후에 있을 배포에서나, 서비스의 확장 등 여러가지 생각을 했을 때 편할 것이라고 생각 했기때문이다.

     

     

    우선, Django  서버가 구현이 되어 있다는 가정하에 글을 작성하려고 한다.

    1. pip freeze > requirement.txt로 설치 된 라이브러리 들을 정리하자.

     

     

    2. Dockerfile을 작성

    FROM python:3.9.13
    ENV PYTHONUNBUFFERED=1
    RUN apt-get -y update
    RUN apt-get -y install vim
    
    RUN mkdir /tuto
    ADD . /tuto
    
    WORKDIR /tuto
    
    COPY requirements.txt /tuto/
    RUN pip install -r requirements.txt

    나같은 경우 컨테이너에  tuto라는 폴더를 만들고 이곳에서 주요 기능을 처리하려고 만들었다.

     

    3. docker-compose.yml 만들기

    version: "3.9"
    
    services:
      app:
        build:
          context: . # 현재 폴더를 의미한다.
          dockerfile: Dockerfile
        image: tutorial.django # 이미지 이름을 의미한다.
        command:
          /bin/sh -c "python manage.py makemigrations --settings=tutorial.settings.prod
          && python manage.py migrate --settings=tutorial.settings.prod
          && gunicorn --bind 0:8000 tutorial.wsgi.prod:application"
        container_name: test_tuto_app # 컨테이너 이름을 의미한다.
        volumes:
          - .:/tuto # 현재 폴더와 컨테이너의 tuto와 연결 시킨다.
          - ../env:/tuto/env # 나같은 경우 동일 폴더에 가상환경이 없어서 이런 방법을 해줬다.
          - static_volume:/tuto/static # static파일을 volume으로 묶은다(이후 nginx와 연결)
          - media_volume:/tuto/media # media파일을 volume으로 묶은다(이후 nginx와 연결)
        expose:
          - "8000" # 내부에서만 접속 가능하게 함(nginx에서 접속을 하면, 이후에는 내부 8000번 포트로만 작동하기 위함)
        depends_on:
          - db    # 밑에서 설명하겠지만, postgresql 과 연결을 위해서 depends_on이 필요
    
    volumes:
      static_volume:
      media_volume:

    1차적으로 App Server인 장고를 연결하였다. 만약 정상 작동인지 확인하고 싶다면  expose 대신

    더보기

    ports:

    - "8000:8000"

    으로 변경하면 테스트가 가능 할 것으로 본다.

     

    4. docker-compose.yml 에  DB(postgresql) 추가

    version: "3.9"
    
    services:
      db:
        image: postgres:12.11-alpine
        container_name: test_db
        volumes:
          - ./data/db:/var/lib/postgresql/data # 외부의 데이터와 연결한다.
        environment:  # 환경변수는 django에서 설정한 부분을 사용하면 된다.
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: postgres
    
      app:
        build:
          context: . # 현재 폴더를 의미한다.
          dockerfile: Dockerfile
        image: tutorial.django
        command:
          /bin/sh -c "python manage.py makemigrations --settings=tutorial.settings.prod
          && python manage.py migrate --settings=tutorial.settings.prod
          && gunicorn --bind 0:8000 tutorial.wsgi.prod:application"
        container_name: test_tuto_app
        volumes:
          - .:/tuto
          - ../env:/tuto/env
          - static_volume:/tuto/static
          - media_volume:/tuto/media
        expose:
          - "8000"
        depends_on:
          - db
    
    volumes:
      static_volume:
      media_volume:

    depends_on 설정을 하지 않으면 연결 된 것을 확인 하지 못하기 때문에 꼭 설정 해주고 해당 방법도 테스트를 하고 싶으면 ports에 포트를 설정해주면 된다.

     

    여기까지 docker-compose에서 gunicorn 서버를 돌리면서 DB와 연결한 상태를 확인 할 수 있을 것이다.(내가 한번에 적고 있지만, 한 개의 컨테이너를 만들고 테스트를 해보길 바란다.)

     

    5. nginx 관련 설정 및 폴더 생성

    나같은 경우 nginx 폴더를 새로 생성했는데, 위치는

    더보기

    app

    data

    nginx

            |__ conf.d

            |.              |___ default.conf

            |      

            |__ nginx.Dockerfile

    media

    static

    ....

    동일한 위치 선상에 nginx 폴더를 만들어 주었고, 그 안에 Dockerfile과 conf.d 폴더를 다시 만들었다. 그리고 conf.d 폴더 안에 default.conf 라는 파일을 넣어주는 구조로 만들었다.

    # nginx.Dockerfile
    
    FROM nginx:latest
    
    RUN mkdir -p /static \
        && mkdir -p /media
    #default.conf settings
    
    upstream app_server {
        ip_hash;
        server app:8000; # 도커에서 설정 했던 서비스 이름과 포트 할당
        }
    
    server {
            listen       80;
            server_name  Your Domain or Static IP address;
    
            location = favicon.ico { 
                access_log off; 
                log_not_found off; 
            }
    
            location /static/ {  # Domain/static/ 으로 오는 요청을 처리하는 곳
                alias  /static/; # nginx가 있는 위치를 Domain/static/css/tttt -> /static/css/tttt로 경로를 할당해준다.
            }
    
            location /media/ {   # Domain/media/ 으로 오는 요청을 처리하는 곳
                alias /media/;
            }
    
            location / { # 도메인으로 오는 요청을 처리하는 곳
                proxy_pass http://app_server; # upstream에 선언했던 부분
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_redirect off;
                proxy_set_header Host $http_host;
        	}
    }

    이렇게 세팅을 해주면 nginx 세팅은 끝이 난다.

     

    6. docker-compose.yml에 nginx 설정 세팅

     

    version: "3.9"
    
    services:
      db:
        image: postgres:12.11-alpine
        container_name: test_db
        volumes:
          - ./data/db:/var/lib/postgresql/data # 외부의 데이터와 연결한다.
        environment:  # 환경변수는 django에서 설정한 부분을 사용하면 된다.
          POSTGRES_USER: postgres
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: postgres
      nginx:
        build:
          context: ./nginx/ # 생성한 nginx 폴더를 의미
          dockerfile: nginx.Dockerfile
        image: tutorial.nginx
        container_name: test_tuto_nginx
        ports:
          - "80:80" # nginx 설정에서 listen 80으로 설정 
        volumes:
          - ./nginx/conf.d/:/etc/nginx/conf.d/
          - static_volume:/static     # static_volume 연결
          - media_volume:/media
        depends_on:
          - app    # app이 먼저 생성 되지않으면 nginx는 에러를 발생
    
      app:
        build:
          context: . # 현재 폴더를 의미한다.
          dockerfile: Dockerfile
        image: tutorial.django
        command:
          /bin/sh -c "python manage.py makemigrations --settings=tutorial.settings.prod
          && python manage.py migrate --settings=tutorial.settings.prod
          && gunicorn --bind 0:8000 tutorial.wsgi.prod:application"
        container_name: test_tuto_app
        volumes:
          - .:/tuto
          - ../env:/tuto/env
          - static_volume:/tuto/static
          - media_volume:/tuto/media
        expose:
          - "8000"
        depends_on:
          - db
    
    volumes:
      static_volume:
      media_volume:

     

    작성을 한 후에  docker-compose up --build 하면 이미지부터 컨테이너까지 정상적으로 생성되고 작동하는 것을 확인 할 수 있을 것이다.

     

    혹시라도 작동이 되지 않거나 문제가 있으면 로그를 확인해보면 어느정도 실마리를 잡을 수 있을 것이라고 본다.

     

    나같은 경우도 컨테이너 생성은 되었지만 Django 의 static 파일 처리에서 상태코드가 200으로 오지만 적용이 안되는 경우를 확인했기 때문이다. (이 문제도 블로그에 기입을 할 예정 - 링크)

     

     

     Ref.

    https://leffept.tistory.com/345

    https://velog.io/@odh0112/Django-Nginx-Gunicorn-%EC%97%B0%EB%8F%99

    https://velog.io/@odh0112/Django-Nginx-Gunicorn-%EC%97%B0%EB%8F%99-2-fb00a9kg

    https://prohannah.tistory.com/136

    https://my-repo.tistory.com/31

    https://pajamacoder.tistory.com/m/54

    https://ko.linux-console.net/?p=6535#gsc.tab=0

    https://velog.io/@jimin_lee/%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%B0%B0%ED%8F%AC%ED%95%98%EA%B8%B0

     

     

    - 어떤 문제를 해결하기위해 검색하고 블로그에 작성한 글입니다. 부족한점이 많지만 틀린점이나 부족한점이 있다면 말씀해주시면 감사하겠습니다. 

    댓글

Designed by Tistory.