본문 바로가기

회고록(TIL&WIL)

TIL 2022.08.30 Gunicorn, nginx

nginx

웹서버의 한 종류로 네트워크 신호를 받아서 다양한 기능을 처리함, 로드밸러서를 만든다던지, 프록시 등 있으나 대표적으로 정적파일들을 불러와 WSGI에 전달해줌으로써 django에서 파일 파일 처리를 할 필요가 없어지므로 효율이 높아진다.

Gunicorn(WSGI web server gateway interface)

들어온 네트워크 신호를 파이썬으로 바꿔주는 역할

웹서버와 어플리케이션을 이어주는 역할

1. 설치

pip install gunicorn

2. docker-compose.yaml 파일에서 command 변경

command: gunicorn SMOPS_PARC.wsgi:application --bind 0.0.0.0:8000

이렇게 하면 프로젝트명으로 된 폴더 안에 wsgi.py 파일이랑 연결을 시켜 주는 것

 

*최초 wsgi 연결 시 프로젝트의 폴더 중 static 폴더에 직접적으로 연결이 되지않기 때문에 css, 이미지등이 깨지게 된다.

우선 settings.py에서 static 경로를 지정해주어야한다.

STATIC_ROOT = BASE_DIR / "static"
STATIC_URL = "/static/"

그리고 url.py 에서도 static url이 잘적용되도록 작성해주어야한다.

...
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
...      
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

그리고 다시금 docker를 build 해주면 된다.

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

도커 환경에서 서버를 실행하고 개발을 진행 하기 위한 세팅을 위해 dotenv 추가 및 코드 변경

각 SECREAT_KEY 와 DEBUG에 default 값을 줌으로써 로컬에서 runserver로도 개발할 수 있게 설정

각각 prod 환경과 dev 환경으로 구분하기위해 기존의 파일을 그대로 복사하여 이름 변경

(기존의 .env도 .env.dev로 바꿔줘야하는데 바꾸지 않을경우 이후에 docker-compose시 우선순위로 설정되기때문에 변경해줘야만 한다)

.env.prod  .env.dev   //  .env.postgres.prod  .env.postgres.dev 파일 각각 생성한 뒤

prod 환경에서는 DEBUG='0' 코드 추가하여 디버그를 꺼주고 dev 환경에서는 DEGUB='1' 코드 추가하여 디버그 켜기

# settings.py
...

# SECURITY WARNING: keep the secret key used in production secret!
# SECRET_KEY = os.environ.get('SECRET_KEY')
SECRET_KEY = os.environ.get('SECRET_KEY', "somesecreat")
# =====================================================

# SECURITY WARNING: don't run with debug turned on in production!
# DEBUG = True
DEBUG = int(os.environ.get("DEBUG", 1))

...

디버그모드를 껏을 경우 추가로 설정을 해줘야만 하는데 설정하지 않을 경우 400 Bad Request 가 발생한다.

settings.py 에서 ALLOWED_HOSTS 를 아래 처럼 변경해주고 .env에도 상수 추가필요

// settings.py
...
if os.environ.get('DJANGO_ALLOWED_HOSTS'):
    ALLOWED_HOSTS = os.environ.get('DJANGO_ALLOWED_HOSTS').split(' ')
else:
    ALLOWED_HOSTS = []
...
# .env.prod
DJANGO_ALLOWED_HOSTS = localhost 127.0.0.1

변경한 파일명에 맡게 docker-compose.yml 파일 내용 변경

...
env_file:
  - ./.env.prod
...
env_file:
  - ./.env.postgres.prod
...

docker-compose build 시 volume을 생성이 되어있는지 여부를 체크해줘야한다. 기존의 볼륨을 지워줘야 정상적으로 build가 된다.

 

docker-compose.yml 에서 nginx 서비스 작성

services에 nginx 서비스를 추가로 작성하였고 생선한 volumes 들을 아래쪽의 web서비스 부분과 volume에 추가해줌

 

version: "3.8"
# ㄴ 사용하는 docker-compose 버젼

services: # 추가할 서비스들 web, db, nginx
  nginx:
    build: ./nginx
    volumes:
      - static_volume:/usr/src/app/static
      - media_volume:/usr/src/app/media
    ports:
      - 80:80
    depends_on:
      - web
  web: 
    build: .
    # ㄴ . 을 써서 현재폴더에 있는 도커파일로 빌드를 하겠다.
    # command: python manage.py runserver 0.0.0.0:8000
    command: gunicorn SMOPS_PARC.wsgi:application --bind 0.0.0.0:8000
    # ㄴ 사용하는 커맨드
    ports: # 포트 맵핑
      - 8000:8000
    working_dir: /usr/src/app/
    volumes: # 바인딩 볼륨
      - ./:/usr/src/app/
     # ㄴ 현재 폴더(.)를 /usr/src/app/ 에 바인딩 
      - static_volume:/usr/src/app/static
      - media_volume:/usr/src/app/media
    expose:
      - 8000
    env_file:
      - ./.env.prod
      # ㄴ 현재 폴더(.)의 .env 파일로 환경변수 설정
    depends_on:
      - db
  db:
    image: postgres:14.4-alpine
    volumes:
      - postgres_db:/var/lib/postgresql/data
    env_file:
      - ./.env.postgres.prod
    ports:
      - "5432:5432"


volumes:
  postgres_db:
  static_volume:
  media_volume:

nginx 폴더 생성 후 nginx.conf 파일 생성하여 코드 작성

# nginx/nginx.conf

upstream SMOPS_PRAC {
    server: web:8000;
    # ㄴ 내부에서 nginx와 gunicorn이 통신할 떄 쓰이는 포트번호
}

server {
    listen 80;
    # ㄴ 외부와 통신할 때 쓰이는 포트
    location / {
        # nginx에서 쓰는 default 세팅
        proxy_pass http://SMOPS_PRAC;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
    # nginx에서 정적파일들을 미리 가져올 수 있도록 설정
    location /static/ {
        alias /usr/src/app/static/;
    }
    location /media/ {
        alias /usr/src/app/media/;
    }
}

nginx폴더에 dockerfile 생성 하여 코드 작성

FROM nginx:1.220.alpine
RUN rm /etc/nginx/conf.d/default.conf
# ㄴ 실행 시 디폴트 파일 제거
COPY nginx.conf /etc/nginx/conf.d

이후 docker desktop 확인해서 떠있는 container나 volume 정리 후

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

메인페이지를 안만들었다면 접속 시 Bad Request가 아닌 Not found가 뜨면되고 admin 페이지가 접속 안되는 경우는 migrate를 안했을 가능성이 높기 떄문에 docker-desktop에서 터미널로 접근해서 migrate를 해주면 된다.

추가로 python manage.py collectstatic 을 해줌으로써 static 파일을 모아줘야한다.

 

+ nginx에서 돌아가는 log 확인 방법

nginx의 log들을 자동으로 docker logs에 저장해둔다.

docker logs [container_name]

docker-desktop에서 있는 이름은 진짜이름이 아니고
docker ps 커맨드를 통해서 진짜 이름을 확인해서 입력해주어야함

docker logs [container_name] -f

-f 플래그를 달아주면 실시간으로 follow할 수 있다.