Web/Django-python

Docker-Compose 를 활용한 Django + Nginx + Gunicorn Container 구축기

Docker-Compose 를 활용한 Django + Nginx + Gunicorn Container 구축기

목차

1. 도커란?
2. Django+Python 프레임워크 튜토리얼
3. 장고, Nginx, Gunicorn 각각의 역할과 차이점
4. 본격적인 구축 시작 - Dockerfile 사용하기
5. Docker-Compose 사용하여 django와 nginx 묶어주기


1. 도커란?

도커란 VMware, Virtual Box와 같은 가상화 플랫폼 중 하나로써, 다른 가상화 프로그램들과 달리 도커는 컨테이너라고 하는 독자적인 방식을 이용하는데 , 컨테이너는 별도로 만들어진 공간에서 프로세스가 동작하는 기술로 기존 가상화 기술과는 확연한 차이를 가진다.

전 가상화 (Full-Virtualization)

완전 가상화 라고도 불리는 기존 가상화 방식인 전 가상화 방식은 OS와 하드웨어 전체를 가상화 하는 방식으로써, base가 되는 실제 컴퓨터의 Hardware 위에서 host OS가 돌아가고, 그 OS 위에서 별도의 소프트웨어를 활용해 가상의 하드웨어를 에뮬레이팅 하는 방식이다.

Hypervisor가 존재하여 guest OS 로부터의 신호 ( 주로 명령어) 등을 받아와 host os와 하드웨어가 이해할 수 있도록 번역해주는 역할을 하는데, 이는 실제 Hardware와 가상화된 하드웨어 간에 사용하는 명령어가 다를 수 있기 때문. OS와 하드웨어의 종류는 매우 많고, 종류별로 명령어를 사용하는 방법도 천차만별이므로 이 차이점을 적절히 메꿔주는 역할을 hypervisor가 수행한다고 보면 된다. 거기에 더불어 각 가상화 OS들에 리소스를 분배해주는 작업도 담당한다.

이 방식은 호스트 OS가 무엇이건 상관없이 가상화된 하드웨어 위에 guest OS가 올라가기 때문에 하드웨어, OS의 제약이 상대적으로 적은 방법이지만, 호스트 OS위에서 hypervisor와 가상 하드웨어, guest OS 가 모두 구동되기 때문에 그다지 좋은 퍼포먼스를 보여주지는 못하는 방식이기도 하다.

  • 하드웨어와 OS 전체를 가상화 하는 방식
  • Hyperviser의 역할 : guest <->Host간 명령어 번역 , 리소스 분배
  • 장 : OS,하드웨어의 제약이 적다
  • 단 : 단일 하드웨어 위에서 host os , hyperviser, 가상 하드웨어, guest os 가 모두 돌아가서 성능이 좋지않음.

​ [ 전 가상화 방식의 구조]

엄밀히 구분하자면, 전 가상화 방식과는 별개로 호스트 가상화라는 방식이 존재한다. 이 방법이 통상적으로 우리가 자주 사용하는 가상화 방식이고, VMware, Virtual box가 여기에 속한다. 여기서는 Hypervisor의 역할을 가상머신 소프트웨어가 담당한다고 보면 된다.

엄밀히 구분한 방식에서 전 가상화 방식은 호스트 가상화와 별개로 하드웨어 위에 Host OS 가 존재하지 않는다. 그러나 최근에 와서는 대부분의 전가상화를 호스트형 가상화와 혼용하여 사용하고있으므로 그냥 알고만 있으면 될것같다.

반 가상화 (Para-Virtualization)

반 가상화 방식은 완전 가상화와는 달리 하드웨어에 대한 가상화는 이뤄지지 않는 대신. Hypervisor 가 담당하던 명령어 번역 기능을 각 guest OS에 전담시키게 하는데 이를 통해 성능면에서 가해지던 부담을 대폭 줄일 수 있다. 따라서 hypervisor는 가상화 OS들에게 리소스를 분배해주는 역할만 담당하면 된다.

