Data Engineering Zoomcamp Week 2 - Workflow Orchestration with Kestra
목차
이번 주(Week 2)는 데이터 엔지니어링에서 “파이프라인을 만드는 것”보다 더 중요할 수 있는,
파이프라인을 안정적으로 운영하게 만드는 기술을 배운 주차였다.
주제는 Workflow Orchestration, 도구는 Kestra.
데이터 파이프라인은 보통 다음처럼 여러 도구가 얽혀 있다.
- 데이터 다운로드(wget/HTTP)
- 변환(Python)
- 적재(PostgreSQL / BigQuery)
- 스케줄 실행(매일/매월)
- 실패 시 재시도 / 알림 / 로그
- 과거 데이터 채우기(backfill)
이걸 사람이 수동으로 조율하면, 언젠가 반드시 삑난다.
그래서 “지휘자(Orchestrator)”가 필요해지고, Week 2는 그 지휘자를 Kestra로 구현해보는 과정이었다.
1. 워크플로우 오케스트레이션이란?
1) 개념: “파이프라인 지휘자”
워크플로우 오케스트레이션은 쉽게 말해:
여러 작업(태스크)을 정해진 순서/조건/시간에 맞춰 실행하고,
실패를 추적하고, 자동화하는 시스템
여기서 중요한 포인트는 “실행”만이 아니라 “운영”이다.
단순히 스크립트를 돌리는 건 누구나 할 수 있는데, 운영에서는 다음 문제가 항상 발생한다.
- 누락: 매일/매월 해야 하는데 사람이 잊는다.
- 실패: 네트워크, 권한, 스키마 변경, 리소스 부족으로 종종 터진다.
- 재실행: 실패한 시점부터 다시 돌려야 하는데 어디까지 처리됐는지 애매해진다.
- 가시성: “어디서 죽었는지” 로그/상태를 한 눈에 보고 싶다.
- 동시성: 동시에 여러 실행이 붙으면 DB에 중복 적재/락/충돌이 발생한다.
그래서 오케스트레이터는 단순 실행기가 아니라 다음 기능을 갖는다.
- 워크플로우 실행(정의된 단계들을 순서대로)
- 스케줄링(매일, 매월, 특정 시간)
- 이벤트 기반 실행(특정 파일 도착, 특정 이벤트 발생 시)
- 실패 감지 / 로깅 / 재시도 / 알림
- 실행 이력(Execution) 관리
- 동시성 제어(Concurrency)
- 과거 데이터 재처리(Backfill)
2) Kestra와 Airflow 비교
둘 다 오케스트레이터지만 “사용 감각”이 다르다.
Kestra
- YAML 기반으로 Flow를 정의한다. 코드 자산으로 관리하기 쉽다.
- 플러그인 중심이라 DB/클라우드/스크립트 실행을 “태스크로 붙이는 느낌”이 강하다.
- UI가 강력해서 실행 흐름(Gantt)과 로그를 보기 편하다. 초보자도 빠르게 감을 잡는다.
- 스케줄/이벤트 기반 트리거를 자연스럽게 지원한다.
Apache Airflow
- Python으로 DAG를 정의한다. 복잡한 로직은 강하지만 운영 난이도가 올라갈 수 있다.
- 생태계가 크고 실무 레퍼런스가 많다. 업계 표준에 가깝다.
- 개발자가 “오케스트레이션 로직 자체를 코드로 쥐고” 설계할 때 강점이 있다.
Week 2의 목표는 “개념 학습 + 빠르게 ETL/ELT 파이프라인 만들기”였고,
그 흐름에서 Kestra는 진입 장벽이 낮고, 눈으로 확인 가능한 부분이 많아서 학습에 잘 맞는다.
2. Kestra 설치 방법, 핵심 개념
1) 왜 Docker Compose로 설치하는가
오케스트레이터는 보통 단일 프로그램이 아니라, 메타데이터 DB, 실행 환경, UI 등이 함께 필요하다.
그래서 로컬 실습에서는 Docker Compose로 한 번에 올려 “재현 가능”하게 만든다.
보통 다음 구성으로 띄운다.
- Kestra 서버: UI + 스케줄러 + 실행 엔진
- PostgreSQL(메타데이터 DB): 실행 이력, 상태, 설정 등을 저장
- PostgreSQL(파이프라인 데이터 DB): NYC taxi 같은 실제 데이터를 적재
- pgAdmin: Postgres GUI
접속은 보통 Kestra UI http://localhost:8080.
포트 충돌(특히 8080)이 나면 docker-compose에서 포트 매핑을 바꿔야 한다.
2) Kestra 핵심 개념(실제로 YAML 읽을 때 중요)
- Flow: 태스크 묶음. 오케스트레이션 단위(하나의 파이프라인).
- Task: 실행 단계 하나. (wget, SQL 실행, 파일 삭제 등)
- Inputs: Flow 실행 시 주입되는 파라미터(택시 타입, 년/월 등).
- Variables: 문자열 조합/재사용. 파일명/테이블명 만드는 데 핵심.
- Outputs: 태스크 결과. “다운로드 파일 경로” 같은 걸 다음 태스크가 사용.
- Triggers: 자동 실행 장치. 스케줄/이벤트 기반 실행.
- Execution: Flow가 실제로 한 번 실행된 기록(상태, 로그, 시작/종료 시간).
- Plugin Defaults: 공통 설정(DB 접속 정보 등)을 반복하지 않게 기본값 지정.
- Concurrency: 동시 실행 제한. 중복 적재나 DB 충돌을 막는 장치.
- Namespace: Flow를 그룹으로 묶어 관리하는 논리적 경로.
특히 Variables / Outputs / Triggers를 이해하면, Kestra YAML이 “왜 이렇게 생겼는지”가 보인다.
3. 데이터 파이프라인 구축하기
Week 2에서 우리가 만든 데이터 파이프라인은 단순히 “CSV를 DB에 넣는 코드”가 아니다.
목표는 반복 실행 가능하고, 실패해도 다시 돌릴 수 있는 파이프라인을 만드는 것이다.
뉴욕 택시 데이터 파이프라인의 기본 흐름은 다음과 같다.
1) 입력값 받기 (taxi type, year, month)
2) 파일명 / 테이블명 동적 생성
3) GitHub에서 CSV 다운로드
4) 스테이징 테이블 적재
5) 고유 키 생성
6) 메인 테이블에 병합(MERGE)
7) 임시 파일 정리
이 흐름에서 중요한 점은 “각 단계가 독립적인 태스크(Task)”라는 것이다.
Kestra는 이 단계들을 순서대로 실행하면서,
어디서 실패했는지, 어떤 입력값으로 실행됐는지를 모두 기록한다.
즉, 이 파이프라인은 단순 ETL 코드가 아니라
운영 가능한 워크플로우다.
4. ETL: PostgreSQL 기반 파이프라인
04_postgres_taxi 흐름은 로컬 Postgres를 대상으로 한 ETL 파이프라인이다.
여기서 가장 중요한 설계 포인트는 Staging Table + Merge 전략이다.
1) 왜 바로 메인 테이블에 넣지 않을까?
CSV를 바로 메인 테이블에 넣으면 다음 문제가 생긴다.
- 같은 파일을 다시 실행하면 중복 데이터가 쌓인다
- 월별 데이터를 부분 재처리하기 어렵다
- 변환 로직을 적용하기가 까다롭다
그래서 실무에서는 거의 항상 다음 패턴을 쓴다.
CSV → Staging Table → 변환 → Main Table
2) 스테이징 테이블의 역할
- CSV 원본을 그대로 적재
- 실행 단위(월별)로 깨끗하게 초기화(TRUNCATE)
- 변환/검증/고유 키 생성 작업 수행
3) 고유 키(unique_row_id)가 핵심인 이유
택시 데이터에는 명시적인 primary key가 없다.
그래서 여러 컬럼을 조합해 md5 해시로 고유 ID를 만든다.
이 고유 ID는 사실상 “이 행의 지문(fingerprint)”이다.
MERGE 시 이 키를 기준으로:
- 이미 있는 데이터 → 무시
- 없는 데이터 → INSERT
이 덕분에 같은 파일을 여러 번 실행해도
데이터가 중복되지 않는다.
5. 스케줄링과 Backfill
1) 스케줄링이 필요한 이유
데이터 파이프라인은 “한 번 돌리고 끝”이 아니다.
- 매일 새 데이터가 쌓인다
- 매월 집계가 필요하다
- 사람이 기억해서 실행하면 반드시 빠진다
그래서 Kestra에서는 Trigger를 이용해 자동 실행한다.
cron: "0 9 1 * *"
→ 매월 1일 오전 9시 실행
2) trigger.date는 언제 생기나?
scheduled flow에서 자주 쓰는 표현식이 {{trigger.date}}다.
중요한 점은 이것이다:
- Trigger로 실행될 때만 trigger.date가 존재한다
- 수동 실행(Manual Execute)에는 trigger가 없다
그래서 trigger.date를 쓰는 flow를 수동 실행하면
에러가 나는 게 정상이다.
3) Backfill이란?
Backfill은 “과거 데이터를 한꺼번에 채워넣는 것”이다.
예를 들어:
- 2020년 전체 데이터를 지금 다시 적재
- 워크플로우가 만들어지기 전의 기간 재처리
Kestra UI에서는 날짜 범위를 지정해
트리거 실행을 과거로 소급(backfill)할 수 있다.
이 기능 덕분에:
- 12개월을 수동으로 실행할 필요가 없다
- 실패한 달만 골라서 재실행 가능하다
6. ETL vs ELT 비교
Week 2의 중요한 전환점은
“ETL만이 답이 아니다”라는 인식이다.
ETL
- Extract → Transform → Load
- 로컬 DB, 온프레미스 환경에 적합
- 변환 후 적재 → 저장 공간 절약
- 대규모 데이터에서는 변환이 병목
ELT
- Extract → Load → Transform
- 클라우드 DW(BigQuery 등)에 적합
- 원본 데이터를 그대로 보존
- 변환은 DW의 연산 성능을 활용
Zoomcamp 흐름도 이 차이를 명확히 보여준다.
- 로컬 Postgres → ETL
- GCP(BigQuery) → ELT
7. BigQuery로 데이터 로드
GCP 환경에서는 파이프라인 구조가 바뀐다.
GCP ELT 흐름
Extract → GCS 업로드 → BigQuery 테이블 생성 → BigQuery에서 변환
여기서 GCS는 데이터 레이크 역할을 한다.
즉, 원본 CSV를 보관하는 저장소다.
KV Store와 Secrets의 중요성
GCP 설정에는 민감한 정보가 많다.
- 서비스 계정 JSON
- 프로젝트 ID
- 버킷 이름
이걸 YAML에 하드코딩하면:
그래서 Kestra는 KV Store와 Secrets를 제공한다.
8. 워크플로우에 AI가 필요한 이유
데이터 엔지니어링 워크플로우는 생각보다 반복 작업이 많다.
- YAML 보일러플레이트
- 플러그인 옵션 기억
- 사소한 오타로 인한 실패
AI는 이 반복 작업을 줄이는 데 특화되어 있다.
하지만 중요한 전제가 있다.
AI는 컨텍스트가 없으면 반드시 틀린다.
범용 ChatGPT는:
- 플러그인 이름을 틀리거나
- 존재하지 않는 옵션을 만들어내거나
- 옛 문법을 섞어 쓴다
그래서 Kestra는 “자기 문서 기준”의 AI Copilot을 제공한다.
9. RAG(Retrieval Augmented Generation)란?
RAG는 AI의 환각(hallucination)을 줄이기 위한 핵심 기술이다.
개념은 단순하다.
질문 → 관련 문서 검색 → 문서를 포함해 AI에게 질문
즉, AI가 “기억”이 아니라
실제 문서를 근거로 답하게 만드는 방식이다.
Kestra 예제에서는:
- 릴리즈 노트 ingest
- 문서 임베딩 생성
- KV Store에 저장
- 질문 시 관련 문서 검색
이 덕분에:
- 존재하지 않는 기능을 말하지 않고
- 버전 기준으로 정확한 답변을 한다
마무리
Week 2는 Kestra를 “써본 주차”가 아니라,
- 왜 오케스트레이션이 필요한지
- ETL을 운영 가능한 구조로 만드는 법
- 스케줄링과 백필의 실전 의미
- 클라우드에서 ELT로 사고 전환
- AI를 쓸 때 왜 컨텍스트와 RAG가 중요한지
이걸 한 번에 연결해 이해하게 만든 주차였다.