WSGI(Web Server Gateway Interface)는 웹서버와 어플리케이션이 통신하기 위한 인터페이스입니다. 웹서버의 요청을 어플리케이션으로 전송해주는 역할을 합니다.
Gunicorn은 Python 어플리케이션을 위한 WSGI입니다. Flask 프레임워크로 작성된 어플리케이션을 웹서버와 통신을 하기 해서 서비스를 안정적으로 서빙할 수 있도록 해줍니다.
Python 가상 환경은 프로젝트 폴더에서 python3-venv
패키지를 통해 아래와 같은 명령어로 세팅할 수 있습니다. 이외에도 가상 환경은 Conda와 같은 패키지를 이용할 수 있으며, Docker와 같이 독립적인 컨테이너 환경을 기반으로 작업해도 무방합니다.
python3 -m venv [가상환경저장폴더]
Flask 어플리케이션이 작성되어 있다면, 동일 가상환경에서 gunicorn 패키지를 설치합니다.
(venv) $ pip install gunicorn
만일, flask 어플리케이션의 이름이 project
라고 가정합니다. 프로젝트 폴더의 구조는 다음과 같습니다.
참고로, __init__.py
파일을 이용하여 패키지 디렉토리 구조로 구성하는 것을 추천합니다. 파이썬에서 패키지로써 인식되도록 하는 특별한 파일입니다. 이 파일은 해당 디렉토리가 패키지임을 나타내며, 패키지를 초기화하는 데 사용될 수 있습니다.
project
├── project
│ ├── __init__.py
│ ├── static
│ ├── templates
│ └── views
├── venv
├── requirements.txt
└── wsgi.py
다음과 같이 프로젝트 루트 폴더에 wsgi.py
파일을 작성합니다.
# wsgi.py 파일
from project import app
if __name__ == "__main__":
app.run()
gunicorn 패키지 설치와 시작 파일이 작성되었다면 다음과 같이 동작 여부를 테스트해 볼 수 있습니다.
5000번 포트로 테스트 설정해봅니다. (방화벽이 설정되어 있다면 외부에서 접속 시 방화벽에서 포트를 열어줘야 합니다.)
# 프로젝트 루트 폴더에서 수행 (가상환경 활성화 후)
(venv) $ gunicorn --bind 0.0.0.0:5000 wsgi:app
아래와 같은 결과를 볼 수 있습니다.
Output
[2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4
[2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419)
[2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync
[2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421
웹 브라우저에서 http://localhost:5000
또는 http://127.0.0.1:5000
주소로 접속해서 flask 웹 어플리케이션이 정상적으로 동작하는지 확인합니다.
Ctrl + C
로 서비스를 중단하고, 시스템 서비스를 등록해줍니다.
이제, 아래와 같이 시스템 파일을 등록해줍니다.
sudo vi /etc/systemd/system/[서비스이름].service
[Unit]
Description=[서비스 설명]
After=network.target
[Service]
User=ubuntu # 사용자 계정
Group=www-data # NGINX 계정 그룹
WorkingDirectory=/var/www/[프로젝트 명]/flask # 웹 어플리케이션 루트 패스
Environment="PATH=/var/www/[프로젝트 명]/flask/venv/bin" # Python 가상 환경 실행파일 패스
ExecStart=/var/www/[프로젝트 명]/flask/venv/bin/gunicorn --workers 3 --preload --bind unix:/tmp/[소켓이름].sock -m 007 wsgi:app
# OOM 등 상황 대비하여 자동 재시작 설정
Restart=always
RestartSec=5
TimeoutStopSec=20
KillMode=process
SuccessExitStatus=SIGKILL
MemoryMax=2G
OOMScoreAdjust=-500
[Install]
WantedBy=multi-user.target
설정 내용에서 ExecStart
부분의 설명을 좀 더 덧붙이자면, 아래와 같습니다.
--worker 3
gunicorn의 워커 수를 3개로 지정한다는 의미입니다.
일반적으로 workers = 2 * CPU 코어수 + 1
와 같은 공식을 적용합니다. 예를 들어, 4코어 CPU라면 권장값은 9개입니다. 하지만, 이 공식은 단순한 I/O 바운드 웹 앱 기준이고, 메모리 사용이 높은 서비스에는 적절하지 않을 수 있습니다.
서버 환경에 맞춰서 적정한 수치로 조정하길 권장합니다.
Gunicorn은 기본적으로 워커마다 앱을 개별로 로딩합니다. --preload
옵션을 사용하면 마스터 프로세스에서 한 번만 모델을 로드하고, 이를 fork() 방식으로 자식 워커들에게 전달합니다. 이 옵션으로 오히려 빠른 응답성과 메모리 효율성이 향상될 수 있습니다.
하지만, 이 옵션은 multiprocessing을 사용하거나 대형 AI 모델을 탑재하는 경우 사용이 권장되지 않습니다.
옵션 마지막 부분은 유닉스 소켓 파일을 생성하고 바인딩 하는 부분입니다. 소켓 파일에 대해 umask
를 007
로 세팅 (소유자와 그룹에 접근 권한 부여)합니다.
이제 서비스를 등록하고 시작합니다.
sudo systemctl start [서비스명]
sudo systemctl enable [서비스명]
아래 명령어를 통해 서비스의 상태를 확인할 수 있습니다.
sudo systemctl status [서비스명]
또는
sudo service [서비스명] status
이제 NGINX 가상 호스트 설정을 해줍니다. HTTP 통신만 가정하겠습니다.
먼저 아래와 같이 가상 호스트 설정 파일을 만들어 줍니다.
sudo vi /etc/nginx/site-available/[웹서비스 명칭]
아래와 같이 Reverse Proxy 서버로 설정합니다.
server {
listen 80;
listen [::]:80;
server_name project.com www.project.com; # 도메인 설정
location / {
include proxy_params;
proxy_pass http://unix:/tmp/[소켓파일 명].sock;
}
}
파일을 저장하고 나와서 아래와 같이 실제 enabled 폴더에 링크를 생성해 줍니다.
sudo ln -s /etc/nginx/sites-available/[웹서비스 명칭] /etc/nginx/sites-enabled
NGINX 서비스를 재시작합니다.
sudo service nginx restart
SSL 설정이나 기타 NGINX 설정들을 사용하는 환경에 맞춰서 추가/수정할 수 있습니다.
지금까지 간단한 Gunicorn 설정 방법을 알아보았습니다.
문의사항이나 잘못된 부분이 있으면 댓글로 남겨주시기 바랍니다.
감사합니다.