대신, 어찌됐든 명령어의 차이는 있기 때문에 각 가상머신이 직접 명령어를 변환하여 host에 전달해 줄 필요가 있다. 따라서 반가상화 방식에 사용될 OS들은 커널에서 해당 기능이 추가되어야 한다. 반 가상화 방식에 사용할 OS는 별도로 준비해야 한다는 의미이다. OS단에 번역기가 추가되었으니, 가상 하드웨어를 구동할 필요도 없고 hypervisor의 기능도 대폭 줄어들 수 있게 되어 가벼워졌다.

  • 하드웨어에 대한 가상화 없이 OS만 가상화 하는 방식
  • Hypervisor의 역할 : 리소스 분배 -> 가벼워져서 성능에 대한 부담 경감
  • 장 : 전 가상화방식에 비해 훨씬 좋은 성능을 보여준다
  • 단 : 이 방식의 가상화를 사용하기 위해 커널을 직접 수정한 전용 OS 를 사용해야 한다.

​ [반 가상화 방식의 구조 ]

현재에 와서는 반가상화, 전가상화를 크게 구분하지 않고 혼재하여 사용하고 있기는 하다만, 어느정도 차이점에 대한 구분은 필요하다.

컨테이너 방식

기본적인 가상화 방식을 알아보았으니, 도커에서 사용되는 Container 방식이 어떤건지에 대해 알아보자. 기본적인 가상화 방식 둘 다 성능문제는 있었고, 이를 더욱 개선하기 위해 반 가상화 방식을 기반으로 하여 프로세스를 OS에서 분격리하여 성능의 손실 없이 딱 필요한 만큼의 자원만 할당해주는 새로운 방식을 만들었는데, 이 방법이 컨테이너다.

반 가상화 방식과 거의 동일한 구조를 가지고 있는걸 알 수 있다. 하드웨어에 대한 가상화 대신, host OS에서 도커 엔진을 구동하고, 그 엔진 위에서 각각의 컨테이너, 앱들이 구동되는 형태로 사용된다.

이때 컨테이너를 만들기 위해서는 컨테이너 실행에 필요한 파일, 설정값, 그리고 결정적으로 반 가상화로 사용할 수 있게 개조된 커널 을 가진 OS 이미지가 필요하다. 즉, 이미지에는 컨테이너 구동에 필요한 모든 정보가 다 담겨있다는 의미. 도커의 경우는 저 OS 이미지를 도커 허브에서 공식, 비 공식적으로 배포하고 있으니 그걸 그대로 사용하면 된다.

반 가상화의 차이점은 도커 컨테이너 상에서는 게스트 운영체제가 돌아가고 있지 않다는 것. 컨테이너를 실행할 때 딱 필요한 프로세스만 골라서 실행되게 하는 식으로 불필요한 프로세스들이 OS단에서 돌아가는것을 막는다.

또한 도커를 도입한 서버 시스템은 docker file을 이용해 이미지를 직접 옮기지 않아도 스크립트 만으로 동일한 서버 환경을 조성할 수 있고, 이를 통한 버전관리, 기능 추가/삭제가 굉장히 유연하다 . 또한 서비스의 구축을 위해 가상머신에서 구동되는 서버 하나 혹은 여러개에서 각기 분리된 기능을 수행하는 대신, 여러개의 컨테이너를 묶는 식으로 서비스를 구축할 수 있게 된다.

요약하면, 도커에서 사용하는 컨테이너 방식은 기본적으로는 반 가상화의 구조를 따르고 있지만 성능면에서 많은 개선이 이뤄진 방식이라고 생각하면 될것 같다.


2.Django+python 프레임 워크

장고 프레임워크는 WAS(Web Application Server)의 일종으로써 웹사이트를 이용한 서비스를 구성할 때 쓰이는 파이썬 웹 프레임워크이다. 기존에 쓰이던 PHP 기반의 APM 서버나 asp 기반의 IIS 서버와는 동작 방식이나 구조에 약간의 차이점이 있지만, 서버사이드 언어를 이용해 웹 페이지를 랜더링 시켜준다는 역할은 동일하다.

장고는 기본적으로 파이썬 언어를 기반으로 하기때문에, 파이썬을 사용한다는 것 하나만으로 엄청난 장점이 있다. 파이썬의 무궁무진한 모듈과 확장성을 그대로 가져와 사용할 수 있기 때문.

MVT 아키텍쳐

장고는 장고 특유의 MVT(Model - view - Template) 아키텍쳐를 사용하는데, 이 방식은 apm이나 iis와는 다르게 약간 생소할 수도 있다. 웹 브라우저로부터 받은 요청을 다음과 같은 방식을 통해 처리하는 아키텍쳐이다.

