이 글에서 다루는 것
DAG 내부에 로직을 넣지 않고, 별도 Python 학습 스크립트(train.py)를 BashOperator로 호출하여 코드와 오케스트레이션을 분리하는 패턴을 다룹니다.
선수지식
- Airflow 3단계: ML 파이프라인 DAG 구성 — DAG 구조와 XCom 전달
이 단계에서 해결하려는 문제
이전 단계에서는 학습 로직을 DAG 파일 안에 직접 작성했습니다. 하지만 실무에서는 학습 코드가 수백 줄 이상이고, 데이터 사이언티스트가 별도로 관리합니다. DAG는 오케스트레이션만 담당하고, 학습 코드는 독립 스크립트로 분리해야 유지보수와 협업이 가능합니다.
실습 코드: GitHub (BashOperator_and_Python_ML_Script)
🧭 실습 전체 흐름 요약
[1단계] 학습 스크립트 작성
[2단계] BashOperator로 스크립트 실행 DAG 구성
[3단계] Airflow 웹 UI에서 실행 및 로그 확인
📁 디렉토리 구조
airflow/
├── dags/
│ └── run_train_script.py ← DAG 파일
├── ml_code/
│ ├── train.py ← 모델 학습 스크립트
│ └── model.pkl ← 학습된 모델 파일
🧪 [1단계] 학습 스크립트 작성 (train.py)
# airflow/ml_code/train.py
import pickle
from sklearn.datasets import load_iris
from sklearn.ensemble import RandomForestClassifier
data = load_iris()
X, y = data.data, data.target
model = RandomForestClassifier()
model.fit(X, y)
model_path = "/opt/airflow/ml_code/model.pkl"
with open(model_path, "wb") as f:
pickle.dump(model, f)
모델은
/opt/airflow/ml_code/model.pkl경로에 저장됩니다.
🧪 [2단계] DAG 작성 (run_train_script.py)
# airflow/dags/run_train_script.py
from airflow import DAG
from airflow.operators.bash import BashOperator
from datetime import datetime
with DAG(
dag_id='bash_run_train',
start_date=datetime(2023, 1, 1),
schedule_interval=None,
catchup=False,
) as dag:
run_training = BashOperator(
task_id='run_train_script',
bash_command='python3 /opt/airflow/ml_code/train.py'
)
train.py는 Airflow 컨테이너 내/opt/airflow/ml_code/경로에 위치해야 합니다.
✅ [3단계] Airflow 컨테이너 진입 및 확인
docker exec -it airflow-airflow-webserver-1 bash
cd /opt/airflow/ml_code
ls -l
train.py와model.pkl파일이 보이면 성공
🔧 추가 설정: requirements.txt와 Docker 재빌드
- requirements.txt 작성:
scikit-learn
- Dockerfile 작성:
FROM apache/airflow:2.8.2
COPY requirements.txt /requirements.txt
USER airflow
RUN pip install --no-cache-dir -r /requirements.txt
- Docker Compose 재빌드:
docker-compose down
docker-compose build
docker-compose up -d
🔍 확인 포인트
| 항목 | 확인 방법 |
|---|---|
| 모델 파일 생성 | airflow/ml_code/model.pkl 존재 확인 |
| 로그 출력 | DAG > Task Logs에서 출력 메시지 확인 |
설계 판단 (Why This Way?)
DAG는 오케스트레이션(언제, 무엇을)만 담당하고 학습 로직은 별도 스크립트로 분리하여 의존성 충돌을 방지합니다. 프로덕션에서는 KubernetesPodOperator로 학습 전용 컨테이너를 격리하는 것이 표준 패턴입니다.
다음에 읽을 글
→ Airflow 5단계: PythonOperator + MLflow Tracking 연동 — 실험 추적과 DAG 통합