Airflow 웹 UI의 뷰 커스터마이징
Airflow 웹 UI의 뷰 커스터마이징 (Customize view of Apache from Airflow web UI)
Plugin manager를 사용해 Airflow 핵심 UI와 함께 커스텀 UI를 통합하는 방법을 설명하는 문서예요. fastapi_apps, fastapi_root_middlewares, external_views, react_apps 네 가지 객체 참조와, React 플러그인 부트스트랩 툴로 외부 React 앱을 개발·통합하는 방법을 살펴볼게요.
출처: 문서
본문
Airflow에는 Plugin manager를 사용해 핵심 UI와 함께 커스텀 UI를 통합할 수 있는 기능이 있어요.
Plugins는 Airflow 핵심 RestAPI와 통합돼요. 이 플러그인에서는 airflow.plugins_manager.AirflowPlugin 기본 클래스에서 세 가지 객체 참조가 파생돼요. 그것은 fastapi_apps, fastapi_root_middlewares, external_views와 react_apps예요.
-
fastapi_apps를 Airflow 플러그인에서 사용하면 핵심 RestAPI를 확장해 커스텀 정적 파일이나 다른 json/application 응답을 제공하는 추가 엔드포인트를 지원할 수 있어요. 이 객체 참조에서는 FastAPI 애플리케이션과 name, url prefix 같은 메타데이터 정보가 담긴 딕셔너리 목록이 전달돼요.
-
fastapi_root_middlewares를 Airflow 플러그인에서 사용하면 FastAPI 애플리케이션의 루트에 커스텀 미들웨어를 등록할 수 있어요. 이 미들웨어는 핵심 엔드포인트를 포함한 전체 FastAPI 애플리케이션에 커스텀 헤더, 로깅 또는 다른 기능을 추가하는 데 사용할 수 있어요. 이 객체 참조에서는 Middleware 팩토리 객체, 초기화 파라미터, name 같은 메타데이터 정보가 담긴 딕셔너리 목록이 전달돼요.
-
external_views를 Airflow 플러그인에서 사용하면 Airflow UI에서 iframe이나 외부 링크로 렌더링되는 커스텀 뷰를 등록할 수 있어요. 이는 외부 애플리케이션이나 커스텀 대시보드를 Airflow UI에 통합하는 데 유용해요. 이 객체 참조에서는 뷰 이름, href(템플릿 가능), destination, icon과 url_route 같은 선택 파라미터가 담긴 딕셔너리 목록이 전달돼요.
-
react_apps를 Airflow 플러그인에서 사용하면 Airflow UI에서 렌더링할 수 있는 커스텀 React 애플리케이션을 등록할 수 있어요. 이는 커스텀 React 컴포넌트나 애플리케이션을 Airflow UI에 통합하는 데 유용해요. 이 객체 참조에서는 앱 이름, bundle_url(js 자산을 로드할 위치, 템플릿 가능), destination, icon과 url_route 같은 선택 파라미터가 담긴 딕셔너리 목록이 전달돼요.
fastapi_apps, fastapi_root_middlewares, external_views, react_apps를 등록하는 정보와 코드 샘플은 plugin에서 확인할 수 있어요.
Bootstrap Tool로 React 애플리케이션 개발하기 (Developing React Applications with the Bootstrap Tool)
경고 (Warning)
React 애플리케이션은 Airflow 3.1의 새로운 기능으로 실험적(experimental)으로 간주해야 해요. 이 기능은 사용자 피드백과 보고된 오류에 따라 향후 버전에서 경고 없이 변경될 수 있어요. UI와 플러그인 간의 의존성·상태 상호작용이 리팩터링될 수 있으며, 이는 제공된 부트스트랩 예제 프로젝트도 변경시킬 거예요.
이것은 실험적 기능이에요.
Airflow는 React 플러그인 부트스트랩 툴을 제공해 개발자가 외부 React 애플리케이션을 핵심 UI로 빠르게 생성·개발·통합할 수 있게 해요. 이는 Airflow UI를 커스터마이징하는 가장 유연하고 권장되는 방법이에요. 이 툴은 동적 import와 호환되고 호스트 Airflow 애플리케이션과 React 인스턴스를 공유하는 라이브러리로 빌드되는 완전한 React 프로젝트 구조를 생성해요.
새 React 플러그인 프로젝트 만들기 (Creating a New React Plugin Project)
Bootstrap 툴은 dev/react-plugin-tools/에 있고, 새 React 플러그인 프로젝트를 생성하는 간단한 CLI를 제공해요:
# Navigate to the bootstrap tool directory
cd dev/react-plugin-tools
# Create a new plugin project
python bootstrap.py my-awesome-plugin
# Or specify a custom directory
python bootstrap.py my-awesome-plugin --dir /path/to/my-projects/my-awesome-plugin
이것은 Vite, TypeScript, Chakra UI 통합, 그리고 Airflow의 UI와 통합되는 라이브러리로 빌드하는 적절한 구성을 갖춘 완전한 React 프로젝트를 생성해요.
경고 (Warning)
새 React Plugin 프로젝트를 만들 때는 bootstrap 툴을 사용하는 것을 강력히 권장해요. Airflow의 Core UI와의 호환성을 보장하려면 특정 번들링 구성이 필요한데, 프로젝트를 수동으로 설정하면 통합 문제가 생길 수 있어요. 이미 통합하려는 기존 React 프로젝트가 있다면, 참고용으로 bootstrap 툴 코드와 생성된 빌드 구성 파일을 살펴볼 수 있어요. React와 React-DOM은 호스트 애플리케이션과 공유되는 의존성이며 호환 가능한 버전이 필요해요.
React 개발 워크플로우 (React Development Workflow)
프로젝트가 생성되면 프로젝트 디렉토리의 README.md 파일에서 다음을 포함한 완전한 개발 지침을 참고하세요:
- 사용 가능한 개발 스크립트 (
pnpm dev,pnpm build등) - 프로젝트 구조 설명
- 핫 리로드가 있는 개발 워크플로우
- 프로덕션용 빌드
- 흔한 React 개발 문제 트러블슈팅
생성된 프로젝트는 필요한 모든 도구가 사전 구성되어 있고 Airflow의 UI 개발 패턴을 따르고 있어요.
Airflow와 통합하기 (Integrating with Airflow)
React 애플리케이션을 Airflow와 통합하려면 다음을 해야 해요:
- 빌드된 자산을 제공 (Serve the built assets) — 자신의 인프라에서 하거나
fastapi_apps를 사용해 Airflow 내에서 직접 할 수 있어요. - React 앱을 등록 (Register the React app) —
react_apps플러그인 구성을 사용해요.
예시 플러그인 구현 (Example Plugin Implementation)
React 애플리케이션을 제공하는 Airflow 플러그인을 만들어요:
from pathlib import Path
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
import mimetypes
from airflow.plugins_manager import AirflowPlugin
# Ensure proper MIME types for cjs files
mimetypes.add_type("application/javascript", ".cjs")
# Create FastAPI app to serve static files
app = FastAPI()
# Mount your React app's dist folder
react_app_directory = Path(__file__).parent.joinpath("my-awesome-plugin", "dist")
app.mount(
"/my-react-app",
StaticFiles(directory=react_app_directory, html=True),
name="my_react_app_static",
)
class MyReactPlugin(AirflowPlugin):
name = "My React Plugin"
# Serve static files
fastapi_apps = [
{
"app": app,
"url_prefix": "/my-plugin",
"name": "My Plugin Static Server",
}
]
# Register React application
react_apps = [
{
"name": "My Awesome React App",
"url_route": "my-awesome-app",
"bundle_url": "https://airflow-domain/my-plugin/my-react-app/main.umd.cjs",
"destination": "nav",
}
]
플러그인 구성 옵션 (Plugin Configuration Options)
React 앱은 몇 가지 구성 옵션을 지원해요. 자세한 내용은 plugin을 참고하세요.
통합 모범 사례 (Integration Best Practices)
생성된 템플릿은 Airflow 통합에 이 모범 사례를 따르고 있어요:
- 외부 의존성 (External Dependencies) — React와 공통 라이브러리는 호스트 애플리케이션과의 충돌을 피하기 위해 외부로 표시돼요.
- 전역 명명 (Global Naming) — 일관성을 위해 표준화된 전역 이름(
AirflowPlugin)을 사용해요. - 라이브러리 빌드 (Library Build) — 동적 import를 위한 적절한 외부화와 함께 UMD 라이브러리로 구성돼요.
- MIME 타입 (MIME Types) — FastAPI가 기본적으로
.cjs파일을 평문 텍스트로 제공하므로,.cjs파일에 대한 적절한 JavaScript MIME 타입 처리를 해요.
배포 전략 (Deployment Strategies)
외부 호스팅 (External Hosting)
자산을 외부 인프라에서 호스팅할 수도 있어요:
react_apps = [
{
"name": "My External App",
"url_route": "my-external-app",
"bundle_url": "https://my-cdn.com/main.umd.cjs",
"destination": "nav",
}
]
통합 문제 트러블슈팅 (Troubleshooting Integration Issues)
흔한 통합 문제와 해결책:
- MIME 타입 문제 —
mimetypes.add_type("application/javascript", ".cjs")를 사용해.js와.cjs파일이 올바른 MIME 타입으로 제공되도록 해요. - 컴포넌트가 로드되지 않음 — bundle URL에 접근 가능하고 예상 형식과 일치하는지 확인해요.
- React 개발 문제 — 프로젝트와 함께 생성된
README.md파일에서 React 특유의 개발 문제 트러블슈팅을 참고하세요.
Airflow 2 플러그인 지원 (Support for Airflow 2 plugins)
Airflow 2 플러그인은 몇 가지 제한과 함께 여전히 지원돼요. 그러한 플러그인에 대한 자세한 정보는 Airflow 2 문서에서 찾을 수 있어요.
blueprints를 통한 Rest 엔드포인트 추가는 여전히 지원되고, 그 엔드포인트들은 WSGI Middleware를 통해 FastAPI 애플리케이션에 통합되어 /pluginsv2 아래에서 접근할 수 있어요.
Airflow 2를 통한 Flask-AppBuilder 뷰(appbuilder_views) 추가는 자체 iframe에서 여전히 지원돼요.
AF3 핵심 UI(예: 기본 템플릿 확장)를 확장하는 것은 불가능하지만, auth manager의 추가 메뉴 항목이 핵심 UI 보안 탭에 추가되고 그 href는 iframe에서 렌더링돼요. 이것이 fab provider가 Airflow 3 UI에 users, roles, actions, resources, permissions 커스텀 뷰를 통합하는 방식이에요.
Airflow 3 플러그인은 전체 react 앱에 대한 UI 커스터마이징을 허용하도록 개선될 거예요. 가능하면 플러그인을 Airflow 3 플러그인으로 업그레이드하는 것을 권장해요. 그때까지 임시적이거나 커스텀한 요구에는 Middleware를 사용해 핵심 UI index 요청에 커스텀 javascript나 css를 주입할 수 있어요.