소개

Django는 우리가 웹사이트를 구축하기 쉽도록 도와주는 파워풀한 웹 프레임워크이다. Django는 개발 시 사용할 수 있는 간단한 웹서버를 탑재하고 있어, 로컬에서 코드를 테스트해 볼 수 있다. 그러나 실제 운영 서버에서 사용하거나 더 향상된 보안을 위해서는 웹서버가 필요하다.

이번 가이드에서는 운영 서버 환경에 Django Virtual 환경을 어떻게 설치/구성하는지 살펴본다. Apache 서버를 이용해 프론트 애플리케이션을 핸들링하고 클라이언트의 요청을 Django app에 보내는 방법을 살펴볼 것이고, 이것은 mod_wsgi라는 Apache 모듈을 이용하여 Django와 Apache와의 커뮤니케이션이 가능하도록 설정할 것이다.

사전 지식 및 목표

이 가이드에서는 Ubuntu 14.04 서버를 이용할 것이고 non-root 유저를 사용하여 sudo 권한으로 설정할 것이다. Ubuntu 서버는 Azure나 AWS를 이용해 쉽게 생성 가능하다.
우리는 Django를 python 가상환경을 사용하여 설치할것이다. 가상환경은 우리의 프로젝트에 필요한 패키지를 격리된 환경에 설치 할 수 있도록 도와준다.

Django app을 Apache 인터페이스에 설정하기 위해 mod_wsgi라는 Apache 모듈이 필요하다.

Ubuntu repository를 이용한 패키지 설치

첫 단계로 우리는 필요한 것들을 Ubuntu repository를 이용해 다운로드하고 설치 할 것이다. Apache web Server, Apache를 Django App과 연결하기 위한mod_wsgi 모듈 그리고 우리 프로젝트에 포함된 python 패키지를 다운로드하기 위한 패키지 매니저인 pip가 필요하다.

우리는 Python3을 사용하므로 다음 명령어로 설치한다.

1
2
sudo apt-get update
sudo apt-get install python3-pip apache2 libapache2-mod-wsgi-py3

이 명령어로 Python3 pip, apache2, mod_wsgi 모듈까지 설치 할 수 있다.

python 가상환경 설정

Ubuntu 리파지터리를 이용해 필요한 컴포넌트를 설치함으로써 Django 프로젝트를 시작 할 수 있는 준비가 되었다.
첫단계로 python 가상환경을 만들어보자. 이렇게 함으로써 우리 프로젝트가 다른 프로젝트나 설정에 영향 받지 않고 독립적인 실행이 가능하게 된다.

python 가상환경을 생성하기 위한 virtualenv 라는 커맨드를 pip이용하여 설치한다.

1
sudo pip3 install virtualenv

virtualenv를 설치했으면 우리 프로젝트를 git repository를 통해 clone 한다.

1
2
sudo apt-get install git
git clone https://github.com/xxxx/xxxx.git

clone 받은 프로젝트 디렉터리로 이동하여 가상환경을 만든다.

1
2
3
4
5
6
7
8
virtualenv myenv
```

`myenv`는 임의로 정한 가상환경의 이름이다. 이 명령어로인해 anchvy 디렉터리 안에 `myenv`라는 디렉터리가 생성된다. 이 디렉터리안에는 우리가 사용할 python과 pip가 설치된다. 우리는 이것을 이용하여 격리된 python 환경에서 우리 프로젝트를 실행 할 수있다.

그럼 python 가상환경으로 들어가 보자.
```bash
source myenv/bin/activate

가상환경으로 진입하면 쉘의 앞부분에 가상환경이름이 표시된다.

1
(myenv) crynut84@anchovy-web:~/anchovy$

python 패키지 설치

우리 프로젝트는 requirements.txt 파일에 python 패키지의 종속성이 표기 되어있다.
가상환경 내에서 이를 이용하여 패키지를 설치해 보자.

1
(myenv)$ pip install -r requirements.txt

pip는 requirements.txt에 기록된 패키지를 python 가상환경내에 설치 해 줄 것이다.
이를 확인하려면 myenv안의 폴더를 뒤져보면 된다.

프로젝트 설정 마무리

