Project Portfolio
서비스 안정성을 설계하고 운영으로 연결하는 인프라 엔지니어
Project 01
AI 영화 큐레이션 플랫폼
Qwen-14B 기반 AI 큐레이션과 3D 전시회 경험을 제공하는 팀 프로젝트.
저는 AI 서빙 서버 구축, GPU 배포, 모니터링, CI/CD 파이프라인을 담당했습니다.
2025.11 ~ 2026.02
AI 서빙, GPU 배포, 모니터링, CI/CD
FastAPI, PyTorch, Docker, Nginx, Prometheus, Grafana, GitHub Actions
VM1에 배정된 저장 용량은 10GB. Frontend, Backend, Nginx, Redis 컨테이너만으로도 저장 공간이 부족한 상황이었습니다.
VM2(GPU 서버)는 100GB가 배정되어 있고, AI 모델은 메모리에 로드되므로 디스크 여유가 충분했습니다. PostgreSQL을 GPU 서버에 설치하고, VM1에서만 접속할 수 있도록 네트워크를 격리하여 보안을 확보했습니다.
애플리케이션과 DB 사이의 네트워크 경로가 명확해졌고, GPU 서버의 남는 디스크를 활용하여 별도 스토리지 없이 안정적으로 운영할 수 있었습니다.
6개 GitHub Actions 워크플로를 서비스 단위로 분리 — 변경된 서비스만 트리거되어 Docker Hub를 거쳐 VM1(앱 서버)·VM2(GPU 서버)에 배포됩니다.
BGE-M3 임베딩 모델이 PyTorch 2.6.0을 요구했으나, 기존 Docker 이미지는 이전 버전 기반이었습니다. 모델 로딩 시점에 런타임 에러가 발생했습니다.
Dockerfile의 베이스 이미지를 pytorch/pytorch:2.6.0-cuda12.4-cudnn9-runtime으로 변경했습니다. T4 GPU가 CUDA 12.4를 지원하는 것을 확인한 뒤 결정했습니다.
PyTorch 업그레이드 후 bitsandbytes(4-bit 양자화 라이브러리)가 빌드에 실패했습니다. C 컴파일러가 없어서 발생한 문제로, build-essential 패키지를 추가하고 triton도 함께 설치하여 호환성을 확보했습니다.
T4 GPU의 VRAM은 16GB. Qwen-14B 베이스 모델 + LoRA 어댑터 + BGE-M3 임베딩 모델을 동시에 올리면 VRAM이 초과되어 OOM(Out of Memory)이 발생했습니다.
이 문제를 감으로 해결하지 않기 위해 Prometheus + Grafana + DCGM Exporter 모니터링 스택을 구축했습니다. 실시간으로 VRAM 사용량, GPU Utilization, 온도를 관측하면서 다음 실험을 진행했습니다.
pytorch/pytorch:2.6.0-cuda12.4-cudnn9-runtime 기반. build-essential, triton 추가 설치로 양자화 라이브러리 호환성 확보
Qwen-14B (4-bit 양자화) + LoRA (fp16) + BGE-M3 임베딩. T4 16GB VRAM 내에서 안정 운영
GPU 서버의 리소스를 실시간으로 관측하기 위해 docker-compose.ai.yml에 모니터링 스택을 함께 구성했습니다.
NVIDIA GPU 메트릭 수집. VRAM 사용량, GPU Utilization, 온도, 전력 소비를 Prometheus 포맷으로 노출합니다.
시스템 메트릭 수집. CPU, RAM, 디스크 I/O를 수집하여 GPU 외 병목도 함께 확인합니다.
메트릭 수집 허브. 5GB 저장 + 7일 보존 정책으로 운영하며, DCGM과 Node Exporter 데이터를 통합 저장합니다.
대시보드. /monitor/ 경로로 서빙. GPU 사용량, 시스템 리소스, 모델 서빙 상태를 시각화합니다.
fp16 로드 시 16GB 초과 확인 → 4-bit 양자화 적용 후 ~8GB로 안정화
fp32 vs fp16 VRAM 비교 → 응답 품질 차이 없어 fp16 확정
BGE-M3 추가 VRAM 실측 → 전체 조합이 16GB 내 운영 가능 확인
GPU 서버에서 운영 중인 페르소나 모델(Qwen-14B + LoRA)을 외부에서도 API로 호출할 수 있도록, OpenAI chat completion 포맷과 호환되는 Public API를 구축했습니다.
Bearer 토큰 또는 X-API-Key 헤더로 API Key 검증. 만료·폐기 상태 확인
OpenAI messages 배열에서 사용자 프롬프트 추출. ticketId로 페르소나 테마 매핑
백엔드가 내부망(10.0.x.x:5000)의 AI 서버로 요청을 중계. 120초 타임아웃 + 에러 핸들링
AI 서버 응답을 OpenAI chat.completion 포맷으로 변환하여 반환. 토큰 사용량·비용·레이턴시를 DB에 기록
콘솔에서 발급·폐기. RPM/TPM/RPD 제한 설정. 키별 사용량 독립 추적
요청별 토큰 추정 + 비용 산출. 일별 집계 테이블로 대시보드 조회 지원
GPU 서버는 내부망에서만 접근 가능. 백엔드가 유일한 프록시 경로로 외부 노출 차단
Public AI API의 사용량·비용·상태를 확인하고 API Key를 관리할 수 있는 웹 콘솔을 프론트엔드 + 백엔드 양쪽에 구현했습니다.
24시간 기준 총 요청 수, 성공률, 평균 레이턴시 표시. 2시간 단위 트래픽 바 차트와 엔드포인트별 호출 빈도 테이블 제공
30일 누적 비용 산출 및 월별 결제 히스토리 조회. 토큰당 단가 기반 비용 모델(Input ₩2,000/M, Output ₩15,000/M) 적용
키 발급·폐기·목록 조회. 키별 상태(active/revoked/expired) 관리 및 프리뷰 마스킹 처리
사용량·에러율·빌링 알림 설정 UI 및 OpenAI 호환 API 명세서 제공
콘솔 전용 토큰으로 로그인. httpOnly 쿠키 기반 세션 관리, 환경별(dev/prod) 쿠키 정책 분리
요청별 로그(cuk_api_usage_logs) + 일별 집계(cuk_api_usage_daily) 2단 구조. 대시보드 조회 시 집계 테이블에서 즉시 응답
기간별 요청 수·성공률·레이턴시 집계 조회. 2시간 단위 바 차트 데이터 반환
월별 비용 집계·결제 히스토리 조회. 토큰 단가 기반 비용 산출
API Key 발급. RPM/TPM/RPD 제한값·만료일 설정
API Key 폐기. 즉시 revoked 전환, 기존 사용 로그 보존
API Key 레코드. 상태(active/revoked/expired), 만료일, RPM·TPM·RPD 제한값 저장. SHA-256 해시로 키 보안 저장
요청별 로그. request_id, 토큰 수, 비용, 레이턴시, IP, User-Agent 기록. 빌링·디버깅 양쪽에 활용
일별 집계. 키·모델별 요청 수, 에러 수, 토큰 합계, 비용 합계를 사전 집계하여 대시보드 즉시 응답
Project 02
웹소설 작가용 AI 통합 워크스페이스
기획, 집필, AI 보조를 하나의 흐름으로 연결하는 멀티플랫폼 작업 환경.
저는 인프라 설계, Traefik 기반 리버스 프록시, CI/CD 파이프라인, AI 서비스 서버를 담당했습니다.
2026.02 ~ 2026.03
인프라, CI/CD, 리버스 프록시, AI 서빙
Traefik, Docker, GitHub Actions, GHCR, FastAPI, Electron
사용자 요청은 Cloudflare(WAF · SSL/TLS · DDoS 방어 · CDN 캐싱)를 거쳐 ServaRica VPS로 들어오고, Traefik(Edge Network)이 받아 각 서비스로 라우팅합니다.
Frontend(Nginx · React · Vite, :3000), Backend API Gateway(FastAPI, :8000), Redis 캐시(:6379)가 VPS 안에서 동작합니다.
PostgreSQL(:5432)로 데이터를 영속하고, Prometheus · Grafana · Node Exporter로 모니터링하며, AI 기능은 외부 Google Gemini API를 호출합니다.
Gleey는 제품 소개 페이지(랜딩)와 데스크톱 애플리케이션 서비스를 서로 다른 도메인으로 운영해야 했습니다. 또한 프론트엔드, 백엔드, AI 서비스 등 여러 컨테이너가 동시에 돌아가는 환경이었습니다.
Traefik 3.6.9을 edge 프록시로 배치하고, edge와 gleey-net 두 개의 Docker 네트워크를 분리했습니다. TLS 인증서는 Cloudflare Origin 인증서를 /etc/traefik/ssl/에 마운트하여 관리합니다.
Traefik ↔ 외부 트래픽 연결. HTTPS 종단점 역할, 도메인별 라우팅 규칙 적용
서비스 간 내부 통신 전용. 외부 접근 차단으로 서비스 격리 보장
Cloudflare Origin 인증서를 파일 마운트. Traefik entrypoint에서 HTTPS 종단 처리
Docker 라벨로 도메인 → 서비스 매핑 선언. 컨테이너 시작만으로 라우팅 자동 반영
Gleey는 Web, Desktop(macOS/Windows), Backend로 구성된 프로젝트입니다. 각 영역의 빌드 환경과 배포 대상이 다르기 때문에 워크플로를 분리했습니다.
macOS에서 Electron 앱 패키징 시, 코드 서명 없이 빌드하면 실패하는 문제가 발생했습니다. Apple Developer 인증서 없이 팀 내 배포가 필요한 상황이었습니다.
미서명 Mac 패키징 폴백을 구현하여 인증서 없이도 빌드가 가능하도록 처리했습니다. macOS drag region 이슈와 중복 relayout 핸들러도 함께 수정했습니다.
dev 브랜치에 push할 때마다 전체 배포 워크플로가 실행되면서, 불필요한 빌드와 배포가 반복됐습니다.
dev 브랜치의 push 이벤트에서 자동 배포 트리거를 제거하고, 특정 feature 브랜치와 workflow_dispatch로만 배포되도록 수정했습니다. concurrency group을 설정하여 동시 배포를 방지했습니다.
AI 모델 교체 과정에서 맞춤법 검사 기능의 응답이 불안정했고, AI 패널과 캐릭터 이름 생성 기능에서 간헐적 오류가 발생했습니다.
AI 모델을 단계적으로 교체하면서 각 기능별 안정성을 검증했습니다. 맞춤법 검사 모델을 4차례 반복 수정하고, AI 패널 응답 처리와 캐릭터 이름 생성 로직을 안정화했습니다.
Summary
Prometheus + Grafana로 GPU 리소스를 실시간 관측하고, 데이터를 근거로 모델 정밀도와 양자화 수준을 결정했습니다.
제한된 리소스(10GB VM)에서 DB 배치를 최적화하고, 멀티 도메인 환경에서 Traefik을 선택하는 등 상황에 맞는 판단을 내렸습니다.
CuKee 6개, Gleey 5개의 CI/CD 워크플로를 구성하여, 빌드 환경·비용·배포 대상에 따라 파이프라인을 분리했습니다.
GPU 호환성, 데스크톱 패키징, 배포 트리거 과잉 등의 문제를 커밋 단위로 추적하며 단계적으로 해결했습니다.