​ [장고의 MVT 구조]

  1. 웹 브라우저로부터 URL 요청이 들어옴
  2. 해당 요청에 대해 urls.py에서 적절한 app을 찾아 app/urls.py에 연결해줌
  3. 해당 app의 urls.py는 URL 패턴에 따라 연결될 페이지를 판정하여 views.py로 넘겨줌
  4. app/view.py는 URL 패턴에 따라 호출할 Class를 지정함
  5. 지정된 Class는 자신에게 선언된 내용대로 Templates 를 가져와 해당하는 웹 페이지를 랜더함.

Model은 서비스 내에서 데이터 구조를 정의하고 데이터베이스를 관리하는 방법을 제공하는 역할을 한다.

기존의 was들이 그저 페이지 / 디렉토리 구조만으로 서비스를 운영했다면, 장고는 그에 비해서는 약간 더 복잡한 구조를 가진다고 볼 수 있다. 그러나 더 확실하게 명시되고 구분된 파일 구조를 가질 수 있어 개발/유지보수에 있어 좀 더 간편하다는 장점이 있다.

3.장고, Nginx, Gunicorn 각각의 역할과 차이점

이제 docker와 장고의 개념을 알아봤으니, 나머지 둘인 Nginx 와 Gunicorn이 어떤 역할을 하는지에 대해 알아봐야 하는데 이걸 얘기하기 위해 웹서비스가 어떻게 이뤄지는지를 구분해서 알아보자.

웹서비스의 구조

  • 정적 처리 : 클라이언트 -> (Request) -> 웹서버
  • 기본적인 동적 처리의 경우 : 클라이언트 -> (Request) -> 웹서버 -> (Request) -> WAS -> 외부 프로그램 실행(WAS에서 동작)
  • CGI를 사용하는 경우 : 클라이언트 -> Request -> 웹서버 -> CGI -> 외부 프로그램 실행(웹서버에서 동작)
  • WSGI를 사용하는 경우 : 클라이언트 -> Request -> 웹서버 -> Request -> WSGI (미들웨어) -> Requset -> WAS -> 외부 프로그램

웹 서버

  • 소프트웨어 + 하드웨어로 이루어짐.
  • 하드웨어 : 웹서버가 설치된 시스템 컴퓨터
  • 소프트웨어 : 웹 브라우저 클라이언트로부터 Requset를 받아 정적인 컨텐츠(html , css 등등)을 Response 하는 프로그램.
  • 기능 : 클라이언트의 요청에 응답을 보내는 역할을 한다.
    • 정적인 컨텐츠 제공 -> WAS 를 거치지 않고 서버의 자원을 제공한다.
    • 동적인 컨텐츠 제공을 위한 요청 전달 -> 클라이언트의 Request를 WAS에 보내고, WAS 가 처리한 결과를 전달받으면 해당 내용을 클라이언트에 Response 한다.
  • 웹서버 소프트웨어의 예) Apache, Nginx, IIS 등등

CGI - Common Gateway Interface

  • 정적으로 동작하는 웹서버를 동적으로 기능하게 만들기 위함.
  • 웹서버에 들어온 Request를 외부 프로그램과 연결하여 해당 프로그램이 그 요청을 처리하게 연결해주는 역할.
  • 들어온 요청을 연결해주는 역할만 할 뿐, 웹 서버가 외부 프로그램을 직접 실행함.
  • WAS와의 차이는 연결되는 외부 프로그램을 서버가 직접 실행하는지, WAS가 대신 실행하는지 차이.
  • -> 요청이 들어올 때 마다 서브프로세스를 fork함.
  • 따라서 WAS에 비해 다수의 요청을 처리하기에 불리하다.

WAS - Web Application Server

  • 웹서버 + CGI = WAS. 일반적으로는 웹서버와 WAS를 굳이 구분할 필요가 없음.
  • DB조회, 다양한 로직 처리등등의 동적인 컨텐츠 제공을 위해 만들어짐.
  • http/https 를 통해 컴퓨터나 장치에 애플리케이션을 수행해주는 미들웨어(소프트웨어 엔진)임.
  • 웹 컨테이너/서블릿 컨테이너 라고도 불림 -> jsp, servlet 구동 환경을 제공함.
  • 웹서버+웹컨테이너 -> 웹서버의 기능을 구조적으로 분리하여 처리하기 위한 목적.
  • ->분산처리 환경을 구성하고, 주로 DB 서버를 따로 분리하는 식으로 구성된다.
  • 예)Tomcat(Apache), JBoss(Redhat), Jeus(Tmax),, Web Sphere(IBM),Django 등

