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들이 쌓이는 것을 보니 뿌듯한 마음도 있습니다!!
안정적으로 정상화가 되면 단위 테스트 및 버전 관리가 더 쉬워질거라 믿습니다 ㅎㅎ
모두들 화이팅입니다!!
Author And Source
이 문제에 관하여(Docker, Django + Nginx + uwsgi 로컬서버에서 배포 진행), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@yh20studio/Docker-Django-Nginx-uwsgi-로컬서버에서-배포-진행저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)