Docker와 FastAPI를 활용해서 AI 모델을 배포해보자!

준커·2024년 1월 8일
0

DevOps

목록 보기
4/6
post-thumbnail

진행중인 프로젝트에서 kobert, yolov8 2개의 모델을 사용한 클린봇, 이미지에서 옷의 색상 추출 기능을 사용하게 되어 Docker와 FastAPI를 사용하여 모델 API 서버를 배포해 보았다.

Sluv의 AI 모델 도입기

모델 서버는 한번 생성하고 나면 수정이 거의 없을 것이라 판단하여 CI/CD 파이프라인은 따로 구축하지 않고 수동배포 하였다.

1. EC2 생성하기

기본적인 프리티어로 사용할 수 있는 EC2를 생성하였다.


특이사항은 모델과 Docker 이미지의 크기가 어마어마하기 때문에 스토리지를 최대한으로 사용하였다.

탄력적 IP 할당

생성된 인스턴스에 탄력적 IP를 할당.

2. Docker 설치

kobert와 yolov8을 동시에 사용해야 하므로 종속성 버전 관리가 까다롭다. 때문에 미리 생성된 Docker 이미지를 사용하여 배포할 것이다.

> sudo apt-get update
> sudo apt-get install docker
> sudo apt install docker.io
> sudo usermod -a -G docker $USER

EC2 재접속 (재접속해야 sudo 없애 docker 명령어 사용 가능)!

> docker pull {dockerhub img}
> docker images
> docker run -it --name {원하는 이름} -d -p 80:8000 {docker img 이름}

FastAPI의 기본 포트가 8000이기 때문에 ec2의 80포트와 Docker 컨테이너의 8000 포트를 연결하였다.

3. FastAPI로 서버 만들기

많고 많은 언어와 프레임워크들 중 FastAPI를 선택한 이유는 다음과 같다.

  1. AI 모델이 Python으로 작성되어 호환성이 높다.
  2. API가 모델별로 1개씩 총 2개만 필요하기 때문에 django나 Flask보다 API 환경 구축이 빠르고 편하다.

main.py

from fastapi import FastAPI
from routes import routes

app = FastAPI()
app.include_router(routes.api)

routes/routes.py

from fastapi import APIRouter
import os
import sys
sys.path.append(os.getcwd())
from dto.commentReqDto import CommentReqDto
from dto.itemImgReqDto import ItemImgReqDto
import kobert_model
import yolov8

api = APIRouter()

@api.post("/check-malicious-comment")
def checkMaliciousComment(commentReqDto : CommentReqDto):
    # TODO : Call cleanBot Metho
    return kobert_model.predict(commentReqDto.comment)

@api.post("/check-item-color")
def checkItemColor(itemImgReqDto : ItemImgReqDto):
    # TODO : Call cleanBot Method
    return yolov8.detect_color(itemImgReqDto.itemImgUrl)

dto/commentReqDto.py

from pydantic import BaseModel


class ItemImgReqDto(BaseModel):
    itemImgUrl: str
    

dto/itemImgReqDto.py

from pydantic import BaseModel


class ItemImgReqDto(BaseModel):
    itemImgUrl: str
    

위 파일들과 AI 모델 파일을 함께 Github에 업로드 하였다.

4. 코드 Clone

> docker ps
> docker exec -it {docker 컨터이너 아이디} /bin/bash

생성해 놓은 Docker 컨테이너에 접속하여 Github에 올려놓은 코드를 clone하면 된다.

> pip install fastapi uvicorn
> git clone {Github 주소}
> cd {Project 폴더}
> uvicorn main:app --reload

5. 트러블 슈팅

5-1. 첫 번째 트러블..

> uvicorn main:app --reload

위 명령어로 실행시켰지만 터미널이 멈추는 상황이 발생하였다.
분명 내 PC 로컬환경에선 무난하게 실행이 됐었다.

5-1. 첫 번째 해결!

EC2가 멈추는 이유는 메모리가 부족하기 때문이라고 생각하여 AI 개발자에게 최소 어느정도의 메모리가 필요하냐고 물어보니 3GB라고 하였다...