웹서버와 WAS를 구분하는 이유?

웹서버가 필요한 이유

  • 클라이언트가 서버로부터 Response를 받을때 HTML문서와 이미지 파일등의 정적 컨텐츠를 한꺼번에 받는것이 아닌, 웹 문서를 모두 받고 나면 그에 맞는 이미지 파일을 재 요청하여 받아오는 식임.
  • 이때 웹서버 프로그램이 이미지 파일 요청까지 한번에 처리해서 Response 해주면 WAS에 요청을 다시 보낼 필요가 없어짐
  • -> 웹서버가 정적 요청을 처리하면 WAS의 요청/응답 과정이 생략되어 서버의 부담을 줄일 수 있음.

WAS가 필요한 이유

  • 웹 페이지에 존재하는 동적 컨텐츠를 처리하기 위함.
  • 웹서버만을 이용한다면 동적으로 동작해야 하는 컨텐츠의 결과를 웹서버에서 모두 미리 로드해두고 클라이언트에 Response를 보내야함.
  • -> 이에 따른 자원낭비를 막기 위해 WAS를 통해 클라이언트의 요청에 맞는 컨텐츠를 그때 그때 제공할 수 있음.

기능을 분리하는 이유

  • 서버의 부하 방지 : 두개의 서버 프로세스가 별개의 작업을 처리하게끔 하여 동적 데이터를 처리하기 위해 상대적으로 바쁜 WAS에 가해지는 부하를 줄인다.
  • 정적컨텐츠는 대체로 처리량이 많은 멀티미디어 컨텐츠가 많기 때문에 해당 요청까지 WAS가 처리하면 부하가 커지게 된다.
  • 물리적으로 두 서버를 분리하여 보안을 강화한다.
  • 대용량의 처리를 필요로 하는 웹 서비스의 경우는 웹서버 하나에 여러개의 WAS를 분산하여 연결할 수 있다.
  • 백사이드/프론트사이드로 분리한 WAS를 연결하면 무중단 운영이 가능해진다.
  • 하나의 웹 서비스에서 여러개의 어플리케이션 서비스가 가능해진다. (예-서버 하나에서 PHP와 Java 어플리케이션 동시 제공 가능.)

WSGI - Web Server Gateway Interface

  • 웹서버와 웹 어플리케이션간 인터페이스를 제공하는 파이썬 프레임워크.
  • -> 파이썬 스크립트(혹은 웹 어플리케이션)이 웹 서버와 통신하기 위한 인터페이스라는 소리. (일종의 프로토콜)
  • 서버|게이트웨이 , 어플리케이션|프레임워크 양단으로 나눠진 구조.
  • 웹서버와 WAS 사이에서 미들웨어로써 동작하며, 웹 서버의 관점에서는 WAS 처럼, WAS 관점에서는 서버처럼 동작한다.
  • 다수의 클라이언트에서 전해지는 Request들을 동시에 처리하기 위해 사용함.
  • -> CGI와는 다르게 Request 마다 서브프로세스를 만들지 않음.
  • 웹서버로부터 들어온 요청을 처리하는데, 환경정보와 요청에 대한 콜백 함수 등을 파싱하고 정리하여 WAS에 제공하고, WAS은 해당 요청을 처리하고 콜백 함수를 통해 웹서버로 응답함.
  • 같은 프로세스에서 다수의 애플리케이션과 프레임워크들을 실행시킴.

정리하자면,

  • WAS는 웹서버와 외부프로그램을 연결하는 미들웨어이고, WSGI는 WAS가 파이썬 프로그램과 연결되는 경우에 웹서버와 WAS를 연결하는 미들웨어 역할을 한다고 생각하면 된다.
  • CGI 방식은 웹서버와 외부프로그램을 직접 연결시켜 웹서버 위에서 외부 프로그램이 실행되는 방식이다.
  • WAS 방식은 외부 프로그램을 웹서버와 분리시키고 WAS라는 별개의 서버 위에서 실행되게 한다.
  • 따라서 Django, Nginx, Gunicorn을 이용한다고 하면 Django 는 WAS, Nginx는 웹서버, Gunicorn은 WSGI가 되겠다.

