본문으로 건너뛰기

Alembic 마이그레이션

quant-ai의 DB 스키마는 Alembic으로 관리합니다. 마이그레이션은 멱등(idempotent) 하게 작성되어 있어 같은 head로 두 번 upgrade해도 안전합니다.

사전 요구 사항

  • TimescaleDB가 떠 있고 DATABASE_URL이 정확함 — 드라이버는 반드시 postgresql+psycopg:// (psycopg v3) 사용
  • api 컨테이너 안에서 alembic 실행
# 컨테이너 안에서
docker compose exec api alembic current

# 호스트에서 한 줄로
docker compose exec -T api alembic current

리비전 체인

00_baseline (no-op, 기존 BTC 스키마 stamp 용)
└─ 01_asset_class_enum (asset_class enum 추가)
└─ 02_market_asset_class (ohlcv 등 market 테이블에 asset_class)
└─ 03_trading_asset_class (trades / backtest_results)
└─ 04_exchange_keys_kis (KIS 컬럼: app_key, app_secret, account_no)
└─ 05_symbols_and_calendars (equity_symbols + market_calendars)
└─ 06_fx_rates (FX 환율 하이퍼테이블)
└─ 07_analysis_reports (analysis_reports + analysis_traces)
└─ 08_broker_events_queue (broker_order_events + queue)
├─ 09_positions_table (positions hypertable)
│ └─ 10_live_gating_tables (live_confirm_tokens, user_settings)
└─ 09_backtest_asset_class (backtest_results.asset_class)
└─ 10_exchange_keys_asset_class (exchange_keys.asset_class)
멀티 head

08_broker_events_queue에서 두 개의 09_* 브랜치로 분기합니다. 둘 다 선형 후속(10_live_gating_tables, 10_exchange_keys_asset_class)을 가지며 alembic upgrade head는 두 head를 모두 적용합니다. 분기는 의도적이며 alembic heads로 항상 두 줄을 확인하세요.

적용 (upgrade)

새 인스턴스

# 1) 컨테이너 부팅
docker compose up -d timescaledb redis api

# 2) 모든 마이그레이션을 head로
docker compose exec -T api alembic upgrade head

# 3) 검증
docker compose exec -T api alembic current
# 10_live_gating_tables (head) 또는
# 10_exchange_keys_asset_class (head)

기존 BTC-only 인스턴스 (Base.metadata.create_all로 만들어진 DB)

00_baseline은 의도적으로 비어 있어 기존 테이블을 다시 만들지 않습니다. 한 번만 stamp해서 기준점을 잡습니다.

# 1) 베이스라인을 stamp (실제 SQL은 실행되지 않음, alembic_version 행만 추가)
docker compose exec -T api alembic stamp 00_baseline

# 2) 그 위에서 head까지 upgrade
docker compose exec -T api alembic upgrade head

부분 적용

특정 revision만 올리고 멈추기:

docker compose exec -T api alembic upgrade 05_symbols_and_calendars

상대 경로로 한 단계만:

docker compose exec -T api alembic upgrade +1

롤백 (downgrade)

데이터 손실 가능

08_broker_events_queue 이전으로 되돌리면 큐 잔여 분석 작업과 broker audit 행이 함께 사라집니다. 특히 09_positions_table을 다운그레이드하면 하이퍼테이블의 압축 정책이 손실됩니다. 프로덕션 다운그레이드 전 반드시 pg_dump를 먼저 수행하세요.

# 한 단계 다운
docker compose exec -T api alembic downgrade -1

# 특정 revision으로 다운
docker compose exec -T api alembic downgrade 04_exchange_keys_kis

# 전부 되돌림 (위험)
docker compose exec -T api alembic downgrade base

운영 시나리오: 무중단 배포 + 마이그레이션

scripts/deploy_azure.sh는 다음 순서를 따릅니다.

1. ACR로 새 이미지 push
2. VM에서 docker compose pull
3. docker compose run --rm api alembic upgrade head ← 여기서 스키마 갱신
4. bash scripts/rolling_restart.sh ← 컨테이너 교체
5. /health 200 확인 (실패 시 --rollback)

이로써 새 이미지가 기동될 때는 이미 새 스키마가 적용되어 있어, 시작 실패가 거의 없습니다. 이는 모든 마이그레이션이 add-only이고 컬럼/테이블 삭제를 별도 revision으로 미루는 컨벤션 덕분입니다 — 구 이미지가 잠깐 새 스키마와 공존해도 호환됩니다.

검증

# 1. 현재 head
docker compose exec -T api alembic current
# 출력에 (head) 가 있어야 함

# 2. 모든 head 표시 (분기 확인)
docker compose exec -T api alembic heads
# 멀티 head가 정상 — 두 줄이 떠도 OK

# 3. 히스토리
docker compose exec -T api alembic history --verbose

트러블슈팅

증상원인 / 조치
relation "ohlcv" already exists기존 BTC 인스턴스에서 stamp 누락 → alembic stamp 00_baseline 후 다시 upgrade
extension "timescaledb" does not existTimescaleDB 이미지가 아닌 plain Postgres에 붙음. docker-compose.yml의 image를 timescale/timescaledb:latest-pg16으로
permission denied to create extension "pg_trgm"슈퍼유저로 실행해야 함. quant 유저는 default DB owner이지만 일부 클라우드 Postgres는 별도 권한 필요. RDS/CloudSQL 등 매니지드 DB라면 운영자가 1회 CREATE EXTENSION 수동 실행
column "asset_class" of relation "trades" already exists이미 부분 적용된 상태. alembic stamp <revision>으로 메타테이블만 동기화 후 head 시도
Multiple head revisions are present정상. alembic heads로 둘 다 확인하고 그대로 진행

자세한 케이스 분석은 DB 마이그레이션 실패를 참고하세요.

관련 페이지