개요

현재 4-2 캡스톤 프로젝트에선 매수 알림 기능을 위해 pytorch로 만들어진 모델을 서빙해주는 프레임워크가 필요했다.

그 역할에 제격인게 바로 같은 Python 프레임워크인 Fastapi였다.

본격적으로 모델을 만들기 전에 테스트로 어떤 식으로 동작하는지 알고 싶었고 간단하게 Iris dataset을 Random Forest 방법으로 학습시켜 만든 모델로 진행하였다.

 

모델 

import joblib
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier

# Load the iris dataset
iris = load_iris()
X, y = iris.data, iris.target

# Train a random forest classifier
model = RandomForestClassifier()
model.fit(X, y)

# Save the trained model
joblib.dump(model, 'model.joblib')

 

 

Fastapi

 

from fastapi import FastAPI
import joblib
import numpy as np
from sklearn.datasets import load_iris  # 추가
app = FastAPI()

# Load the trained model
model = joblib.load('model.joblib')

# Load the iris dataset
iris = load_iris()  # 추가

@app.get("/")
def read_root():
    return {"message": "Welcome to the ML Model API V2"}

@app.post("/predict/")
def predict(data: dict):
    features = np.array(data['features']).reshape(1, -1)
    prediction = model.predict(features)
    class_name = iris.target_names[prediction][0]
    return {"class": class_name}

 

만들어진 모델을 실고 /predict 라우터에 post 요청으로 딕셔너리 데이터가 도착하면 해당 데이터가 어떤 이미지인지 클래스 값을 리턴으로 돌려준다.

 

Docker

# Use the official Python image
FROM python:3.9

# Set the working directory in the container
WORKDIR /app

# Copy the local code to the container
COPY . .

# Install FastAPI and Uvicorn
RUN pip install --no-cache-dir -r requirements.txt

# Expose the port the app runs on
EXPOSE 8000

# Command to run the application
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

 

우리의 프로젝트에선 모든 서비스를 컨테이너 단위로 올리기 때문에 도커 이미지로 만들어줄 필요가 있었다.

 

Docker hub upload

 

작동 test

Local에서 실행

 

/ endpoint로 접근

 

 

모델 호출을 위해 /predict로 접근

 

iris dataset중 setosa에 해당한다는 결과값을 받을 수 있었다.

 

 

AWS EC2에서 실행

 

Flow

 

보안그룹에서 8000 port tcp 연결 추가 → docker image pull 후 실행 → 브라우저에서 ip 단위로 접근 → 모델 호출

 

CI / CD

이번 프로젝트에서 devops 역할을 맡았기 때문에 만들어지는 모든 서비스를 자동으로 배포하고 싶었다. 

CI / CD 도구로는 Github Actions를 선택하였고 아래는 그 과정들이다.

 

1. Github repo 환경변수 설정 

 

 

2.  .github/workflows 하위 디렉토리로 yaml 파일 push

 

name: Build to dockerhub and deploy to ec2

on:
  push:
    branches:
      - main  # exec when pushed main branch

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Set up Python
        uses: actions/setup-python@v2
        with:
          python-version: '3.9'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt

      - name: Build Docker image
        run: |
          docker build -t ${{ secrets.DOCKER_USERNAME }}/fastapi_test:v1 .

      - name: Login to Docker Hub
        run: echo "${{ secrets.DOCKER_TOKEN }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin

      - name: Push Docker image to Docker Hub
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/fastapi_test:v1

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to EC2
        run: |
          echo "${{ secrets.EC2_KEY }}" > ec2_key.pem
          chmod 600 ec2_key.pem
          ssh -o StrictHostKeyChecking=no -i ec2_key.pem ec2-user@13.124.230.180 << 'EOF'
            docker pull ${{ secrets.DOCKER_USERNAME }}/fastapi_test:v1
            docker stop my_fastapi_container || true
            docker rm my_fastapi_container || true
            docker run -d -p 8000:8000 --name my_fastapi_container ${{ secrets.DOCKER_USERNAME }}/fastapi_test:v1
          EOF

 

작동 flow 및 테스트

 

 

개발자가 깃허브 레포지토리 메인 브렌치에 PUSH할 경우 그것을 트리거로 하여 Github Actions가 docker hub에 container를 빌드하고 최종적으로 EC2에 배포한다.

 

테스트

 

1. Fastapi Root router message 변경

 

2. Github push

 

 

ec2에서 확인 시 컨테이너가 재생성된 것 확인 및 버전 확인. V1에서 V2로 바뀐 것을 확인 가능하다.