본문으로 건너뛰기

ML Plugin Train — Dagster UI 임베드 (#1508 / RFC #1476 결정 B')

ml_plugin 학습 트리거 운영자 가이드. RFC #1476 결정 = 옵션 B' (Dagster UI iframe 내장) — GenD UI 안에서 Dagster Playground 그대로 사용.

두 가이드 — 역할 분리 (#1537)

본 가이드 (ml-plugin-train.md) = 운영자 UI 시나리오 — GenD UI 안 iframe 로 클릭 + Playground 직접 사용. 이 페이지부터 보세요.

자동화 / CI / ETL 통합 = ml-plugin-train-trigger.mdPOST /api/v1/ml-plugins/{id}/train REST API 호출, 3-layer allowlist 보안, GraphQL launchRun 내부 구조.

운영자 절차 — GenD UI 안 Dagster 임베드

1. ML Plugin 선택

/admin/ml-plugins → 등록된 plugin 의 우측 액션 영역 → 👁 (detail) 아이콘 클릭 → detail sheet 오픈.

ML 플러그인 리스트

운영자 사이클 #1531 prod 캡쳐 (commit 7208a631). demo_credit_risk_plugin 1개 등록 + Capability badge (train / predict) + Provider Allowlist verified 표시.

2. Detail Sheet — Plugin 정보 + Train (Dagster) section

Detail Sheet 가 우측에서 슬라이드 인 → 상단에 plugin 정보 (Capability / Config / Serving Runtime / 메타데이터) + 하단에 "Train (Dagster)" section.

ML 플러그인 Detail Sheet

스크롤하면 Train (Dagster) section 안의 DagsterRunEmbed iframe (/dagster/locations/ml_plugin_train_repo/jobs/ml_plugin_train_job/playground) 노출:

Train (Dagster) iframe embed

위 캡쳐의 iframe 안 화면 — oauth2-proxy 의 "Sign in with Keycloak OIDC" 가 보이는 이유는 password-grant 토큰 주입 (E2E 캡쳐 path) 이 Dagster 의 oauth2-proxy 세션과 분리되기 때문. 실 운영자가 GenD UI 로 로그인하면 cookie 가 자동 공유되어 iframe 안에서 Dagster Playground 가 그대로 보임 — 별도 클릭 / 로그인 불필요.

3. Launch Run

Playground 안에서 직접:

  1. Run config editor — 다음 YAML 입력 (또는 minimum):
    ops:
    ml_plugin_train:
    config:
    plugin_id: "<UUID>" # plugin row id
    plugin_name: "demo_credit_risk_plugin"
    provider_class: "gend_api.services.ml_plugins.sklearn_baseline.SklearnBaselineProvider"
    plugin_config: {task: "classification", dataset_uri: "demo://"}
  2. Launch Run 버튼 → run id 즉시 발급
  3. 같은 iframe 안에서 step log / event log / asset materialization 모두 추적

4. 결과 확인

  • MLflow registry: mlflow.gend.svc.cluster.local:5000/#/models/<plugin_name> (별도 탭)
  • KServe InferenceService: kubectl --context aks-genos-prod -n gend get inferenceservice (운영자 ops)
  • Audit log: gend.audit channel — ml_plugin_train_triggered event

자동화 (API)

GenD UI 가 아닌 외부 시스템 / 스크립트 trigger:

TOKEN=$(curl -s -X POST "https://gend.genon.ai/auth/realms/gend/protocol/openid-connect/token" \
-d "grant_type=password" -d "client_id=gend-ui" \
-d "username=$ADMIN_USER" -d "password=$ADMIN_PASS" | jq -r .access_token)

curl -X POST "https://gend.genon.ai/api/v1/ml-plugins/$PLUGIN_ID/train" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
# → 202 + {"run_id":"<dagster_run_id>","plugin_id":"...","status":"queued"}

RFC #1476 옵션 B' 의 근거

A (UI 책무)B' (iframe embed) ← 선택
운영자 진입점GenD UI 안 액션 버튼GenD UI 안 iframe (같은 진입점)
step log / re-executeUI 가 wrap 구현Dagster UI 그대로
Dagster API 변경 영향UI fix 필요0 (iframe 안 자동 반영)
운영자 학습곡선GenD-only기존 Dagster 사용자 호환 + GenD-only 사용자도 같은 화면
구현 비용큰 (RunProgressDialog 신규)작은 (50-line iframe wrapper)

보안

  • iframe sandbox: allow-same-origin allow-scripts allow-forms allow-popups
    • allow-downloads / allow-top-navigation 거부 — 임베드된 콘텐츠가 부모 페이지 탈취 불가
  • 같은 gend.genon.ai 도메인 → X-Frame-Options: SAMEORIGIN 자연 호환
  • oauth2-proxy 가 같은 Keycloak 세션 사용 → silent SSO
  • CSP frame-src 'self' 명시 (ingress nginx config)

트러블슈팅

증상원인해결
iframe 빈 화면 + console "Refused to display ... in a frame"X-Frame-Options: DENY 헤더Dagster ingress 의 proxy_hide_header X-Frame-Options; 또는 SAMEORIGIN 으로 교체
iframe 안 "Login required"oauth2-proxy 세션 만료부모 페이지 새로고침 → 자동 재인증
Launch Run 후 step FAILURE(a) Dagster image stale (b) ml_plugin_train_repo workspace.yaml 미반영본 PR 의 cross-reference #1430 audit, PR #1431
iframe 안 navigation 후 GenD UI back 버튼 부조별도 navigation context의도된 설계 — iframe 안 history 는 부모와 분리

회귀 가드

  • ui/src/components/admin/MLPlugins/DagsterRunEmbed.test.tsx (6 vitest 케이스):
    • default src / custom job/location / view='runs' / sandbox attribute / 새 탭 링크 / height prop
  • ui/tests/ml-plugins-train-embed-e2e.spec.ts (3 Playwright):
    • detail sheet → Train 탭 → iframe 렌더 + src 검증
    • sandbox attribute strict
    • /dagster/ ingress 200/302/401 응답

관련