-
Notifications
You must be signed in to change notification settings - Fork 0
Project Execution & Completion
이 문서는 Kubernetes 기반 주식 백테스팅 플랫폼의 설계, 구현, 검증, 완성 과정을 요약한다.
초기 설계 문서(Design Principles, ADR-Design Decisions)는 변경 없이 보존되어 있으며, 이 문서는 최종 구현 결과를 기존 Wiki 문서와 연결하는 요약 허브 역할을 한다.
1 Backtest = 1 Kubernetes Job
검증 완료된 레거시 Python 백테스트 엔진을 한 줄도 수정하지 않고, Docker 컨테이너로 감싸 Kubernetes Job으로 실행하는 클라우드 네이티브 플랫폼을 구축했다.
| 결정 | 근거 |
|---|---|
| Kubernetes Job 선택 | 1 백테스트 = 1 Pod으로 실행 격리. Celery + Redis 대비 별도 브로커 불필요, TTL 기반 자동 정리 ([[ADR-Design Decisions#ADR-001 |
| Stateless Web 계층 | 로컬 파일시스템 의존 제거. 수평 확장 시 코드 변경 불필요. 결과는 MySQL에 저장하거나 Base64로 인라인 반환 |
| GitOps 배포 (Argo CD) | Git이 인프라의 단일 진실 공급원. 선언형 매니페스트로 drift 자동 복구, 롤백은 Git revert로 완료 |
| 관측성 + 재현성 |
run_id 기반 전 구간 추적, 4개 재현성 식별자(data_hash, rule_type+params, engine_version, image_tag)로 동일 입력 = 동일 출력 보장 |
- 설계 원칙 상세 → Design Principles
- 의사결정 기록 (8개 ADR) → ADR-Design Decisions
- 통합 아키텍처 개요 → Final Architecture
프로젝트는 6개 Phase로 나누어 순차적으로 구현했다. 각 Phase는 이전 Phase의 결과물 위에 구축된다.
| Phase | 범위 | 핵심 산출물 |
|---|---|---|
| Phase 1 — 컨테이너화 | Flask 앱을 Docker 이미지로 패키징, docker compose up 한 줄로 개발 환경 구동 |
Dockerfile, docker-compose.yml, .env.example
|
| Phase 2 — K8s 런타임 | Web Deployment + MySQL StatefulSet, ConfigMap/Secret 환경변수 주입 |
k8s/*.yaml 매니페스트 세트, backtest_results DDL |
| Phase 3 — Job 오케스트레이션 | 백테스트 요청을 K8s Job으로 비동기 실행, Worker가 결과를 MySQL에 저장 |
worker.py, JobLauncher 추상화, /status/<run_id> API |
| Phase 4 — CI/CD & GitOps | GitHub Actions로 test → build → push, Argo CD로 자동 배포 |
.github/workflows/ci.yml, Argo CD Application |
| Phase 5 — 관측성 검증 | Rule 8 준수 확인, run_id 기반 전 구간 추적 검증, E2E 데모 |
scripts/demo.sh, Prometheus/Grafana(optional -> Successed) |
| Phase 6 — 문서화 | 아키텍처 다이어그램, 운영 가이드, 기술 회고 |
docs/ 디렉터리, Wiki 문서 |
백테스트 실행의 전체 흐름:
User Request → Web (입력 검증, PENDING insert) → K8s Job 생성
→ Worker (엔진 실행, 결과 저장) → MySQL Persistence
→ Web (/status/<run_id>로 결과 조회)
상태 머신은 PENDING → RUNNING → SUCCEEDED/FAILED 단방향 전이를 따른다.
- 실행 라이프사이클 상세 → Execution Lifecycle
- 배포 절차 및 환경 구축 → Deployment-and-Setup-Guide
- 장애 대응 런북 → Runbook-Troubleshooting
프로젝트 진행 중 아래 방법으로 구현 상태를 지속적으로 검증했다.
| 검증 항목 | 방법 | 참조 |
|---|---|---|
| E2E 파이프라인 검증 |
scripts/demo.sh로 백테스트 제출 → 상태 폴링 → 결과 확인 자동화 |
E2E-demo-verification |
| run_id 추적 검증 |
kubectl logs에서 Web → Worker → MySQL 전 구간 run_id 추적 |
E2E-demo-verification |
| 메트릭 모니터링 | Prometheus /metrics 엔드포인트, Grafana 대시보드로 request latency, job success rate 확인 |
Observability |
| 로깅 규격 준수 | 모든 컴포넌트가 stdout/stderr structured logging 사용, [run_id=<UUID>] 포맷 확인 |
Observability |
| CI/CD 파이프라인 |
git push → GitHub Actions green → 이미지 push → Argo CD auto-sync 확인 |
CI_CD_GitOps |
-
docker compose up→/health200 OK,/run_backtest정상 응답 -
kubectl apply -f k8s/→ Web Pod Ready, MySQL Pod Ready - 백테스트 요청 → K8s Job 생성 → MySQL에 결과 저장 →
/status/<run_id>=SUCCEEDED - CI/CD: push → test → build → deploy 전 과정 자동화 확인
구현 완료된 플랫폼의 핵심 구성 요소:
| 계층 | 구현 | 역할 |
|---|---|---|
| Flask Web | Gunicorn + Flask Deployment (Stateless) | 요청 검증, run_id 발급, Job 생성, 상태 조회, UI 렌더링 |
| K8s Worker Job | 1 백테스트 = 1 Pod (Ephemeral) | 엔진 실행, Adapter 파생 지표 계산, MySQL 결과 저장 |
| MySQL 8.0 | StatefulSet + PVC |
backtest_results 테이블 — 모든 결과의 단일 진실 공급원 |
| Prometheus + Grafana | ServiceMonitor + Dashboard JSON | HTTP latency, request count, job success/failure rate 모니터링 |
| GitHub Actions + Argo CD | CI (test → build → push) + CD (auto-sync) | Immutable image tag (:<git-sha-short>)로 배포 추적, Git 기반 롤백 |
동일한 4개 식별자(data_hash, rule_type+params, engine_version, image_tag)가 주어지면 동일한 백테스트 결과가 생성된다. 모든 식별자는 backtest_results 테이블에 저장되어 사후 감사가 가능하다.
backtest_results 테이블은 17개 컬럼으로 구성되며, 실행 상태(status), 재현성 식별자(data_hash, image_tag), 정규 데이터(equity_curve_json, trades_json, metrics_json), UTC 타임스탬프(created_at, started_at, completed_at)를 포함한다.
- 인프라 아키텍처 → Infra Architecture
- 애플리케이션 아키텍처 → App Architecture
- 통합 아키텍처 → Final Architecture
- 데이터 모델 → ERD-Data Model
- 재현성 체계 → Reproducibility
-
엔진 불변성 유지: 레거시 엔진을 수정하지 않으면서 5-tab 대시보드에 필요한 파생 지표(drawdown curve, portfolio curve, cumulative return)를 제공해야 했다. Adapter Layer 패턴으로 해결했으나, 엔진 내부 루프 접근이 필요한 기능(예: 실행 중 peak equity 추적)은 구현 불가 제약이 남았다.
-
Job 생성 오버헤드: Kubernetes Job은 Pod 생성에 ~5-10초 오버헤드가 발생한다. 짧은 백테스트에서는 실행 시간보다 인프라 오버헤드가 클 수 있다. Celery 대비 trade-off로 인지하고 수용했다.
-
Write Path / Read Path 분리: Write Path(Web → Job 생성 → Worker → MySQL 저장)와 Read Path(Web → MySQL 조회 → 응답)를 분리한 구조는 Web 계층이 실행 상태를 보유하지 않도록 하는 핵심 설계 결정이었다. 이를 통해 Web은 완전한 stateless를 유지하면서 비동기 실행과 결과 조회를 양립할 수 있었다.
-
Secret 관리: GitOps 환경에서 Secret을 Git에 커밋하지 않으면서 Argo CD 배포와 양립시키는 것이 도전이었다.
secret-template.yaml+ CI/CD 변수 주입 방식으로 해결했다. -
Argo CD Sync 상태 reconciliation: 로컬 개발 환경 재시작 후 CLI(
argocd app get) 또는kubectl로 Application 상태를 조회하면Unknownsync 상태가 표시되는 경우가 있었다. 그러나 Argo CD Web UI에 접속하면 상태가 재계산되어 정상(Synced/Healthy)으로 복구되었다. 이는 Argo CD controller의 reconciliation 타이밍 또는 status cache refresh 주기에 의한 동작으로, GitOps 운영 시 CLI 상태만으로 판단하지 않아야 한다는 교훈을 얻었다.
| 결정 | 얻은 것 | 포기한 것 |
|---|---|---|
| 애플리케이션 매니페스트는 Raw YAML 관리 | 매니페스트 투명성, 학습 곡선 최소화 | 환경별 분기, 템플릿 재사용성 |
| MySQL JSON 컬럼 | 스키마 유연성, 마이그레이션 불필요 | SQL 수준 쿼리 최적화, 정규화 |
| Immutable image tag (Git SHA) | 배포 추적, 롤백 보장 |
latest 태그 편의성 |
| 단일 네임스페이스 | 구성 단순화, RBAC 범위 명확 | 멀티 환경(dev/staging/prod) 분리 |
-
단일 환경: dev/staging/prod 분리 없이 단일 네임스페이스에서 운영. 애플리케이션 매니페스트는 Raw YAML로 관리하며, 관측성 스택(Prometheus/Grafana)은
kube-prometheus-stackHelm chart로 설치했다. 환경별 분기가 필요해지면 Kustomize 도입을 검토할 수 있다. - 자동 스케일링 미적용: 현재 아키텍처는 수평 확장 친화적으로 설계되어 있다(Web은 stateless, Worker Job은 요청별 독립 실행). 그러나 HPA(Horizontal Pod Autoscaler) 기반 자동 확장은 아직 적용되지 않아, 동시 요청 급증 시 수동 개입이 필요하다.
-
분산 트레이싱 부재:
run_idgrep 기반 추적은 소규모에서 충분하나, Pod 수 증가 시 OpenTelemetry 도입이 필요. -
데이터 lifecycle 미정의:
backtest_results테이블의 보존 기간, 압축, 아카이빙 정책이 미정의. -
외부 접근 아키텍처 (MetalLB): 현재는 Ingress + ClusterIP 구성으로 클러스터 내부 트래픽만 처리한다. on-prem/LAN 환경에서 외부 접근이 필요하면 MetalLB로 Ingress Controller에 LoadBalancer VIP를 부여하는 구성(
MetalLB VIP → Ingress → ClusterIP)을 검토할 수 있으나, 로컬 단일 클러스터 환경에서 LAN 접근이 요구사항이 아니므로 채택하지 않았다. - 클러스터 스케일링 전략: Control Plane HA(다중 마스터)와 Worker 노드 확장 두 가지를 검토했다. 이 플랫폼은 백테스트를 K8s Job으로 실행하므로 처리량과 격리성이 Worker 자원에 의존하며, Control Plane HA는 핵심 실행 모델 개선에 기여하지 않는다. 따라서 현재는 Control Plane 1노드 + Worker 노드 확장 가능 구성을 전제로 설계했다.
-
Kustomize: 애플리케이션 매니페스트의 환경별 분기 관리
-
멀티 환경 배포: dev → staging → prod 파이프라인
-
HPA + 오토스케일링: 백테스트 요청 부하에 따른 자동 확장
-
OpenTelemetry: 분산 트레이싱으로 Web → Worker → DB 구간 latency 프로파일링
-
Sealed Secrets / External Secrets Operator: GitOps 호환 시크릿 관리 강화
-
의사결정 기록 → ADR-Design Decisions
-
트러블슈팅 시나리오 → Runbook-Troubleshooting
전체 기술 문서는 아래 Wiki 페이지에서 확인할 수 있다.
- Design Principles — 8가지 아키텍처 원칙
- Scope & Non-Goals — 범위 및 의도적 비목표
- ADR-Design Decisions — 8개 Architecture Decision Records
- Final Architecture — 통합 아키텍처 개요
- Infra Architecture — K8s 토폴로지, 계층 구조
- App Architecture — Web↔Worker 책임 경계, Adapter Layer
- Execution Lifecycle — 상태 머신, Job 규격, 생명주기 정책
- API-Endpoints & Schemas — Endpoint 목록, Request/Response 스키마
-
ERD-Data Model —
backtest_results테이블 스키마 - Reproducibility — 재현성 식별자, 저장 경계
- CI_CD_GitOps — CI 파이프라인, GitOps 전략
- Deployment-and-Setup-Guide — 환경 구축, K8s 배포 절차
- Observability — Prometheus 메트릭, Grafana 대시보드
- Runbook-Troubleshooting — run_id 기반 장애 추적
- Rollback Runbook — Git 기반 롤백 절차
- E2E-demo-verification — E2E 데모 실행 및 검증 기록
- Testing Strategy — 테스트 전략