개발한 프로젝트를 운영환경(Production)에서 돌리려면 몇가지 설정을 해야한다. 디버깅을 위해 설정했던 기능을 꺼주어야하고, 프로젝트내에 포함된 스테틱 컨텐츠(css, jaavascript, image 등)를 한데모아 통합하는 일, 그리고 디비의 설정을 실제 디비로 바꿔주는 일등이 있다.

다음의 명령어로 프로젝트의 스테틱 파일을 한데 모을 수 있는데, 저 명령어를 수행하고 나면 settings.py의 STATIC_ROOT 경로로 파일이 모이게 된다.
왜 스테틱 파일을 모아야하는지는 다음 설명(Django static)을 참조한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python manage.py collectstatic
```

프로젝트의 `settings.py`를 열어(vi XXX/settings.py) DB설정을 실서버로 변경한다. (이부분은 향후 자동화하는 방법이 필요하다.)

```javascript
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': '{DB_NAME}',
'USER': '{DB_USERNAME}',
'PASSWORD': '{DB_PASSWORD}',
'HOST': '{DB_HOST_ADDRESS}',
'PORT': '3306'
}
}

그리고 pip를 통해 mysql에 접속하는 python 모듈인 mysqlclient를 설치한다.

1
pip install mysqlclient

이 경우 Azure Ubuntu에서 mysql_config: not found 오류가 발생한다
sudo apt-get install libmysqlclient-dev을 먼저 설치 후 다시 mysqlclient를 설치하면 된다.

DEBUG 모드가 아니므로 DEBUG 속성을 False로 수정하고, 모든 클라이언트 요청을 처리하기위해 settings.pyALLOWED_HOSTS 속성을 수정한다.

1
2
DEBUG = False
ALLOWED_HOSTS = ['*']

Apache 설정

우리 Django 프로젝트를 Apache와 연결시키는 방법을 알아보자. Apache는 클라이언트의 요청을 WSGI 포맷으로 변경하여 Django 어플리케이션으로 전달해야하는데 이 작업을 mod_wsgi 모듈이 담당한다. 이 설정은 아까 설치할때 이미 활성화되어있다.
위 경로의 apache 설정을 수정한다.

1
sudo vi /etc/apache2/sites-available/000-default.conf

image

우선 static file의 경로 설정을 한다. 그 다음 wsgi 경로 설정. 그 후 python 경로설정과 virtual 환경 설정을 한다.

ref.

https://www.digitalocean.com/community/tutorials/how-to-serve-django-applications-with-apache-and-mod_wsgi-on-ubuntu-14-04

Comment and share

우리가 개발한 프로젝트를 운영 서버로 배포하다 보면 static 파일을 한데 모으는 python manage.py collectstatic이란 명령어를 접하게된다.
collectstatic 명령어는 Django 프로젝트의 여러 app에서 사용하는 스테틱 파일을 한 곳(경로)으로 모아주는 역할을 한다.(물리적으로 파일을 copy 한다는 뜻이다)

웹 서버와 웹 어플리케이션

Django를 이용하여 웹 애플리케이션 개발할 때 Django에 내장된 경량의 웹서버를 사용하게 된다. 하지만 공식문서에도 경고하고 있는것처럼 이것은 실제 웹서버가 아니므로 Production 환경에서는 사용해서는 안 된다.

don’t use this server in anything resembling a production environment. It’s intended only for use while developing. (We’re in the business of making Web frameworks, not Web servers.)

프로덕션 환경과 유사한 상황에서는 사용하면 안 된다. 오직 개발 중에만 사용해라.(이건 웹 프레임워크를 만들기 위한 것이지 웹서버가 아니다.)

그렇다! runserver로 사용하는 개발용 서버는 서버가 아니다. 실제 Production 환경에서는 ApacheNginx와 같은 웹서버를 사용해야 한다. 즉 사용자의 요청(Request)이 들어오면 웹서버가 받아서 적절한 처리 후에 웹 애플리케이션에 넘겨주고 웹 애플리케이션은 우리가 작성한 로직에 따라 적절한 처리 후에 웹서버에 돌려주어 사용자에게 응답(Response)하는 것이다.

image

이것을 간단하게 도식화하면 위의 그림과 같은데 웹서버와 웹 애플리케이션 사이에는 WSGI(Web Server Gateway Interface)라는 규약으로 통신하게 된다.

스테틱 파일을 모으는 이유?

