티스토리 뷰
- airflow 대신 n8n을 사용했으나 n8n은 코드 기반의 작업이 어려워서 airflow로 마이그레이션하는 과정에서 배워간 기록입니다.
1. Airflow 핵심 개념: DAG와 스크립트의 관계
DAG란 무엇인가?
DAG(Directed Acyclic Graph, 방향성 비순환 그래프)는 작업(Task)들의 실행 순서와 의존관계를 정의한 하나의 워크플로우입니다. Airflow에서 DAG 파일 자체는 실제 데이터 처리 로직을 담기보다는, 어떤 스크립트를(Task) 어떤 순서로, 어떤 주기로 실행할지 정의하는 역할을 합니다.
예시: 독립적인 두 개의 수집 파이프라인
- 네이버 뉴스 수집: 매시간 최신 뉴스를 수집하는 파이프라인
- 위키피디아 수집: 매일 특정 주제의 문서를 수집하는 파이프라인
Airflow에서는 이 두 워크플로우를 각각 별개의 DAG 파일로 정의하여 관리합니다.
naver_news_dag.pywikipedia_crawl_dag.py
스크립트와 DAG의 관계
- 스크립트(모듈): 실제 데이터 수집, 변환, 저장 등 비즈니스 로직을 수행하는 Python 함수 또는 클래스 파일.
- DAG 파일: 이 스크립트들을 어떤 순서와 조건으로 실행할지 정의하는 파일.
즉, 스크립트는 실제 일을 하고, DAG는 일의 순서와 스케줄을 정의합니다.
네이버 뉴스 수집 DAG의 태스크 구성 예시
하나의 naver_news_dag.py 파일은 내부적으로 여러 Task로 구성됩니다.
fetch_news_links: 특정 키워드의 뉴스 목록 페이지에서 기사 URL 수집scrape_articles: 수집된 URL 목록을 바탕으로 각 기사 본문을 병렬로 수집 (동적 태스크 매핑 활용)transform_data: 수집된 데이터를 정제하고 원하는 스키마(예: CSV, JSON)로 변환upload_to_db: 변환된 데이터를 데이터베이스에 적재
이 1~4번까지의 전체 흐름과 의존 관계를 정의한 것이 naver_news_dag입니다.
왜 DAG를 분리하여 운영하는가?
- 독립성: 스케줄, 리소스, 성공/실패 알림을 워크플로우별로 독립적으로 관리할 수 있습니다.
- 관리 용이성: 네이버 뉴스 수집 로직 변경이 위키피디아 수집 DAG에 영향을 주지 않습니다.
- 자원 분배: 각 DAG의 중요도에 따라 리소스 풀(Pool)이나 동시 실행 개수를 다르게 설정할 수 있습니다.
권장 파일 구조
실제 로직을 담은 코드는 별도 모듈로 분리하고, dags/ 디렉터리에는 DAG 정의 파일만 가볍게 유지하는 것이 좋습니다.
.
├── dags/
│ ├── naver_news_dag.py # DAG 정의 파일
│ ├── wikipedia_crawl_dag.py # DAG 정의 파일
│ └── modules/
│ ├── crawler.py # 실제 크롤링 함수
│ └── database_client.py # DB 연결 및 업로드 함수
├── config/
│ └── requirements.txt # Python 라이브러리 목록
├── docker-compose.yaml
└── .env
2. Docker 환경에서 파이프라인 구축 및 실행 절차
핵심 개념
- Airflow는 Docker 컨테이너 내부에서 실행됩니다. 따라서 DAG가 사용하는 모든 Python 라이브러리는 컨테이너 안에 설치되어야 합니다.
- 이 프로젝트는
docker-compose.yaml에 정의된_PIP_ADDITIONAL_REQUIREMENTS환경변수를 통해 컨테이너 시작 시config/requirements.txt파일에 명시된 라이브러리를 자동으로pip install합니다. - 로컬의
dags/폴더는 컨테이너 내부의/opt/airflow/dags/경로에 마운트되므로, 로컬에서 DAG 파일을 수정하면 즉시 컨테이너에 반영됩니다. - 설치를 위한 공식 문서: https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#initializing-environment
Docker 설정 상세 설명
_PIP_ADDITIONAL_REQUIREMENTS의 동작 원리와 사용법
이 환경 변수는 Airflow Docker 이미지가 컨테이너를 시작할 때마다 추가적으로 Python 라이브러리를 설치하도록 지시하는 역할을 합니다.
- 동작 원리: Airflow 공식 이미지 내부에는 컨테이너가 시작될 때 실행되는
entrypoint.sh스크립트가 있습니다. 이 스크립트는_PIP_ADDITIONAL_REQUIREMENTS환경 변수에 값이 있는지 확인하고, 만약 값이 있다면pip install [해당 값]명령을 실행합니다. - 왜 사용하는가?: Airflow DAG를 작성하려면
pandas,requests,boto3등 다양한 외부 라이브러리가 필요합니다. 기본 Airflow 이미지에는 이런 라이브러리들이 없으므로, 우리가 직접 설치해주어야 DAG가 정상적으로 동작합니다. - 권장 사용법: 이 변수에 직접 패키지 목록을 나열하는 것(
"pandas requests")보다, 별도의requirements.txt파일을 만들어 관리하는 것이 훨씬 효율적입니다.volumes설정을 통해 로컬의./config/requirements.txt파일을 컨테이너의/opt/airflow/config/requirements.txt위치에 연결(마운트)했기 때문에, 컨테이너는 로컬 파일을 읽어서 라이브러리를 설치할 수 있습니다.
# .env 파일 또는 docker-compose.yaml 환경 변수 섹션에 아래와 같이 설정 _PIP_ADDITIONAL_REQUIREMENTS="-r /opt/airflow/config/requirements.txt"- 주의사항 (프로덕션 환경): 공식 문서에서도 경고하듯이 이 방법은 개발 및 빠른 테스트 용도로 적합합니다. 컨테이너가 재시작될 때마다 매번
pip install을 다시 실행하므로 시작 시간이 길어지고, 네트워크 상황에 따라 설치가 실패할 수 있습니다. 프로덕션 환경에서는 필요한 라이브러리를 미리 설치한 커스텀 Docker 이미지를 빌드해서 사용하는 것이 표준적인 방법입니다.
볼륨 마운트 (volumes)
로컬 컴퓨터의 디렉터리를 Docker 컨테이너 내부의 디렉터리와 연결하는 기능입니다. 컨테이너에 직접 들어가지 않고 로컬에서 코드를 수정할 수 있습니다.
${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags: 로컬의dags폴더를 컨테이너의/opt/airflow/dags폴더에 연결합니다. 로컬에서 DAG 파일을 추가하거나 수정하면 실시간으로 컨테이너에 반영됩니다.config,logs,plugins폴더도 동일한 원리로 연결됩니다.
airflow-init 서비스의 역할
이 서비스는 다른 Airflow 서비스들이 시작되기 전에 단 한 번 실행되어 초기화 작업을 수행하는 특수한 컨테이너입니다.
- Airflow 메타데이터 데이터베이스 스키마 생성 및 업그레이드 (
db init,db upgrade) - 기본 Airflow Admin 계정 생성
- 볼륨으로 마운트된 폴더들의 파일 권한(ownership) 설정
이 작업이 성공적으로 완료되어야 depends_on 설정에 따라 다른 서비스들이 순차적으로 시작됩니다.
docker-compose.yaml의 예시
# 이 파일은 Apache Airflow를 Docker 환경에서 실행하기 위한 최소한의 설정입니다.
# CeleryExecutor를 사용하며, PostgreSQL을 메타데이터 DB로, Redis를 메시지 브로커로 사용합니다.
# --- 공통 설정을 위한 YAML 앵커 정의 ---
# 여러 서비스에서 중복되는 설정을 &앵커이름 으로 정의하고, <<: *앵커이름 으로 재사용합니다.
x-airflow-common:
&airflow-common
# 사용할 Airflow Docker 이미지입니다. .env 파일에서 AIRFLOW_IMAGE_NAME으로 버전을 지정할 수 있습니다.
image: ${AIRFLOW_IMAGE_NAME:-apache/airflow:3.0.6}
environment:
# 모든 Airflow 컴포넌트가 공유하는 환경변수들을 &앵커이름 으로 정의합니다.
&airflow-common-env
# Airflow 실행 방식을 CeleryExecutor로 지정합니다.
AIRFLOW__CORE__EXECUTOR: CeleryExecutor
# 메타데이터 저장을 위한 PostgreSQL 데이터베이스 연결 정보입니다.
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://airflow:airflow@postgres/airflow
# Celery 작업 결과 백엔드로 데이터베이스를 사용하도록 설정합니다.
AIRFLOW__CELERY__RESULT_BACKEND: db+postgresql://airflow:airflow@postgres/airflow
# Celery 작업 큐를 위한 Redis 메시지 브로커 연결 정보입니다.
AIRFLOW__CELERY__BROKER_URL: redis://:@redis:6379/0
# DAG가 처음 UI에 표시될 때 'paused' 상태로 시작하도록 설정합니다. (권장: true)
AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'true'
# 예제 DAG를 불러올지 여부를 결정합니다. (개발 시 false 권장)
AIRFLOW__CORE__LOAD_EXAMPLES: 'false'
# 중요: 컨테이너 시작 시 추가로 설치할 Python 라이브러리를 지정합니다.
# 아래 설정은 컨테이너 내부의 /opt/airflow/config/requirements.txt 파일을 읽어 설치하라는 의미입니다.
_PIP_ADDITIONAL_REQUIREMENTS: ${_PIP_ADDITIONAL_REQUIREMENTS:--r /opt/airflow/config/requirements.txt}
# 로컬 디렉터리를 컨테이너 내부 디렉터리와 연결(마운트)합니다.
# 이를 통해 로컬에서 DAG 코드를 수정하면 바로 컨테이너에 반영됩니다.
volumes:
- ${AIRFLOW_PROJ_DIR:-.}/dags:/opt/airflow/dags
- ${AIRFLOW_PROJ_DIR:-.}/logs:/opt/airflow/logs
- ${AIRFLOW_PROJ_DIR:-.}/config:/opt/airflow/config
- ${AIRFLOW_PROJ_DIR:-.}/plugins:/opt/airflow/plugins
# 컨테이너 내부에서 실행될 유저의 ID를 지정합니다. => airflow 공식 도커 문서에서 자동으로 env에 추가되는 가이드를 제공합니다.
# https://airflow.apache.org/docs/apache-airflow/stable/howto/docker-compose/index.html#initializing-environment
# Linux/macOS에서 로컬 유저 ID와 맞춰주면 마운트된 볼륨의 파일 권한 문제를 방지할 수 있습니다.
user: "${AIRFLOW_UID:-50000}:0"
# 모든 Airflow 서비스가 postgres와 redis에 의존하도록 설정합니다.
# 이 서비스들이 먼저 정상 실행되어야 Airflow 서비스들이 시작됩니다.
depends_on:
&airflow-common-depends-on
redis:
condition: service_healthy
postgres:
condition: service_healthy
# --- 서비스 목록 정의 ---
services:
# Airflow 메타데이터를 저장할 PostgreSQL 데이터베이스 서비스
postgres:
image: postgres:13
environment:
POSTGRES_USER: airflow
POSTGRES_PASSWORD: airflow
POSTGRES_DB: airflow
volumes:
- postgres-db-volume:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-U", "airflow"]
interval: 10s
retries: 5
restart: always
# CeleryExecutor의 메시지 브로커 역할을 하는 Redis 서비스
redis:
image: redis:7.2-bookworm
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
retries: 50
restart: always
# Airflow 웹 UI 및 API 서버 역할을 하는 서비스
airflow-webserver:
<<: *airflow-common # 공통 설정 상속
command: webserver
ports:
- "8080:8080" # 로컬 8080 포트를 컨테이너 8080 포트와 연결
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8080/health"]
interval: 30s
retries: 5
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
# DAG를 스케줄링하고 Task를 실행 큐에 보내는 역할을 하는 서비스
airflow-scheduler:
<<: *airflow-common # 공통 설정 상속
command: scheduler
healthcheck:
test: ["CMD-SHELL", 'airflow jobs check --job-type SchedulerJob --hostname "$${HOSTNAME}"']
interval: 30s
retries: 5
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
# 실제 Task를 실행하는 작업자(Worker) 역할을 하는 서비스
airflow-worker:
<<: *airflow-common # 공통 설정 상속
command: celery worker
restart: always
depends_on:
<<: *airflow-common-depends-on
airflow-init:
condition: service_completed_successfully
# DB 초기화, 사용자 생성 등 1회성 작업을 수행하는 서비스
airflow-init:
<<: *airflow-common # 공통 설정 상속
command:
- bash
- -c
- |
# Airflow 데이터베이스 스키마를 초기화하거나 최신 상태로 마이그레이션합니다.
airflow db upgrade
# .env 파일에 정의된 값으로 기본 관리자 계정을 생성합니다.
airflow users create \
--username ${_AIRFLOW_WWW_USER_USERNAME:-airflow} \
--password ${_AIRFLOW_WWW_USER_PASSWORD:-airflow} \
--firstname Admin \
--lastname User \
--role Admin \
--email admin@example.com
environment:
<<: *airflow-common-env # 공통 환경변수 상속
# 이 서비스에서는 추가 라이브러리 설치가 필요 없으므로 빈 값으로 덮어씁니다.
_PIP_ADDITIONAL_REQUIREMENTS: ''
# --- 데이터베이스 영구 저장을 위한 볼륨 정의 ---
volumes:
postgres-db-volume:
필요한 파일 및 설정
config/requirements.txt:requests,beautifulsoup4,psycopg2-binary등 DAG에 필요한 외부 라이브러리를 명시합니다..env: DB 접속 정보, API 키 등 민감한 정보를 컨테이너 환경변수로 주입하기 위한 파일입니다. (env.example을 복사하여 생성)docker-compose.yaml:dags/,config/등 로컬 디렉터리를 컨테이너에 마운트하고, 환경변수를 설정하는 파일입니다.
실행 전 준비 사항
1. API 키 및 인증 정보 준비
- 파이프라인이 외부 서비스(예: 데이터베이스, 클라우드 스토리지)에 접속해야 한다면, 필요한 인증 정보(API 키, 자격증명 JSON 파일 등)를 준비합니다.
- 예시: 자격증명 파일을
config/creds.json경로에 저장합니다.
2. .env 파일 생성
- 프로젝트 최상위 경로에서
env.example파일을 복사하여.env파일을 생성합니다.
cp env.example .env
.env파일을 열어 프로젝트에 필요한 환경변수 값을 채웁니다.
# .env 예시
DATABASE_HOST=postgres
DATABASE_USER=user
DATABASE_PASSWORD=password
API_SECRET_KEY=your_secret_key
# 자격증명 파일 경로 (컨테이너 내부 경로 기준)
CREDENTIALS_FILE_PATH=/opt/airflow/config/creds.json
3. requirements.txt 확인
config/requirements.txt파일에 DAG 실행에 필요한 모든 Python 라이브러리가 포함되었는지 확인합니다.
# config/requirements.txt 예시
requests
beautifulsoup4
pandas
Airflow 컨테이너 실행
- 프로젝트 최상위 경로에서 다음 명령을 실행합니다.
docker compose up -d- 최초 실행 시, Airflow 컨테이너는
_PIP_ADDITIONAL_REQUIREMENTS환경변수를 읽어config/requirements.txt에 명시된 라이브러리를 설치합니다. 설치 로그는docker logs명령어로 확인할 수 있습니다.
Airflow 접속 및 DAG 실행
- 웹 UI 접속
- 웹 브라우저에서
http://localhost:8080으로 접속합니다. - 기본 계정: (ID:
airflow, PW:airflow)
- 웹 브라우저에서
- DAG 활성화
- UI 대시보드에서
naver_news_dag와wikipedia_crawl_dag를 찾아 좌측의 토글 버튼을 "On"으로 변경합니다.
- UI 대시보드에서
- DAG 실행 (Trigger)
- DAG 이름 우측의 실행(▶) 버튼을 눌러 수동으로 실행할 수 있습니다.
- 실행 시 필요한 변수를 전달하려면,
Trigger DAG w/ config옵션을 선택하고 JSON 형식으로 파라미터를 입력합니다.{ "keyword": "AI", "target_date": "2025-09-04" }
참고
Running Airflow in Docker — Airflow 3.0.6 Documentation
airflow.apache.org
- https://ssdragon.tistory.com/184
Airflow 설치 - Docker
Apache Airflow 공식 홈페이지 - Running Airflow in Docker 에서 참고하였습니다. 1. 시작 전 (Before you begin)Docker Community Edition(CE)을 본인 컴퓨터에 설치합니다. OS에 따라 Airflow 컨테이너가 제대로 실행되려
ssdragon.tistory.com
Airflow 엄청 자세한 튜토리얼 #왕초심자용
안녕하세요! 에어플로우 튜토리얼을 올린지도 2년이 훨씬 넘었네요! 글을 읽어주시는 분들 모두 감사드리고, 저는 그 사이에 미국에서 컴퓨터 사이언스 > 에어플로우에 대한 정보를 제공하는 정
velog.io
=> 개념 잡는 글로 추천합니다!
'개발일지' 카테고리의 다른 글
| [Database] Alembic으로 Postgres 테이블 생성 및 스키마 수정 (0) | 2025.10.29 |
|---|---|
| [PostgreSQL] Docker에 MeCab 설치하기 (Mac M4 pro 기준) (1) | 2025.09.18 |
| [MongoDB] 원격 서버 DB에 파이썬으로 대용량 데이터 삽입하기(pymongo) (1) | 2024.10.10 |
| [MongoDB] 윈도우에서 MongoDB 7 설치하기(환경변수 설정) (3) | 2024.09.05 |
| [Hadoop & Apache Spark] 하둡과 아파치 스파크-3 초기설정 및 실행/정지 (0) | 2024.06.28 |
- Total
- Today
- Yesterday
- Kafka
- cursorai
- geospy
- PEFT
- rdffox
- ChatGPT
- vscode
- rdflib
- vectorsearch
- LLM
- python
- Postgis
- 키워드추출
- Encoding
- hadoop
- vervel
- 지식그래프
- docker
- Claude
- TextRank
- vertorsearch
- AWS
- Vue3
- PostgreSQL
- pandas
- pdfmathtranslate
- deepseek
- MongoDB
- polars
- SPARQL
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |