본문으로 이동
Kim Jongwon
Projects

Job 실행 · 개인 프로젝트 · 단독 설계·구현 · 2026.02.02 - 2026.03.12

Kubernetes-based Stock Backtesting Platform

1 backtest = 1 Kubernetes Job

백테스트 실행을 Kubernetes Job으로 분리하고 run_id로 Web, Worker, DB, 관측 지표를 추적했습니다.

Execution

1 Job

1 backtest = 1 Kubernetes Job

Request ID

run_id

Web log, Worker log, MySQL 결과 레코드 연결

Observe

Grafana

Job launch와 전략 분포 관측

Flask Web, Kubernetes Job, MySQL로 구성된 백테스트 실행 구조 다이어그램
실행 아키텍처

Job Thread

요청 하나가 결과까지 도달하는 경로

Web process는 요청과 조회에 집중하고, 계산·상태·관측 지표는 별도 책임으로 둡니다.

요청

Flask Web

요청 접수와 상태 조회

계산

Kubernetes Job

백테스트 계산 실행

상태

MySQL

PENDING/RUNNING/SUCCEEDED 저장

관측

Grafana

실행 빈도와 Job launch 관측

왜 Job으로 뺐나

Job 실행 결정

긴 계산이 웹 요청 처리 경로를 지연시키는 문제가 있었습니다. 실행 위치를 바꾸고 각 실행을 Kubernetes Job 단위로 추적·재현하는 구조가 필요했습니다.

작업 파트

  • 개인 프로젝트로 실행 모델 설계, 구현, 배포, 검증 전 과정을 단독 수행했습니다.
  • 1 backtest = 1 Kubernetes Job 실행 모델을 설계했습니다.
  • 백테스트 실행 로직을 Adapter/Wrapper 방식으로 Kubernetes Worker에 적용했습니다.

핵심 결과

  • MSP 과정 개인 프로젝트 우수상
  • Stateless Web + ephemeral Worker 분리
  • run_id 기반 Web, Job, DB 추적

Web 밖에서 실행

Job 실행 경로

Web, Worker Job, DB, Grafana 지표를 run_id 중심으로 추적하는 구조입니다.

  • Flask Web은 요청 접수, 상태 조회, 결과 화면만 담당하고, 백테스트 계산은 ephemeral Worker Job으로 이동했습니다.
  • 각 실행은 run_id를 가진 독립 Kubernetes Job으로 생성되며, run parameters와 image tag로 재현 가능한 실행 단위를 정의합니다.
  • MySQL이 PENDING, RUNNING, SUCCEEDED 상태와 결과를 저장해 Web과 Worker 사이의 기준 상태 저장소 역할을 합니다.
  • GitHub Actions와 GHCR로 이미지를 배포하고, Argo CD와 ServiceMonitor가 배포 상태와 관측 지표 경로를 담당합니다.
Kubernetes JobsPython/FlaskMySQLArgo CDGrafana

실행 화면

아키텍처와 대시보드

최종 아키텍처, 백테스트 화면, Grafana 대시보드가 같은 실행 경로를 보여줍니다.

MSP 과정 개인 프로젝트 우수상 상장
개인 프로젝트 우수상
GitHub Actions, Argo CD, Ingress, Flask Web, Kubernetes Worker Job, MySQL, Prometheus와 Grafana를 포함한 최종 아키텍처
최종 아키텍처
주식 백테스트 플랫폼 대시보드 화면
백테스트 대시보드
Prometheus와 Grafana 기반 관측성 대시보드
관측성 대시보드
백테스트 결과의 매매 타점과 포트폴리오 분석 화면
포트폴리오 분석 화면
백테스트 핵심 KPI 요약 화면
결과 KPI 요약

실행 코드

Job 생성 코드

Job 생성과 실행 환경을 결정하는 코드입니다.

Kubernetes Job 생성 코드

launchers/job_launcher.py

metadata = client.V1ObjectMeta(
    name=build_job_name(_stringify(run_payload.get("run_id"))),
    namespace=self.namespace,
    labels={
        "app": "worker",
        "run_id": _stringify(run_payload.get("run_id")),
    },
)

container = client.V1Container(
    name="worker",
    image=self.worker_image,
    image_pull_policy="IfNotPresent",
    command=["python", "worker.py"],
    env=env,
    env_from=[
        client.V1EnvFromSource(
            config_map_ref=client.V1ConfigMapEnvSource(name=self.configmap_name)
        ),
        client.V1EnvFromSource(
            secret_ref=client.V1SecretEnvSource(name=self.secret_name)
        ),
    ],
)

실행 화면

실행 추적

Job 생성, 상태 저장, run_id 추적, 관측 지표 노출을 한 실행 경로로 구성했습니다.

run_id 중심 연결

  • Kubernetes Job 생성, 상태 저장, run_id 추적, 관측 지표 노출까지 실행 경로가 end-to-end로 작동합니다.
  • Web은 요청과 결과 조회만 담당하고, Worker Job이 계산과 실패 도메인을 독립적으로 처리합니다.