Search
🦄

가장 빠른 머신러닝 앱 배포하기 | fastapi, gunicorn, nginx

subtitle
gunicorn, nginx, fastapi로 lightsail에 머신러닝앱 배포하기
Tags
머신러닝
devops
Created
2021/04/13
2 more properties
가볍고 빠르게 구축하거나 실행할 수 있는 모듈들로 머신러닝 앱을 배포해보자.

fast api, uvicorn, gunicorn, nginx, lightsail

fast api
fastapi는 가볍고 높은 퍼포먼스를 낼 수 있으며 ASGI 서버를 지원하는 모던 웹 프레임워크다. ML 프로젝트는 데이터, 패키지만 있으면 다른 디펜던시가 필요없으므로 이것저것 설정해야하는 django보다는 가벼운 fastapi를 사용하면 빠르고 쉽게 앱을 build할 수 있다. 마이크로소프트, 넷플릭스와 같은 대형 서비스에서도 ML 프로젝트를 fastapi로 빌드했다고 한다.
uvicorn
uvloop, httptools를 사용해 가볍고 빠른 ASGI 서버를 구현할 수 있다. gunicorn과 함께 사용하려면 uvicorn worker를 사용하면 된다.
gunicorn
gunicorn은 WSGI 서버이다. 빠르고 가벼운 서버를 구축할 수 있고 여러 프레임워크에 상관없이 앱을 실행할 수 있다. uvicorn과 함께 사용하여 WSGI 대신 ASGI를 실행할 수 있다.
nginx
http proxy server다. nginx에서 80포트에 request가 들어오면 8000번 포트(uvicorn default port)에 포워딩하여 uvicorn에서 실행한 앱에서 요청을 처리할 수 있다. uvicorn에서도 포트 설정이 가능하지만 1024번 이하는 previlleged ports이므로 80번 포트에서 실행해도 클라이언트에서 요청을 받을 수 없다.
lightsail
웹에서 셸로 접속해서 환경을 구축하고 실행할 수 있다. EC2보다 더 저렴하게 인스턴스를 사용할 수 있다. 사양이 낮거나 불편한 경우 스냅샷을 찍어서 EC2로 업그레이드할 수도 있다.

start fast api

패키지 설치
pip install fastapi uvicorn
Shell
복사
main.py
from fastapi import FastAPI from my_classifier import build_classifier, transformer app = FastAPI() clf = build_classifier() @app.get("/") async def read_root(): return {"msg": "World"} @app.get("/classes") async def read_classes(data = None): result = transformer(clf.predict(data)) return {"classes": result}
Python
복사
앱 실행: uvicorn main:app --reload

Deploy on lightsail

fast api 문서를 보면 deta라는 클라우드 서비스에서도 배포할 수 있다. 홍보하는 대로 무료로 배포할 수 있기도 하지만 실제로 배포하기엔 *무리가 있었다.
*코드와 설치된 패키지를 포함해 250MB를 넘으면 배포 자체가 안된다. 하지만 가벼운 프로젝트라 해도 konlpy나 sklearn 패키지, 데이터셋만 합쳐 200MB는 쉽게 넘는다. 또한 배포 실패 메시지(ex. Error: failed to deploy: Request entity too large)마저 정확히 어떤 원인에서 에러가 났는지 알기 어렵다. (deta 슬랙이 있어 help 채널에서 검색하면 되긴하지만 AWS를 이용하는 게 더 편할 것이다.)
lightsail에서 자유롭게 환경을 구축하기 위해 ubuntu를 선택했다.

install default dependencies

인스턴스 생성 후 셸에 접속해 필요한 패키지들을 설치하여 환경을 구축한다.
sudo apt-get update sudo apt-get install -y --no-install-recommends tzdata g++ git curl
Shell
복사

install java(konlpy를 사용하는 경우)

konlpy는 내부적으로 jvm을 사용하기때문에 자바를 설치하고 자바 경로를 설정해주어야 한다.
자바 설치
sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-get update sudo apt-get install -y openjdk-8-jdk
Shell
복사
JAVA_HOME 환경변수 설정
JAVA_HOME=/usr/lib/jvm/java-1.8-openjdk source /etc/environment && export JAVA_HOME # 확인 echo $JAVA_HOME
Shell
복사

install python

python 설치
sudo apt-get install -y python3-pip python3-dev
Shell
복사
symlink python3 → python, pip3 → pip
cd /usr/local/bin sudo ls -s /usr/bin/python3 python sudo ln -s /usr/bin/pip3 pip pip3 install --upgrade pip
Shell
복사
clean packages
sudo apt-get clean sudo rm -rf /var/lib/apt/lists/*
Shell
복사

install nginx

install nginx
sudo apt-get update sudo apt-get install nginx sudo systemctl start nginx
Shell
복사
/etc/nginx/sites-available 내 file에 쓰기 권한이 없으므로 chmod를 쓰기 권한을 추가해준다.
sudo chmod 775 /etc/nginx/sites-available
Shell
복사
nginx config 추가: cd /etc/nginx/sites-available && vim <서버이름>
AWS route53에서 도메인을 추가한다. A record를 생성하기 위해서는 고정된 IP 주소가 필요하다. lightsail 인스턴스에서 고정된 public IP를 생성해 A record에 연결한다. 생성한 도메인은 nginx conf에 추가한다.
server{ server_name <your-site-domain>; location / { include proxy_params; proxy_pass http://127.0.0.1:8000; } }
Shell
복사
symlink: sites-available/<server-name> → sites-enabled
sudo ln -s /etc/nginx/sites-available/<your-server-name> /etc/nginx/sites-enabled/
Shell
복사

run app

git clone <your-server-repo>
cd /var/www git clone <server-repo> cd <server-repo>
Shell
복사
restart nginx: sudo systemctl restart nginx.service
gunicorn으로 ASGI 서버 실행
k flag는 worker class를 설정한다. gunicorn은 WSGI 서버지만 uvicorn worker 클래스를 사용해서 ASGI 서버를 실행할 수 있다. --daemon 옵션으로 백그라운드에서 실행할 수 있으며, --access-log로 실행되는 동안의 로그를 저장할 파일을 지정할 수 있다.
python3 -m gunicorn -k uvicorn.workers.UvicornWorker main:app \ --daemon --access-logfile ./gunicorn-access.log
Shell
복사
<domain>/docs 에서 자동으로 생성된 api document를 확인할 수 있다.

references