Docker, Django + Nginx + uwsgi 로컬서버에서 배포 진행

이번 글에서는 docker에서 django + nginx + uwsgi 조합으로 돌아가고 있는 웹사이트의 구성을 실행해보려고 합니다.

AWS ec2에서 우분투 환경으로 돌아가던 서버를 docker로 관리 및 운영하기 위해서 docker를 위한 배포를 연습중입니다. 설치 및 container 기초에 대해서 궁금하시다면 이전 글을 참고 해주세요!

우선 저번 글에서 django 서버를 manage.py runsever를 통해서 로컬호스트로 구현을 해보았습니다. 하지만 실제 배포를 위해서는 uwsgi및 nginx를 이용해야합니다.

  • uwsgi를 쓰는 이유
    django의 공식 문서에의 runserver의 글입니다.
    django에서는 runserver를 통해 개발 및 테스트를 합니다.
    (https://docs.djangoproject.com/en/2.2/ref/django-admin/#runserver)

  • nginx를 쓰는 이유
    uwsgi만 이용하게 된다면 https를 위한 인증서 관리가 힘들뿐더러 static file에 대한 요청을 처리하기 힘듭니다. 또한 nginx를 통한 요청으로 성능이 더 좋아진다고 합니다.

nginx가 수행하는 일

  • 도메인 라우팅을 관리합니다 (리버스 프록시).
  • 정적 파일 제공
  • 한 번에 들어오는 많은 요청을 처리
  • 느린 클라이언트 처리
  • 동적 요청을 wsgi에 전달
  • SSL (https)
  • Python 코드와 비교하여 컴퓨팅 리소스 (CPU 및 메모리) 절약
  • 로드 밸런싱, 캐싱 등

uwsgi가 수행하는 일

  • 작업자 프로세스 / 스레드 풀 실행 (코드 실행)
  • Nginx에서 들어오는 요청을 UWSGI와 호환되도록 번역
  • 앱의 UWSGI 응답을 적절한 http 응답으로 변환
  • 요청이 들어오면 실제로 파이썬 코드를 호출합니다.

출처: https://uiandwe.tistory.com/1268 [조아하는모든것]

로컬호스트 배포연습

django + uwsgi + nginx 조합으로 docker로 배포를 하기 위해서는 우선

django 컨테이너 및 이미지가 있다는 가정하에 nginx의 이미지를 생성해야한다.

프로젝트 directory에 nginx라는 폴더를 하나 새로 생성하고

nginx - Dockerfile

FROM nginx:latest

COPY nginx.conf /etc/nginx/nginx.conf
 
COPY letter.conf /etc/nginx/sites-enabled/
 
CMD ["nginx", "-g", "daemon off;"]

nginx.conf

user root;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
}
http {

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    types_hash_max_size 2048;
    client_max_body_size 256M;
    proxy_connect_timeout   10;
    proxy_send_timeout      15;
    proxy_read_timeout      20;
    # server_tokens off;

    server_names_hash_bucket_size 64;
    # server_name_in_redirect off;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;

    ##
    # Logging Settings
    ##
    access_log /log/access.log;
    error_log /log/error.log;

    ##
    # Gzip Settings
    ##

    gzip on;

    # gzip_vary on;
    # gzip_proxied any;
    # gzip_comp_level 6;
    # gzip_buffers 16 8k;
    # gzip_http_version 1.1;
    # gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    ##
    # Virtual Host Configs
    ##
    include /etc/nginx/sites-enabled/*.conf;
}

다음으로 nginx.conf를 만들어주었다. 기존에 사용하던 설정이며, docker로 전환하면서 log파일을 container에 저장할 수 없기 때문에 경로를 다시 지정해주었다.

letter.conf

server {
    listen 80;
    server_name localhost;
    location / {
        uwsgi_pass        unix:///srv/letter_web/letter.sock;
        include           uwsgi_params;
    }
    location /static/ {
        alias /static/;
    }
}

다음과 같이 letter.conf 파일을 만들어주고 해당 글은 localhost에서 배포를 실험해보는 것으로 sever_name이 localhost이지만 실제 배포를 할때는 도메인이 들어가는 것이 맞다. 해당 서버네임으로 요청이 들어온다면 uwsgi를 통해서 파이썬 코드를 실행하는 과정이다.

해당 파일을 nginx의 /etc/nginx/sites-enabled/ 로 복사해주고 nginx의 설정에서 include /etc/nginx/sites-enabled/*.conf; 다음과 같이 추가하여 서버설정을 완료했다.

uwsgi

[uwsgi]
chdir = /srv/letter_web
module = letterproject.wsgi:application

socket = /srv/letter_web/letter.sock 

enable-threads = true
master = true
vacuum = true

logto = /log/@(exec://date +%%Y-%%m-%%d).log
log-reopen = true

ignore-sigpipe = true
ignore-write-errors = true
disable-write-exception = true

post-buffering = 8192
processes = 1
threads = 2
no-orphans = 1
thunder-lock = true

서버 프로젝트 폴더 안에 uwsgi라는 폴더를 생성 후 uwsgi.ini 파일을 다음과 같이 만들어 주었다. 여기서 중요하게 보아야할 것은 socket의 경로설정이다!! 실제로 해당 글을 작성하면서 연습을 해볼때 이 경로 설정이 안맞아 socket 파일을 찾지 못해 웹사이트에 접속을 못하는 에러를 계속 겪었다...

django

django의 Dockerfile 도 수정이 필요하다. 원래는 python3 manage.py runserver로 서버를 실행했지만 이제는 uwsgi를 통해서 돌려야하기 때문이다.
우선 pip3 install uwsgi를 통해서 패키지를 설치해주고 requirement.txt에 저장해준다.

FROM python:3.7.7
# python 3.7.7 버전의 컨테이너 이미지를 base이미지

ENV PYTHONUNBUFFERED 1

LABEL yh Bang <[email protected]>
# Docker의 컨테이너를 생성 및 관리 하는 사람의 정보를 기입해줍니다.

RUN pip3 install django
# python:3.7.7 이미지 상에 django를 pip를 통해 설치합니다.

RUN mkdir /srv/letter_web

WORKDIR /srv/letter_web
# CMD에서 설정한 실행 파일이 실행될 디렉터리를 지정해주어야 한다.

COPY ./requirements.txt ./            

RUN pip3 install -r requirements.txt  

COPY . .

CMD ["uwsgi", "--ini", "uwsgi/uwsgi.ini"]
# uwsgi로 실행할 수 있도록 cmd 교체

EXPOSE 8000

uwsgi --ini uwsgi/uwsgi.ini 해당 코드로 uwsgi 폴더에 있는 uwsgi.ini 파일로 uwsgi 패키지로 서버를 실행시켜줍니다.

Docker-compose

지금까지 django, nginx, uwsgi 의 준비가 끝났다면 해당 이미지와 컨테이너들을 한번에 묶어서 실행할 수 잇는 docker-compose가 필요합니다.

docker-compose 가 무엇이냐? 하면 쉽게 말해서 여러가지 컨테이너를 묶어서 한번에 실행을 할 수 있도록 도와주는 툴이라고 생각하시면 됩니다. docker를 설치했다면 따로 부가적인 설치가 없이 사용할 수 있는 툴입니다.

# docker-compose.yml

version: "3"
services:
  django-web:
    container_name: django-web
    image: 20studio/letterproject-test:1.0.0 # 이미지, 태그
    ports:
        - "8000:8000"
    build: ./letterproject
    volumes: 
        - ./letterproject:/srv/letter_web
        - ./log/uwsgi:/log
  nginx:
    container_name: nginx
    image: nginx
    ports:
        - "80:80"
    build: ./nginx
    volumes:
        - ./letterproject:/srv/letter_web
        - ./log/nginx:/log
        - ./.static_root:/static
    depends_on : 
        - django-web

폴더 내에 docker-compose.yml 파일을 생성해줍니다.
이는 django-web 컨테이너와 nginx 컨테이너를 한번에 묶어서 실행시켜주는 역할을 합니다. 이때 이미지 및 포트 설정은 원하시는 대로 하면 됩니다. 중요한 것은 volumes 설정인데 상대경로를 지정할 수 있도록 해서 편합니다.

예를들어서 ./letterproject:/srv/letter_web 라고 작성한 코드에서
django-web 컨테이너에서는 /srv/letter_web이라고 작성한 경로들이 실제로는 ./letterproject의 경로에서 파일을 찾으면 된다는 것입니다!!

이를 이용해서 nginx에서 static file의 root를 편하게 관리해줄수 있다는 점이 좋은 것 같습니다 --> django는 서버 배포시에 static file을 찾지 못하기 때문에 경로 지정을 해주어야합니다!!

python3 manage.py collectstatic

해당 코드를 이용해서 staticfile을 지정한 곳에 모은 후

nginx에 요청이 들어온 경우 사이트에 대한 요청은 uwsgi의 socket으로, static file에 대한 요청은 특정 static_root로 보내주어야 웹사이트에서 static 파일을 인식할 수 있게 됩니다. 해당 사항에 대해서는 더 자세하게 다른 글에서 다뤄보도록 하겠습니다!!

설정이 다 끝났다면

docker compose up

를 입력하면 image와 container를 생성하는 시간이 지난 후
localhost로 접속하면 화면이 정상적으로 뜨는 것을 확인할 수 있을 겁니다!!

기존에 배포되고 있는 웹사이트를 docker를 통해서 다시 관리를 하려고하니 힘든점이 많지만 그래도 docker내에 정상적으로 작동하는 image들이 쌓이는 것을 보니 뿌듯한 마음도 있습니다!!

안정적으로 정상화가 되면 단위 테스트 및 버전 관리가 더 쉬워질거라 믿습니다 ㅎㅎ

모두들 화이팅입니다!!

좋은 웹페이지 즐겨찾기