이 글에서 다루는 것

DAG 내부에 로직을 넣지 않고, 별도 Python 학습 스크립트(train.py)를 BashOperator로 호출하여 코드와 오케스트레이션을 분리하는 패턴을 다룹니다.

선수지식


이 단계에서 해결하려는 문제

이전 단계에서는 학습 로직을 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.pymodel.pkl 파일이 보이면 성공


🔧 추가 설정: requirements.txt와 Docker 재빌드

  1. requirements.txt 작성:
scikit-learn
  1. Dockerfile 작성:
FROM apache/airflow:2.8.2
COPY requirements.txt /requirements.txt
USER airflow
RUN pip install --no-cache-dir -r /requirements.txt
  1. 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 통합