4.본격적인 구축 시작 - Dockerfile 활용하기

Docker는 dockerfile 을 이용해 이미지 이용한 서버 환경을 빠르고 간편하게 구축할 수 있다 . 컨테이너에 필요할 패키지들이나 사전 정의 명령어, 프로세스 실행등을 이 파일에 미리 정의해서 사용하면 된다.

#docker build --no-cache --network=host -t durumi .
#docker run -it --net host --name durumi durumi /bin/bash
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y python3.6=3.6.9-1~18.04
RUN apt-get install -y python3-pip=9.0.1-2.3~ubuntu1.18.04.1
RUN apt-get install -y net-tools 
RUN apt-get install -y dnsutils
WORKDIR /home/durumi
RUN pip3 install pip==20.0.2
RUN pip3 install django==3.0.4
RUN pip3 install gunicorn==20.0.2

#RUN django-admin startproject mysite

위와같이 필요한 패키지등과 버전을 명시하여 세팅하면 끝. 빌드하면 해당 내용을 가지고 있는 이미지가 만들어지고, 만들어진 이미지를 컨테이너로 RUN 하면 된다.


5.Docker-Compose 사용하여 django와 nginx 묶어주기

dockerfile은 하나의 컨테이너를 만들어 환경을 구축한다고 하면, docker-compose는 여러개의 컨테이너를 묶어서 서비스를 구축한다고 생각하면 된다.

Django + Nginx + Gunicorn을 한꺼번에 사용하는 서비스를 만드려면 어떻게 해야할까?

docker를 사용하지 않는다면 하나의 가상 환경을 구축하여 저 패키지들을 각각 설치해서 쓸테고, docker를 쓴다 하더라도 하나의 컨테이너에 모두 모아서 할수도 있을거다.

그러나, 도커와 컨테이너는 그렇게 쓰라고 있는게 아니다. 여러개의 컨테이너로 프로세스들을 분산하여 이를 묶어서 쓰는것을 권장하고 있고, Docker-compose를 이용하면 이 작업을 훨씬 간편하게 처리할 수 있다.

#첫 빌드시 : docker-compose up --build
#이후 : docker-compose up
# 방화벽 설정으로 실행 안될때 iptables 초기화 
# sudo iptables -t filter -F && sudo iptables -t filter -X && sudo systemctl restart docker
version: "2"
services:
  durumi:
#    build : 
#     context : . 
#     dockerfile : Dockerfile
    image: durumi
    container_name : durumi_service
    volumes: 
      - /home/synod2/synod2/durumi/workspace/volumes:/home/
    working_dir : /home/durumi/
    command: > 
      bash -c "python3 manage.py makemigrations polls
      && python3 manage.py makemigrations apitest
      && python3 manage.py migrate   
      && python3 manage.py collectstatic --noinput
      && gunicorn durumi.wsgi -b 0.0.0.0:8000 "
#      && python3 /home/durumi/manage.py runserver 127.0.0.1:8000 "
#      && gunicorn durumi.wsgi -b 0.0.0.0:8000 "
    ports: 
      - "8000:8000"
    expose : 
      - "8000"
  nginx:
    image: nginx
    container_name : nginx_service
    volumes: 
      - /home/synod2/synod2/durumi/workspace/volumes-nginx:/etc/nginx/conf.d
      - /home/synod2/synod2/durumi/workspace/volumes/.static_root/:/static
    ports:
      - "80:80"
    depends_on : 
      - durumi

구조는 간단하다. 장고가 돌아갈 durumi 컨테이너와 nginx 가 돌아갈 컨테이너를 각각 만들고 두개를 묶어서 쓸 수 있게끔 도움울 줌과 동시에, 컨테이너 외부에서 개발환경을 구축하기 쉽게끔 로컬 디렉토리를 마운트하여 쓸 수 있게끔 문법을 제공하니 제공해주는 대로만 잘 만들어주면 된다.

django + Nginx 환경에서의 static file serve

이때의 주의사항이 있는데, 장고는 기본적으로 CSS나 이미지파일과 같은 정적파일(랜더를 하지않는) 로드를 static이라는 경로에 따로 모아놓고 진행을 한다.

