시계열 모델링과 MLops 적용하기 2
1. 오늘 배운것.
1.MLops 의 이해
1-1. MLops 개념 정리

- 기존에 DevOps(데브옵스)는 개발(Development)와 운영(Operations)이 합쳐진 용어
- 개발과 운영의 경계를 허물고 협업하여 아이디어를 개발하고 배포하는 개발 환경과 도구
- 이를 ML시스템에 적용한 것이 MLops
MLOps는 머신 러닝 작업(Machine Learning Operations)을 뜻합니다. MLOps는 머신 러닝 모델을 프로덕션으로 전환하는 프로세스를 간소화하고, 뒤이어 이를 유지관리하고 모니터링하는 데 주안점을 둔 머신 러닝 엔지니어링의 핵심 기능입니다. MLOps는 협업 기능이며, 주로 데이터 사이언티스트, DevOps 엔지니어, IT로 구성됩니다.
MLops의 조건

- 지속적 통합(Continuous Intergration, CI)
- 코드의 변경사항을 정기적으로 빌드 및 테스트하고 공유 리포지토리에 통합
- 지속적 배포/제공(Continuous Deployment/Delivery, CD)
- 파이프라인, 모델 등 예측 서비스를 자동으로 배포
- 지속적 학습(Continuous Training, CT)
- 데이터가 업데이트 될 때 마다 자동으로 학습 및 업데이트
2.모델 서빙 준비하기
✅ 서빙 방법
- 모델 학습이 완료되었으면 결과를 활용할 수 있도록 해야함
방법1. ML prediction 결과를 database에 저장한다.

방법2. API를 사용하여 필요한 서비스가 호출해서 쓸 수 있도록 만듦

- 보통 산업에서는 GCP, AWS와 같은 SaaS(Software as a Service)를 이용하여 개발함
- Linux 운영체제를 활용하는 것이 기본
✅ 리눅스란?

- Linux는 1991년 Linus Torvals가 Unix 운영체제 기반으로 개발한 무료 소프트웨어 운영체제
- 윈도우, 맥 OS가 있기 전의 운영체제의 조상
- 현재 전세계적으로 300여가지의 배포판이 존재하여, 사용자에 따라 결정할 수 있는 폭이 넓습니다. (ex 개인용컴퓨터, 모바일)
- 여러분들이 사용하는 PC 외에 대부분 SaaS 서비스가 리눅스 기반입니다. (Colab도 !)
- 배포판 분류
- 회사에서 관리: 레드햇, 우분투
- 커뮤너티 관리: 데비안, 젠투, 페도라
2-1.백엔드와 프론트엔드
- Backend: 보이지 않는 곳에서 핵심 로직을 처리
- 데이터 수집, 연산, DB에 데이터 저장 등
- Frontend: 사용자 눈에 보이는 화면
- 사용자가 마우스로 누르는 화면

✅ 웹에서 더불어 등장하는 개념