HTTP 프로토콜을 이용하여 단순히 파일을 응답하는 처리는 웹서버가 잘하는 일이다. 사용자의 요청의 URL을 해석하여 서버 내의 물리적인 위치의 파일을 찾아 HTTP 응답으로 돌려주는 단순한 작업이기 때문이다. 그에 반해 웹 애플리케이션 동적인 데이터를 처리하기 위해 만들어졌다. 예를 들어 로그인한 사용자마다 카트의 내용이 동적으로 변하여 다르게 보인다든가 하는 처리를 말하는 것이다.

CSS, Javascript, image 파일들로 이루어진 static 파일을 웹어플리케이션인 Django가 처리하기에는 너무 비효율적이다. 웹서버에서 웹 애플리케이션으로 요청을 전달하는 데는 WSGI라는 변환과정을 거치며 이것은 자원을 소모하는 일이고, 굳이 웹서버도 할 수 있는 일을 웹 애플리케이션에서 할 필요가 없는 것이다.

그래서 Django에서는 Production에서의 static 파일을 처리하는 기능을 담고있지 않다.

개발할 때 보니까 되던데?

Django 개발할 때는 static 파일이 잘 전송되는 것을 볼 수 있다. 이것은 INSTALLED_APPS의 django.contrib.staticfiles이라는 모듈이 담당하고 있으며, 그마저도 settings.py의 DEBUG 속성을 False로 바꾸면 동작하지 않게된다.

이때부터는 static 파일의 처리는 웹서버가 담당하게 되는 것이다. 아파치 설정 중에도 static 파일의 경로를 정의하는 설정이 포함되는 것을 알 수 있다.

스테틱관련 설정

Django 공식 문서를 보면 settings.py에 정의 할 수 있는 static 관련 설정이 나온다.

  • STATIC_ROOT
  • STATIC_URL
  • STATICFILES_DIRS

STATIC_ROOT

실 서버 배포 시 static 파일을 collectstatic 하기위한 절대 경로이다. 기본 값은 None이며 다음과 같이 설정할 수 있다.

1
STATIC_ROOT = "/var/www/example.com/static/"

staticfiles contrib app이 활성화 되었을 때(기본적으로 Django 프로젝트를 생성하면 INSTALLED_APPS에 포함) ‘collectstatic’ 콘솔 명령어를 수행하면 해당 디렉터리로 static 파일들이 모인다.

STATIC_URL

URL로써 static 파일의 위치를 가르킬 때 사용하는 위치이다. 마찬가지로 기본값은 None이며 아래와 같이 설정한다.

1
STATIC_URL = "/static/" or "http://static.example.com/"

주의 할 점은 마지막에 /를 꼭 붙여주어야 하고 /만 써서 root 경로를 가르키게 하면 안된다.

STATICFILES_DIRS

앱에 포함된 static 파일의 위치를 추가할 수 있다. 기본값은 [](비어있는 리스트) 이고, 아래와 같이 설정한다.

1
2
3
4
5
STATICFILES_DIRS = [
"/home/special.polls.com/polls/static",
"/home/polls.com/polls/static",
"/opt/webfiles/common",
]

앱에 포함된 기본 static 파일의 경로는 {APP_NAME}/static이다. manage.py의 커맨드 명령어인 findstatic을 수행하면 우리가 찾고자 하는 static 파일의 풀 경로를 보여준다.
이때 우선순위는 기본 앱의 경로보다 STATICFILES_DIRS에 명시된 경로가 먼저 사용된다.

Prefixes

STATICFILES_DIRS 지정 시 Optional 속성으로 Prefix를 넣을 수 있다.

1
2
3
4
STATICFILES_DIRS = [
# ...
("downloads", "/opt/webfiles/stats"),
]

예를 들어위처럼 downlaods라는 prefix를 넣으면 어떻게 될까? 해당경로에 있는 파일들은 collectstatic 명령을 내렸을때 STATIC_ROOT에서 지정한 폴더 하위에 downloads라는 폴더를 만들어 모이게 된다.
당연하게도 실제 제공되는 URL도 STATIC_ROOT에서 지정한 경로에 downloads를 붙여 제공하게 된다.

ref.

Comment and share

  • page 1 of 1
Author's picture

Hojin Jun


programmer


seoul