따라서 실제 서비스 환경에서는 CSS나 이미지를 비롯한 정적 파일들을 해당 경로에 모아놔야 정상적으로 로드가 되는데, 장고에서는 runserver 실행시 필요한 static 파일들을 /static/ 이라는 하위경로에 자동으로 모아줘서 장고만 쓸때는 크게 문제가 없다. 서버가 실행되면 /static/ 경로를 참조하면 그만이니까.

근데 nginx를 쓸때는 그렇지 않다. nginx에서 로드할 파일들 목록에 static은 포함이 안되있어서 참조를 못하고, nginx에서 static을 참조를 못하니까 장고에서도 static을 못불러온다.

그래서 nginx에서도 static 파일을 모아올 수 있게끔 수동으로 내용들을 모아줘야한다. 이때 사용하는 명령어가 collectstatic 명령어. 해당 프로젝트 내에서 사용할 static 파일들을 수동으로 모아서 특정 디렉토리로 모아준다.

settings.py

~~~
import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
ROOT_DIR = os.path.dirname(BASE_DIR)

STATIC_URL = '/static'
STATIC_DIR = os.path.join(BASE_DIR,'static')
STATICFILES_DIRS = [
    STATIC_DIR,
    ]

STATIC_ROOT = os.path.join(ROOT_DIR,'.static_root')
~~~

프로젝트의 메인앱이 있는 디렉토리에 settings.py 파일을 위와 같이 수정한다.
static 파일이 모일 경로는 컨테이너 내에서는 /home/프로젝트/ 하위에 생기고, 로컬에서는 /volumes/프로젝트/하위에 생긴다.
.static_root 파일이 모일 경로는 컨테이너 내에서는 /home/ , 로컬에서는 /volumes/ 에 생긴다.

이후 python3 manage.py collectstatic 명령어를 실행해주면 .static_root 디렉토리에 수동으로 파일들을 모아준다.
이러면 이제 nginx 에서 접근할 수 있게 설정을 만들어주면 된다.

docker-compose.yml

~~~
nginx:
    image: nginx
    container_name : nginx_service
    volumes: 
      - /home/synod2/synod2/durumi/workspace/volumes-nginx:/etc/nginx/conf.d
      - /home/synod2/synod2/durumi/workspace/volumes/.static_root/:/static
    ports:
      - "80:80"
    depends_on : 
      - durumi

~~~

docker-compose 파일의 nginx 설정 관련 부분이다. 원래라면 volumes-nginx 에서 가져오는건 conf.d 파일뿐이겠지만, static 파일들을 nginx 컨테이너에 포함시켜야 제대로 인식이 가능하게 되므로, durumi의 볼륨인 volumes의 하위에 있는 .static_root 를 가져와 nginx 컨테이너에 포함시켜주자.

이제 마지막으로, nginx에서 아까 컨테이너로 가져온 .static_root 파일을 인식할 수 있게 해주자.

nginx.conf

upstream durumi {
    ip_hash;
    server durumi:8000; # 서버의 컨테이너 명
}

server {
    location / {
        proxy_pass http://durumi/;
  }

    location /static/ {
        alias /static/;
    }
    listen 80;
    server_name localhost;
}

추가해준건 location /static/ 부분. 컨테이너 내 /static/ 디렉토리를 가져와서 /static/ 이라는 이름으로 사용할 수 있게 지정해주자.

이렇게까지 하고 나면 이제 장고에서 적용해주는 css 를 비롯한 정적 파일들이 제대로 보인다.


지금까지가 Docker 상에서 Django + Nginx + Gunicorn을 묶어서 구동하기 위한 서버 구축기였다. 공모전용으로 진행하는 프로젝트를 공교롭게도 장고로 하게되어 예전에 공부했었던 내용에 더불어 추가적으로 공부를 하면서 작업을 진행했다.

장고는 상대적으로 다른 WAS나 프레임워크들에 비해 잘 정리된 한국어 자료가 적은 편이라, 해외 자료들을 뒤져가면서 서버를 구축했고 문서를 써봤다. 앞으로 개발하는것도 고생길이 훤해보이긴 하다..

이미지 출처

전 가상화 방식 : https://www.researchgate.net/figure/The-Architecture-of-Full-Virtualization_fig1_326440834

반 가상화 방식 : https://www.researchgate.net/figure/The-Architecture-of-Para-Virtualization_fig2_326440834

장고 MVT 구조 : https://developer.mozilla.org/ko/docs/Learn/Server-side/Django/Introduction