- 모놀리식 아키텍쳐(Monolithic Architecture): 모든 소프트웨어의 구성요소가 한 프로젝트에 통합
- 소규모 프로젝트나 운영에는 적합하나, 일부 오류에도 전체 영향을 미칠 수 있음
- 마이크로서비스 아키텍쳐(MicroService Architecture, MSA): 여러개의 작은 서비스 유닛을 쪼개어 운영
- IP(Internte Protocol): 컴퓨터(서버)의 주소에 해당. 127.0.0.1 혹은 localhost는 내 컴퓨터를 가르키는 주소
- Port(포트): 한 서버 내에서의 호수(Room Number)
- 한 컴퓨터에서는 여러 프로그램이 동시에 인터넷을 사용하기 때문에 Port 단위로 나눔
- Ex) 8080: FastAPI, 8501: Streamlit
2-2.실습 - FastAPI + Streamlit 조합으로 만들기
1. 가상환경 생성
python -m venv myenv
# 가상환경 활성화
# Windows
myenv\Scripts\activate
# macOS/Linux
source myenv/bin/activate
2. 백엔드 코드 작성 및 실행
1) backend/main.py 코드 생성
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import random
import math
import time
from datetime import datetime
from collections import deque
import numpy as np
from sklearn.linear_model import LinearRegression # <-- ML 모델 소환
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- [In-Memory Database] ---
# 최근 30개의 데이터만 기억하는 저장소 (Queue)
# 모델이 학습할 '데이터셋' 역할을 합니다.
data_buffer = deque(maxlen=30)
def generate_fake_temperature():
now = time.time()
base_temp = 65.0
cycle = 10 * math.sin(now / 10)
noise = random.uniform(-1.5, 1.5)
return round(base_temp + cycle + noise, 2)
@app.get("/")
def health_check():
return {"status": "ok"}
@app.get("/current-temp")
def get_current_temp():
temp = generate_fake_temperature()
# [핵심] 생성된 데이터를 버리지 않고 '학습 데이터'로 저장합니다.
data_buffer.append(temp)
return {
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"temperature": temp,
"status": "DANGER" if temp > 72 else "NORMAL"
}
@app.get("/predict-temp")
def get_prediction():
"""
[Real ML Model Serving]
저장된 최근 데이터(data_buffer)를 사용하여
선형 회귀 모델을 '실시간으로' 학습시키고 미래를 예측합니다.
"""
# 1. 학습 데이터가 충분한지 확인 (최소 10개 이상)
if len(data_buffer) < 10:
return {"forecast": [], "message": "데이터 수집 중... (최소 10개 필요)"}
# 2. 데이터 전처리 (Scikit-Learn이 좋아하는 형태로 변환)
# X: 시간(인덱스) [0, 1, 2, ... N]
# y: 온도 값
y = np.array(data_buffer)
X = np.arange(len(y)).reshape(-1, 1)
# 3. 모델 학습 (Training)
# "최근 데이터의 추세(기울기)를 배워라"
model = LinearRegression()
model.fit(X, y)
# 4. 미래 예측 (Inference)
# 현재 시점 이후 10스텝(Future X)을 만듭니다.
next_steps = np.arange(len(y), len(y) + 10).reshape(-1, 1)
predictions = model.predict(next_steps)
return {"forecast": np.round(predictions, 2).tolist()}
2) 터미널 1: Backend 실행
# 필요한 라이브러리 설치
pip install fastapi uvicorn scikit-learn numpy
# backend 폴더로 이동 후 실행
cd backend
uvicorn main:app --reload --port 8000
3. 프론트 엔드
1) frontend/app.py 코드 생성
import streamlit as st
import requests
import pandas as pd
import time
import plotly.express as px
# --- [설정] ---
# Docker Compose 배포 시에는 'http://backend:8000'으로 변경해야 함
API_URL = "127.0.0.1:8000"
st.set_page_config(page_title="공장 온도 모니터링", layout="wide")
st.title("🏭 실시간 사출 성형기 온도 관제 시스템")
st.markdown("---")
# 레이아웃 구성 (2단)
col1, col2 = st.columns([1, 2])
# 데이터를 저장할 공간 (세션 스테이트 활용)
if "history" not in st.session_state:
st.session_state["history"] = []
# --- [메인 루프] ---
# Streamlit을 실시간 대시보드처럼 쓰기 위한 placeholder
placeholder = st.empty()
# 'Stop' 버튼을 누르기 전까지 계속 갱신
if st.button('모니터링 시작/중지'):
while True:
try:
# 1. FastAPI에서 데이터 가져오기
res_current = requests.get(f"{API_URL}/current-temp")
res_predict = requests.get(f"{API_URL}/predict-temp")
if res_current.status_code == 200 and res_predict.status_code == 200:
data = res_current.json()
preds = res_predict.json().get('forecast', []) # 혹시 키가 없어도 에러 안 나게 get 사용
curr_temp = data['temperature']
curr_time = data['timestamp']
status = data['status']
# 데이터 누적
st.session_state["history"].append({"time": curr_time, "temp": curr_temp})
if len(st.session_state["history"]) > 30:
st.session_state["history"].pop(0)
df = pd.DataFrame(st.session_state["history"])
# --- [화면 그리기 수정됨] ---
with placeholder.container():
# (1) 상단 지표 (Metric)
m_col1, m_col2, m_col3 = st.columns(3)
# 예측 데이터가 있을 때만 계산
if len(preds) > 0:
pred_msg = f"{preds[-1]} °C"
delta_msg = f"{preds[0] - curr_temp:.1f} 예상"
else:
pred_msg = "학습 데이터 수집 중..."
delta_msg = "0"
m_col1.metric(label="현재 설비 온도", value=f"{curr_temp} °C", delta=delta_msg)
m_col2.metric(label="상태", value=status, delta_color="inverse" if status == "DANGER" else "normal")
m_col3.metric(label="모델 예측(10분 후)", value=pred_msg)
# (2) 경고 메시지
if status == "DANGER":
st.error("🚨 [경고] 설비 온도가 임계치를 초과했습니다! 냉각수를 확인하세요.")
else:
st.success("✅ 설비가 정상 가동 중입니다.")
# (3) 차트 시각화
fig = px.line(df, x='time', y='temp', title='실시간 온도 추이', markers=True)
# 예측값이 있다면 차트에 덧그리기 (선택사항)
if len(preds) > 0:
# 미래 시간축 생성 (간단히 구현)
# 현재 마지막 시간에서 1분씩 더한다고 가정 등 시각화 로직 추가 가능
pass
st.plotly_chart(fig, use_container_width=True)
else:
st.error("백엔드 서버와 통신 실패")
except Exception as e:
st.error(f"연결 오류: {e}")
# 백엔드가 안 켜져있을 때 계속 재시도하지 않도록 잠시 대기
time.sleep(1)
# 1초마다 갱신
time.sleep(1)
2) 터미널 2:Frontend 실행
# 필요한 라이브러리 설치
pip install streamlit requests pandas plotly
# frontend 폴더로 이동 후 실행
cd frontend
streamlit run app.py
4. 결과확인 : http://localhost:8501/
3.도커 설정하기
3-1. 도커의 필요성과 개념
- 가상화의 필요성
- 새로운 운영체제에 시스템을 설치하고자 한다면 새로운 컴퓨터를 구입해야할까? → No. 운영체제 가상화를 통해 해결. Docker 사용
- 독립적인 파이썬 환경을 구축하고 싶다면? → 가상환경 구축을 통해 서로 다른 프로젝트 간 독립성을 확보. venv 사용
- Linux, Window, Mac 등 운영체제가 다양하고 사용하는 명령어 기술이 다름.
- 때문에 로컬 개발마다 재현성 안 나올 수 도 있다. Docker를 이용하면 동일한 개발 환경에서 작업이 가능한 장점
- Docker Hub에서 공식으로 **도커 이미지(Docker Official Image)**를 제공하여 쉽게 도커 이미지를 가져올 수 있음
- 도커이미지: 어떤 어플리케이션에 대하서 단순히 어플리케이선 코드 뿐 아니라, 의존성이 있는 프로그래들을 함께 패키징하여 어느 환경에서든지 실행해볼 수 있도록 만든 데이터
3-2. 실습
백엔드, 프론트 엔드는 하나의 서버에 합칠 수 있습니다. 이걸 모놀리식 구성이라고 하고, 각 기능만큼의 서버로 나눠서 설계하는 것을 MSA 식이라고 합니다. 제조업이 환경은 매우 서버와 데이터가 많기때문에 이를 가정하여 각각 컨테이너화를 하는 것이 권장됩니다.
1) requirements.txt 생성
● backend/requirements.txt
fastapi
uvicorn
scikit-learn
numpy
● frontend/ requirements.txt
streamlit
requests
pandas
plotly
2) Dockerfile 작성
● backend/Dockerfile
# 1. 가볍고 안정적인 파이썬 3.9 버전(Slim)을 베이스로 씁니다.
FROM python:3.9-slim
# 2. 작업 폴더를 만듭니다.
WORKDIR /app
# 3. 필요한 라이브러리 명세서를 복사하고 설치합니다.
# (캐싱 효과를 위해 requirements를 먼저 복사하는 것이 국룰입니다)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 4. 나머지 소스 코드를 다 복사합니다.
COPY . .
# 5. 컨테이너가 켜질 때 실행할 명령어입니다.
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
● frontend/Dockerfile
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
# Streamlit 기본 포트인 8501번을 열고 실행합니다.
CMD ["streamlit", "run", "app.py", "--server.port", "8501", "--server.address", "0.0.0.0"]
3. ★(중요) frontend/app.py 에서 API_URL을 변경
로컬에서는 localhost가 노트북이지만 컨테이너화된 Docker에서는 더이상 localhost가 아닙니다. 따라서 frontend 입장에서 데이터를 찾기위한 직접적인 API_URL를 전달해줄 필요가 있습니다.
# [수정 전]
# API_URL = "http://127.0.0.1:8000"
# [수정 후] Docker 환경용
# 도커 컴포즈가 내부 DNS로 이름을 연결해줍니다.
API_URL = "http://backend-service:8000"
4. docker-compose.yml 파일 생성
● 단일 docker가 아닌 여러개의 docker를 올리는 경우 docker-compose 를 활용
version: '3.8'
services:
# 1번 컨테이너: 백엔드
backend-service:
build: ./backend # backend 폴더에 있는 Dockerfile로 빌드해라
container_name: factory-backend
ports:
- "8000:8000" # 내 컴퓨터 8000번 <-> 컨테이너 8000번 연결
# 2번 컨테이너: 프론트엔드
frontend-service:
build: ./frontend # frontend 폴더에 있는 Dockerfile로 빌드해라
container_name: factory-dashboard
ports:
- "8501:8501" # 내 컴퓨터 8501번 <-> 컨테이너 8501번 연결
depends_on:
- backend-service # 백엔드가 켜진 다음에 프론트엔드를 켜라 (순서 보장)
5.실행 및 결과 확인
● docker - compose up --build
2. 느낀점.
너무어려워서 하나도 이해를 못한것 같습니다....
나중에 자료찾아가 보면서 다시공부해야 할것 같습니다.
정리하면서도 이렇게 이해 못하는 경우는 처음인것 같습니다.