확인해 보니 프리티어 사용을 위한 t2.micro는 메모리가 1GB였다...
학교에게 문의한 결과 비용 지원이 가능했기에! 큰 마음 먹고 t2.medium으로 변경하였다.

5-2. 두 번째 에러..

서버를 실행시켰지만 이번엔 위와 같은 에러가 발생하며 서버가 실행되지 않았다.
AI 개발자에게 말해보니 kobert의 가중치 파일이 clone되는 과정에서 꼬인 것 같다고 말하였다.

Github Clone 과정에서 파일이 꼬일수가 있나..? 처음 듣는 이야기였다.

5-2. Github 1개의 파일의 최대 용량

Github Docs에서 찾아보니 1파일이 100MiB이상인 파일은 제한이된다고 한다.

kobert의 가중치 파일의 크기를 확인해 보니 무려 352MB였다...


Github Docs를 보니 Git LFS를 사용하면 된다고 안내되어 있었다.
(AI 개발자에게 물어보니 push시에도 Git LFS를 사용했다고 한다 ㅎㅎ)

5-2. 두 번째 해결!

> apt install curl
> curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | bash
> apt install git-lfs
> rm -rf {기존 프로젝트 디렉토리}
> git clone {Github 주소}
> cd {프로젝트 디렉토리}
> git lfs pull

Git LFS를 설치하기 전에 Clone한 디렉토리에는 적용이 안 된다고 하여, 삭제 후 다시 Clone하였다.

5-3. 세 번째 에러..

모든 설정을 끝낸 뒤 Postman으로 호출하였지만, 에러가 발생하며, FastAPI에 로그가 찍히지 않았다.

5-3. 세 번째 해결!

우선 Docker 설정을 잘못했다고 판단하여 Docker 컨테이너가 아닌 ec2에 테스트용 API 서버를 띄워 확인해 보았다.

API가 정상적으로 작동하는 것을 확인하였다.

서버에 로그도 정상적으로 찍혔다.

즉, Docker 설정의 문제이다!!

다시 Docker 컨테이너의 Port 설정에 주목하였다.

0.0.0.0:80 -> 컨테이너:8000이 이어진다고 설정되어 있다.

단순

>uvicorn main:app --reload

를 사용할 경우 다음과 같이 127.0.0.1:8000에서 뜨는 것을 확인 할 수 있다.

혹시 127.0.0.1이 아닌 0.0.0.0으로 띄우면 될까..? 하는 마음에 시도해 보았다.

> uvicorn main:app --reload --host=0.0.0.0 --port=8000

정상 동작하는 것을 확인할 수 있었다.

5-4. 네 번째 에러..

batch response: This repository is over its data quota. Account responsible for LFS bandwidth should purchase more data packs to restore access.
Failed to fetch some objects from 'https://github.com/{주소}

환경을 조금씩 바꾸다 최종 셋팅하기 위해 git lfs pull을 했더니 위와 같은 에러가 발생하였다.

5-4. 네 번째 해결!

찾아보니 Git LFS의 무료 버전의 사용량이 다 된 것이라고 한다.

때문에 개인 Repository에 가중치 파일만 넣어 따로 push하였다.
(이때도 Git LFS로 Push해야한다.)

이후 EC2 Docker 컨테이너 안에 따로 Clone후 프로젝트 파일로 가중치 파일을 옮겨 해결하였다.

6. 최종

nohup uvicorn main:app --reload --host 0.0.0.0 --port 8000

최종적으로 nohup을 추가하여 백그라운드 실행으로 서버를 띄워 배포하였다.

7. 발전

나는 배포는 성공했지만, 네 번째 에러였던 Git LFS 관련 에러를 보며 언젠까 또 발생할테고.. 그럴때 마다 Repository를 새로 파야하나..? 라는 생각이 들었다.

글을 작성하고 나니 "그럼 문제가 되는 kobert의 가중치 파일까지 같이 Docker Image로 만들면 되는거 아닌가?" 하는 생각이 들어 AI 개발자의 Docker Image를 기반으로 AI 모델 2개와 FastAPI 서버까지 Docker Image로 만들어 배포해보았다.

AI 모델 서버를 도커 이미지를 만들어 보자!

profile
학부생일뿐

0개의 댓글