들어가기 앞서
OS : Ubuntu 16.04 LTS
Django (1.11.3)
Python : 3.6.1
Nginx : 1.10.3(ubuntu)
굉장히 부족하고, 굉장히 저급 수준의 실력을 가진 유저가 쓴 글입니다. 진행하시다가 오류를 발견하시거나, 진행사항에 문제가 있는 경우 적극적으로 알려주세요. 감사합니다.
Nginx - uWSGI - Django 연동하기
본 포스팅은 도커(Docker) 상에서 Nginx
와 uWSGI
를 연동을 확인하는 포스팅입니다. 도커 스크립트를 통해 컨테이너에는 이미 Nginx
와 uWSGI
가 설치된 가정하에 글의 순서는 다음과 같습니다.
Web Client
-장고 App
Web Client
-uWSGI
-장고 App
Web Client
-Nginx
-uWSGI
-장고 App
으로 진행합니다.
Nginx, uWSGI란
Web Client
는 웹 브라우저다. 웹 서버에게 HTTP
요청을 보낸다.
Nginx
는 웹 서버다. HTTP
요청을 받는다. 그런데 Python
언어를 모른다.
uWSGI
는 HTTP
요청을 Python
으로 변환해준다.
컨테이너 연결하기
해당 예제는 도커 스크립트(Dockerfiles)를 이용해 로컬 프로젝트 파일을 컨테이너로 복사하고, 해당 프로젝트를 /srv/(프로젝트 이름)
에 위치시키고, 워킹 디렉토리를 프로젝트 경로로 이동한 상태입니다.
도커 이미지 파일 생성후 컨테이너로 들어가기
sudo docker run --rm -it -p : /bin/zsh$ sudo docker run --rm -it -p 9000:8000 eb /bin/zsh
run --rm
: 컨테이너 안의 프로세스가 종료되면 컨테이너를 자동으로 삭제(remove)한다.
-it
: 컨테이너를 연결해 터미널을 사용하고 싶다면 필수적으로 지정해줘야 한다.
-i
: 컨테이너가 STDIN을 오픈해서 유지하도록 지정. 이걸 빼놓고-t
만 입력하면, 터미널은 실행되지만 입력이 불가능하다.-t
: 컨테이너에 pesudo-tty(터미널)를 할당한다. 이걸 빼놓고-i
만 입력하면 터미널이 열리지 않는다.
-p
: 컨테이너의 어떤 네트워크 포트를 오픈할지를 지정한다. 외부포트
는 외부에서 컨테이너와 통신할 포트를 의미하며 내부포트
는 컨테이너 내부에서 통신할 포트를 의미한다.
만약, 로컬 환경의 웹 브라우저에서 컨테이너의 웹서버로 접속하려고 한다면 외부
포트(예제에서 9000번
)를 이용해야 한다. 반면에, 컨테이너 안에서 지들끼리(uWSGI, Nginx 등) 통신하고자 할때는 내부
포트(예제에서 8000번
)를 이용하면 된다.
3-1 Django App Runserver
아무것도 실행하지 않고, 웹 클라이언트와 Djano가 서버를 담당하는 예제를 보여줍니다.
Runserver (컨테이너 연결 후)
manage.py
가 있는 곳으로 이동해 runserver
를 실시하자.
$ python manage.py runserver 0:8000 --settings=config.settings.debug
원래 Django에서 런서버 명령어는 python manage.py runserver
가 아닌가? debug
는 뭐고 deploy
는 뭔지 처음에 당황스러웠다. 갑w자기 runserver를 할 때 --settings
도 붙이고 여러모로 당황스럽다.
settings 원본
보통 프로젝트를 시작하면 settings.py
하나만 던져준다. 하지만 실무에서는 로컬(개발용, 디버그용)
과 배포(서비스용, 릴리즈 버전)
로 환경설정을 나눈다. 이것은 상용화되는 모든 소프트웨어의 공통적인 특징이다. 우리가 흔히 하는 게임도 개발용과 배포용으로 나뉜다.
로컬용
은 아무래도 오류를 검출하기 위한 환경세팅을 가져간다.로컬용은
development
,debug
로 표현하기도 한다.
배포용
은 로그 기록이나 오류를 숨겨 사용자 편의성을 도모하고 악의적인 해커로부터 보호하는 환경세팅을 가져간다.배포용은
deploy
,production
으로 표현하기도 한다.
settings 모듈화
위와 같은 이유로 settings
의 설정들을 개발용(debug)
용과 배포용(deploy)
으로 모듈화(분리)했다. 다만, 모든 환경에서 공통적으로 사용되는 설정들은 base.py
에 두었다.
이제 runserver
를 하려면 우리는 두 가지 옵션이 생겼다. 배포용
런서버를 할 것인지 개발용
런서버를 할 것인지 선택할 수 있게 되었다. 그렇다면 코드는 이렇게 된다.
$ ./manage.py runserver --settings=config.settings.debug # 개발용$ ./manage.py runserver --settings=config.settings.deploy # 배포용
settings.py
에 대한 자세한 내용은 여기를 참조하도록 하자. 굉장히 쉽고 자세하게 설명되어있다.
$ python manage.py runserver 0:8000 --settings=config.settings.debug
다만, 우리는 도커의 컨테이너
상에서 로컬용(debug) 런서버를 실행할 것이다. 따라서 우리 웹 클라이언트(크롬)에서 접속하려면 localhost:9000
으로 들어가면 장고가 띄워주는 서버를 만날 수 있다 왜 8000번 포트가 아니라 9000번 포트냐고 묻는다면, 컨테이너를 실행할 때 외부포트를 9000번
으로 설정했기 때문이다.
$ sudo docker run --rm -it -p 9000:8000 eb /bin/zsh
성공화면
3-2 uWSGI
uWSGI는 웹서버(Nginx)가 보낸 요청을 파이썬 언어로 해석하도록 도와준다. 그래서 프로젝트를 시작하면 기본적으로 wsgi.py
가 존재한다. 파이썬 언어로 해석해주는 유용한 툴이니, 당연히 Django 프로젝트를 시작하면 wsgi.py
파일을 제공한다.
3-1 Django
예제에서는 Django 애플리케이션이 직접 웹 클라이언트 요청을 받는 예제를 보였다.
3-2 uWSGI
파트에서는 웹 클라이언트에서 요청을 uWSGI
가 받도록 할 것이다. 3-1 Django
에서 설명했듯이, wsgi.py
도 개발용(debug)과 배포용(deploy)을 나눠서 설정했다.
wsgi의 분리
이제 wsgi
모듈을 이용할 차례다. settings.py
를 분리했던 것처럼, wsgi
역시 로컬용과 배포용을 구분했다. 3-1 Django Runserver
에서 debug 파일을 사용했듯이, 여기서는 uWSGI용 debug 모듈을 사용할것이다.
1. 풀(Full) 명령어를 입력하는 방법
옵션에 대해서는 여기에 자세히 설명되어 있다.
uwsgi --http : --home --chdir --module$ uwsgi --http :8000 --home /root/.pyenv/versions/deploy_eb_docker --chdir /srv/deploy_eb_docker/django_app -w config.wsgi.debug
위 명령어를 대충 해석하면 이렇다. 위에서 설명은 안했지만 uwsgi
는 가상환경 위에서 돌아가기 때문에, 번역가 역할을 하기 위해서 manage.py
와 연결해준다.
--http :8000
: 8000번 포트를 이용해 http 통신을 한다.--home
: 가상환경 디렉토리를 지정한다.가상환경 위치를 모르겠다면
which uwsgi
로 검색해보자.
--chdir
: manage.py가 들어있는 장고 프로젝트 디렉토리를 지정한다.--module
: 모듈을 사용한다는 옵션.-w
와 같은 의미이다.-w
:--wsgi-file
의 준말로, 모듈을 사용한다는 옵션
성공화면
localhost:9000으로 접속했을 때 이 역시 위와 같은 화면이 떠야 한다. 그리고 새로고침을 누를 때마다 아래와 같이 갱신되어야 한다. req : 3/3을 보면 3번 통신을 시도해서 3번 성공(HTTP/1.1 200)했다는 메시지를 힘겹게 찾아볼 수 있다.
2. .ini
로 파라미터를 전달하기
Full 명령어를 입력하면 번거롭기 때문에 프로젝트 내에 .ini
파일을 만든뒤 이를 실행시켜서 파라미터를 전달할 수도 있다.
디렉토리 구조
uwsgi-app.init 파일 세부 내용
uwsgi --ini$ uwsgi --ini .config/uwsgi/uwsgi-app.ini$ uwsgi --http :8000 .config/uwsgi/uwsgi-app.ini # 파라미터에 http가 없는 경우
파일 맨 상단에 보면 http = :8000
이 있는데, 이는 곧 uWSGI가 직접
8000번 통신을 한다는 이야기다. 만약, 이 http
가 없다면, 명시적으로 --http :8000
을 써줘야 한다.
그러나, 3-3 Nginx
부터는 웹 요청을 Nginx
가 담당하도록 할 것이기 때문에 .ini
파일에서 http
파라미터를 지우도록 하자. (이때 다시 도커를 build해줘야 한다.)
3-3 Nginx 실행하기
드디어 웹서버인 Nginx
까지 왔다. 3-3 Nginx
의 연동을 테스트하기 위해서는 추가적인 설명이 더 필요하다. 소켓(socket)
의 개념이 추가될뿐만 아니라, uWSGI
를 가동시킨 상태로 웹 서버도 가동시켜야 하기 때문에 새로운 명령어도 하나 배워야 한다. 이 부분에 대해서는 하단에 넣고, 먼저 실행되는 것을 살펴보도록 하자.
uWSGI(컨테이너) 먼저 실행
nginx 실행(컨테이너)
3-3-1 소켓
Nginx
와 uWSGI
의 접점을 소켓이라고 일단은 이해하자. 그러면 Nginx
와 uWSGI
모두 소켓에 관한 설정이 어딘가 들어있음을 유추할 수 있다.
uWSGI.ini
이때, 소켓파일의 권한을 nginx가 사용할 수 있도록 소켓을 666(읽고, 쓰기) 권한으로 바꿔주는 것을 확인할 수 있다.
nginx.conf
uWSGI
에도, nginx
에도 tmp/eb.sock
이라는 걸 찾아볼 수 있다.
3-3-2 새로운 도커 명령어의 등장
실행 중인 컨테이너에 명령 넣기
$ sudo docker exec
실행 중인 컨테이너 쉘 하나 더열기
$ sudk docker exec -it
이미 실행되고 있는 컨테이너 안에 명령을 넣고 싶을 때 사용한다. uWSGI
를 가동시킨 상태로 Nginx
의 연동 테스트를 실시해야 한다. 즉, 쉘을 두 개 켜야 테스트가 가능하다.
명령어를 보면 컨테이너 ID가 있으니까 이 컨테이너에 명령을 넣는다는 의미이다. 컨테이너의 ID를 얻으려면 sudo docker ps
명령어를 통해 얻어내야 한다. 여기서는 아이디를 통해 컨테이너로 들어가기 때문에 이미지 태그
가 필요 없다.
실행중 발생했던 에러
포트가 이미 할당되어있는 문제
sudo docker ps
로 실행중인 컨테이너 확인
현재 실행중인 컨테이너를 중단시켜야 함
sudo docker stop [Container ID]
입력하면 수초 후에 중단됨.
다시 접속하면 잘된다.
참고한 글
가장 빨리 만나는 도커 http://pyrasis.com/book/DockerForTheReallyImpatient/Chapter20/28
docker run과 관련된 옵션들 http://pyrasis.com/book/DockerForTheReallyImpatient/Chapter20/28
왜
settings.py
를 분리해야하는가? https://cjh5414.github.io/django-settings-separate/굉장히 쉽고, 자세하게 설명되어있다.
Nginx와 uWSGI 연동 https://wikidocs.net/7387
Nginx보다는 uWSGI의 구동테스트 옵션에 관한 내용들을 배웠다.
'프로그래밍 > 배포' 카테고리의 다른 글
[AWS] AWS StepFunction을 이용한 이미지 처리 (0) | 2017.11.10 |
---|---|
docker non-zero code 127 error (0) | 2017.08.12 |
Nginx 이해하기 및 기본 환경설정 세팅하기 (3) | 2017.07.03 |
아마존웹서비스(AWS) 기초 이해하기 (4) | 2017.06.30 |