개인적으로 nginx 자체는 매력적이라고 생각했지만, php-fpm 이라던가 uwsgi 같이 웹서버에서 직접 붙지 않고 socket 으로 연결되는 방식이 마음에 들지 않아 잘 사용하지 않았다. 

설정 및 관리가 좀 더 번거롭기도 했고..


이제는 마음에 안들었던 몇가지를 감수하고 장점을 취해보기 위해서 사용해보려고 하는데,  여전히 개떡같은 uWSGI 설정법을 정리해봄.


----------
2020.06.28 gunicorn 설정 추가

uWSGI보다 gunicorn 이 더 좋다고 한다.
나의 경우 웹소켓을 쓰려는데, uWSGI는 제대로 안되고 gunicorn + eventlet 조합으로 해야해서 스택을 변경해봄.


큰 차이는 없다. 거의 비슷...
----------

환경은 Ubuntu 18.04 + Nginx + uWSGI/gunicorn + Python3 + Flask.

이 방법의 최대 장점 중 하나가 프로젝트별로 python 버전에 구애받지 않고 venv 를 전혀 무리 없이 돌릴 수 있다.. 인 것 같은데 난 평소에 그렇게 안쓰고 있으니 일단 생략.


1. 패키지 설치

apt에도 있긴 한데, pip으로 설치해줘도 된다.

pip install uwsgi

pip install gunicorn


2. 프로젝트 wsgi 설정

프로젝트 폴더에 이런식으로 파일을 만든다.

wsgi.py

from flask_app import app

if __name__ == '__main__':
    app.run()

uwsgi.ini (gunicorn 의 경우엔 필요없음)

[uwsgi]
#plugin = python3
module = wsgi:app

master = true
processes = 3

socket = /tmp/PROJECT.sock
chmod-socket = 664
vacuum = true

die-on-term = true

plugin = python 은, uwsgi 를 apt로 설치한 경우 필요한 것 같음.


3. systemd unit 생성

/etc/systemd/system/ 경로에 PROJECT.service 로 파일을 만든다.

[Unit]
Description=WSGI instance to serve PROJECT
After=network.target

[Service]
User=ubuntu
Group=www-data
WorkingDirectory=/PATH/TO/PROJECT
#Environment="PATH=/PATH/TO/BIN"
#ExecStart=/usr/bin/uwsgi --ini uwsgi.ini
ExecStart=/usr/local/bin/gunicorn -k eventlet -w 3 --bind unix:wsgi.sock -m 007 wsgi:app

[Install]
WantedBy=multi-user.target

뭐 User, Group 이라던가 적당히 해주고, 그 밑에 WorkingDirectory, 환경변수, 실행커맨드 등도 적당히 수정해준다.

gunicorn 도 uwsgi처럼 configuration 파일을 만들어서 할 수 있지만, 명령어로도 충분한 듯...

-k, --worker-class=: 워커 프로세스 종류. sync(기본값), eventlet, gevent 등이 있다.

-w, --workers=: 워커 갯수. 시스템 프로세스 코어당 2~4개가 권장이라는 듯?

-m: unix socket으로 만들 경우 umask


이 후

sudo systemctl enable PROJECT

sudo systemctl start PROJECT

이렇게 자동 실행 설정 및 서비스 시작 해주면 된다.


4. Nginx 설정

sites-available 등의 설명은 생략.


아래와 같이 구성하자. 수정이 필요하다면 적당히 수정...


server {
        listen 80;
        server_name 사이트주소;

        #location / {
        #        include uwsgi_params;
        #        uwsgi_pass unix:///tmp/PROJECT.sock;
        #}
        location / {
                include proxy_params;
                proxy_redirect off;
                proxy_pass http://unix:/PATH/TO/PROJECT/wsgi.sock;
        }
        #location /socket.io {
        #        proxy_pass http://unix:/PATH/TO/PROJECT/wsgi.sock:/socket.io;
        #        include proxy_params;
        #        proxy_http_version 1.1;
        #        proxy_redirect off;
        #        proxy_buffering off;
        #        proxy_set_header Upgrade $http_upgrade;
        #        proxy_set_header Connection "Upgrade";
        #}
        location /static {
                alias /PATH/TO/PROJECT/flask_app/static;
        }
}

업스트림 설정으로 분산화를 하거나, uri 에 따라 다른 프로젝트로 연결하는 것도 가능하다. 이건 내가 쓸일 있을때 수정해둘거임.

uwsgi 는 전용 지시어인 uwsgi_param, uwsgi_pass 를 사용하는데, gunicorn 은 그냥 proxy 관련 지시어들을 사용한다.

소켓을 어디에 만드느냐는 큰 차이 없음.

websocket 을 사용할 경우 주석처리한 것처럼 따로 설정을 해주면 된다.


5. 로그 보기

프로젝트 폴더에 만들었던 uwsgi.ini  에서 log 파일 경로를 지정할 수도 있지만,

sudo journalctl -u PROJECT 로 볼 수도 있다.

uwsgi 관련 로그는 여기에서,

접속 기록이나 파이썬 에러 로그 등은

/var/log/nginx/access.log, /var/log/nginx/error.log 에서 확인할 수 있다. 물론 설정에서 각각 바꿔줬으면 다르겠지?



참고

How To Serve Flask Applications with uWSGI and Nginx on Ubuntu 18.04 (DigitalOcean)

uWSGI documentation

gunicorn documentation

Heroku는 Git 을 기반으로 패키지를 업로드한다.

프로젝트와 git 은 이미 만들어져있다고 가정하고, 해당 디렉토리 아래에서 진행한다.


참고로 Python 3.6


0. Prerequisite

heroku cli 바이너리가 필요한데, 맥에서는 그냥 brew 로 설치가능하다.

$ brew install heroku


Python 버전은 3.6 그리고 virtualenv 패키지가 여러개가 있는데, heroku 는 pipenv 를 쓰는 듯?

$ pip install pipenv


$ pipenv install

로 현재 경로에 virtualenv 환경을 만들고,

$ pipenv shell

을 입력하면 알아서 source 해준다.


1. virtualenv 패키지 설치

$ pipenv install 패키지명

으로 설치하면 Pipfile 에 알아서 넣어줌. 다른 방법은 모르겠음.


gunicorn 도 venv 안에 깔아줘야하는지 모르겠지만, 난 그냥 깔아줬다.


그리고 $ pipenv lock 을 하면 PipfilePipfile.lock 파일을 만들어주는데, 이것 역시 git 에 추가해주자.


2. Procfile 생성

heroku 에서 run 할때 어떤 command 를 실행해야하는지를 알려주는 파일이다.

나의 경우 
web: gunicorn flask_app:app
이렇게 한줄만 있으면 되었음.

web 은 heroku 서비스 관련 예약어이고, 그 뒤론 명령어인데
gunicorn 이란 wsgi 패키지를 이용하는 듯.

난 flask_app/__init__.py 의 형태지만,
프로젝트 루트의 flask_app.py 안에 app = Flask(name) 같은 형태도 가능하다.

마찬가지로 git 에 추가.

3. heroku cli

우선 로그인을 하자
$ heroku login

$ heroku local
로 현재 웹을 테스트 해볼 수 있다.

프로젝트 생성은
$ heroku create

이후 소스 푸시 및 빌드는
$ git push heroku master

$ heroku open

하면 주소가 열린다.


+ Recent posts