“복잡한 Zabbix 운영을 더 효율적으로 만들고 싶다면,
블로그의 핵심 내용을 집대성한 『Zabbix 엔터프라이즈 최적화 핸드북(PDF)』을 확인해보세요.”
https://jikimy.gumroad.com/l/zabbix-master
배경
내가 책임지고 있는 팀은
Cloud Engineer / DevOps / Data Engineer 세 파트로 나뉘어 있다.
어느 날 Data Engineer 팀원이 “Airflow DAG 성공 여부를 Alert으로 받고 싶다” 는 니즈를 제기했다.
Airflow Web UI에서 DAG 실행 상태는 확인할 수 있지만, 장애 Alert으로 바로 받아볼
방법은 없었다.
검색해보니 Prometheus 기반 대시보드 예제는 조금 있었지만, 정작 실패 Alert에 초점을 맞춘 레퍼런스는 없었다.
그래서 결국 Discovery → Item Prototype → Trigger Prototype까지 직접 만들어서 구현했다.
이 글에서는 온프레미스 Kubernetes 환경에서 Zabbix로 Airflow DAG 상태를 모니터링했던 방법을 공유한다.: airflow rest api와 통신만 된다면 온프레미스 kubernetes 든
클라우드 환경이든 상관없이 이 방법을 응용만 하면 되는 부분이니 참고들 바란다.
zabbix agent 및 기타 설정에 관한 설명은 따로 하지 않도록 하겠다.
왜 DAG Alert만으론 부족할까?
- DAG이 실패하는 경우도 문제지만, 더 근본적인 문제는 Airflow 자체가 정상적으로 동작하지 않는 상황이다.
- Scheduler가 멈추면 DAG이 아예 실행되지 않고, Metadata DB 연결이 끊기면 시스템 전체가 정지된다. Trigger 프로세스가 죽으면 특정 이벤트 기반 DAG 실행이 전혀 일어나지 않는다.
- 즉, DAG 실패 Alert은 증상이고, Airflow 헬스 Alert은 원인 진단에 가깝다.
- 둘을 같이 모니터링해야 장애를 빠르게 인지하고 조치할 수 있다.
컨셉
- Airflow REST API에서 DAG ID 목록을 주기적으로 수집한다.
- 각 DAG 실행 결과를 API로 조회한다.
- 최근 실행이
failed이면 Zabbix 트리거로 Alert을 발생시킨다.
1. Zabbix 서버(Ubuntu)에서 하는
작업
1-1. DAG ID 수집 스크립트 작성
Zabbix 서버에서 Airflow API를 호출해 DAG ID 목록을 가져온다.
daginfo.sh : api_url / username / password 등 주요 설정 값은
각자의 운영 환경에 맞춰 수정해야 한다
#!/bin/bash
API_URL="http://192.102.200.97:8080/api/v1/dags"
USERNAME="testuser"
PASSWORD="testpasswd"
LIMIT=100 # 한 번에 가져올 최대 DAG 수
OFFSET=0
OUT_FILE="/tmp/airflow_dag_ids.txt"
RESP_FILE="/tmp/airflow_response.json"
# 결과 파일 초기화
> "$OUT_FILE"
while true; do
# 현재 OFFSET과 LIMIT으로 API 호출
HTTP_STATUS=$(
curl -s -u "$USERNAME:$PASSWORD" \
-o "$RESP_FILE" \
-w "%{http_code}" \
"${API_URL}?limit=${LIMIT}&offset=${OFFSET}"
)
# HTTP 상태 코드 확인
if [ "$HTTP_STATUS" -ne 200 ]; then
echo "Error: Received HTTP status $HTTP_STATUS" >&2
echo "Response content:" >&2
cat "$RESP_FILE" >&2
break
fi
# dag_id만 추출하고 텍스트 파일에 추가
# (경로 변경되면 Zabbix master item에도 동일하게 반영할 것)
jq -r '.dags[].dag_id' "$RESP_FILE" >> "$OUT_FILE"
# 이번 페이지에 DAG가 몇 개 있었는지 확인
DAG_COUNT=$(jq '.dags | length' "$RESP_FILE")
# 더 이상 DAG가 없으면 종료
if [ "$DAG_COUNT" -eq 0 ]; then
break
fi
# 다음 OFFSET으로 이동
OFFSET=$((OFFSET + LIMIT))
done
echo "All DAG IDs saved to $OUT_FILE"
- jq 설치 : apt install -y jq
- chmod +x daginfo.sh
- daginfo.sh 최초 실행
- 크론탭 등록 (3시간마다 실행):
0 */3 * * * /home/example/daginfo.sh
2. Zabbix (7.4) UI에서 하는 작업
사전 작업 : airflow dag 에 관한 호스트 그룹 및 호스트 생성
2-1. Master Item 생성
- 이름:
dagid master item - 키:
vfs.file.contents[/tmp/airflow_dag_ids.txt] - 타입: Zabbix agent
- 데이터형: 텍스트
- 인터페이스:
127.0.0.1:10050 - 갱신 간격: 2h

2-2. LLD(Discovery) 규칙 생성
Master Item에서 가져온 DAG ID 목록을 기반으로 Discovery 수행.
해당 호스트의 디스커버리 규칙 클릭 및 디스커버리 규칙 생성 클릭
- 이름:
Airflow DAGID Discovery - 종류: 의존 아이템
- 키:
airflow.discovery.dagsid(임의 지정 가능) - 마스터 아이템: 위에서 만든
dagid master item - 전처리 (JavaScript):
try {
// value 값 출력 (디버깅용)
console.log("Input value received:", value);
if (!value) {
console.log("No value received or value is empty.");
return JSON.stringify({ "data": [] });
}
// 파일의 내용을 줄 단위로 분할 (윈도우와 유닉스 개행 문자 모두 처리)
var lines = value.split(/\r?\n/);
// DAG ID 목록을 저장할 배열 초기화
var data = [];
// 각 줄을 순회하면서 JSON 객체로 변환하여 배열에 추가
for (var i = 0; i < lines.length; i++) {
var dag_id = lines[i].trim(); // 양 끝 공백 제거
if (dag_id) { // 빈 줄이 아닌 경우만 추가
data.push({ "{#DAG_ID}": dag_id });
console.log("DAG ID added:", dag_id);
} else {
console.log("Empty line at index:", i);
}
}
console.log("Total DAG IDs found:", data.length);
// JSON 형식으로 반환하여 LLD에서 사용할 수 있도록 설정
return JSON.stringify({ "data": data });
} catch (error) {
console.log("Error in JavaScript preprocessing:", error);
return JSON.stringify({ "data": [] });
}


2-3. Item Prototype 생성
각 DAG 실행 상태를 REST API로 확인.
- 이름:
DAG {#DAG_ID} Runs 상태 - 종류 : HTTP 에이전트
- 키:
dagruns.status[{#DAG_ID}] - 데이터형 : 수치 (unsigned)
- URL:
http://192.: 실제 api ip 적용102.200.97:8080/api/v1/dags/{#DAG_ID}/dagRuns?order_by=-execution_date - HTTP 인증: Basic Auth (Airflow 계정)
- 갱신 간격: 5m
- 호스트 인터페이스 : 127.0.0.1:10050
- 전처리 (JavaScript):
// JSON 데이터 파싱
var parsedData;
try {
parsedData = JSON.parse(value);
} catch (e) {
throw "JSON 파싱 오류 발생";
}
// 최신 dagRun만 추출
if (parsedData.dag_runs && parsedData.dag_runs.length > 0) {
// 가장 최신의 dag_run 상태 가져오기
var latestRun = parsedData.dag_runs[0];
var state = latestRun.state;
// 상태에 따라 반환값 설정
if (state === "failed") {
return 1;
} else if (state === "success" || state === "running") {
return 0;
} else {
return 0;
}
} else {
// 빈 데이터인 경우 (실행 이력이 없는 경우)
return 0;
}
- 반환값:
- 실패 →
1 - 성공/실행중 →
0
- 실패 →



2-4. Trigger Prototype 생성 :
조건식과 복구조건식에서 아이템 프로토타입
선택
- 이름:
DAG {#DAG_ID} 상태가 정상이 아닙니다 - 조건식:
last(/Airflow - example Product/dagruns.status[{#DAG_ID}])=1 - 복구조건:
last(/Airflow - example Product/dagruns.status[{#DAG_ID}])=0 - 심각도: 가벼운 장애 (상황에 따라 변경)

2-5. Airflow 헬스 상태 체크 Item 만들기
: 트리거에 대한 가이드는 생략
(1) Scheduler Health
- 이름:
Airflow 스케줄러 health 상태 체크 - 종류: HTTP 에이전트
- 키 : airflow.health
- 데이터형: 수치(unsigned)
- URL:
http://192.:8080/health102.200.97 - 요구 스테이터스 코드 : 200
- 인증: Basic Auth (Airflow 계정)
- 전처리 (JavaScript):
// JSON 데이터 파싱
var parsedData;
try {
if (!value) throw "데이터가 비어 있습니다";
parsedData = JSON.parse(value);
} catch (e) {
return 1; // JSON 파싱 오류 시 비정상 상태로 간주하여 1 반환
}
// scheduler 상태 확인
if (parsedData.scheduler && parsedData.scheduler.status === "healthy") {
return 0; // "healthy"일 경우 0 반환
} else {
return 1; // 그 외의 경우 1 반환
}



(2) Metadata DB Health Item 만들기
- 이름:
Airflow metadata health - 종류 : HTTP 에이전트
- 키:
airflow.metadata.health - 데이터형: 수치(unsigned)
- URL:
http://192.102.200.97:8080/health - 요구 스테이터스 코드 : 200
- 인증: Basic Auth (Airflow 계정)
- 전처리 (JavaScript):
// JSON 데이터 파싱
var parsedData;
try {
if (!value) throw "데이터가 비어 있습니다";
parsedData = JSON.parse(value);
} catch (e) {
return 1; // JSON 파싱 오류 시 비정상 상태로 간주하여 1 반환
}
// scheduler 상태 확인
if (parsedData.metadatabase && parsedData.metadatabase.status === "healthy") {
return 0; // "healthy"일 경우 0 반환
} else {
return 1; // 그 외의 경우 1 반환
}



(3) Trigger Health
- 이름:
Airflow trigger health 상태 체크 - 종류: HTTP 에이전트
- 키:
airflow.trigger.health - 데이터형: 수치(unsigned)
- URL:
http://192.102.200.97:8080/health - 요구 스테이터스 코드 : 200
- 인증: Basic Auth (Airflow 계정)
- 전처리 (JavaScript):
// JSON 데이터 파싱
var parsedData;
try {
if (!value) throw "데이터가 비어 있습니다";
parsedData = JSON.parse(value);
} catch (e) {
return 1; // JSON 파싱 오류 시 비정상 상태로 간주하여 1 반환
}
// scheduler 상태 확인
if (parsedData.triggerer && parsedData.triggerer.status === "healthy") {
return 0; // "healthy"일 경우 0 반환
} else {
return 1; // 그 외의 경우 1 반환
}



마무리
이 구성을 적용하면 Zabbix가 Airflow REST API를 통해:
- DAG ID를 자동 수집하고, 각 DAG의 최근 실행 실패 여부를 Alert으로 제공
- 동시에 Scheduler / Metadata DB / Trigger 프로세스의 헬스 상태까지 감시
즉, DAG 실패 alert(증상) 과 Airflow 헬스 alert(원인) 을 동시에 제공할 수 있다.
여기서의 airflow 환경은 온프레미스 Kubernetes였지만,
사실 이 방식은 어디서든 동일하다.
Airflow REST API에 접근 가능하기만 하면 VM, 클라우드, 매니지드 서비스 모두 적용할 수 있다.
이번처럼 Airflow를 다룰 때 운영자에게
정말 필요한 건 대시보드를 통한 분석이
아니라, 상태 변화를 즉시 받아볼 수 있는 Alert이다. 이 방법은 그 핵심 요구를
정확히 충족한다.
레퍼런스가 거의 없는 영역이라, 같은 고민을 하는 엔지니어들에게 도움이 되기를 바란다.
🛠 마지막 수정일: 2025.12.09
ⓒ 2025 엉뚱한 녀석의 블로그 [quirky guy's Blog]. All rights reserved. Unauthorized copying or redistribution of the text and images is prohibited. When sharing, please include the original source link.
💡 도움이 필요하신가요?
Zabbix, Kubernetes, 그리고 다양한 오픈소스 인프라 환경에 대한 구축, 운영, 최적화, 장애 분석,
광고 및 협업 제안이 필요하다면 언제든 편하게 연락 주세요.
📧 Contact: jikimy75@gmail.com
💼 Service: 구축 대행 | 성능 튜닝 | 장애 분석 컨설팅
📖 E-BooK [PDF] 전자책 (Gumroad):
Zabbix 엔터프라이즈 최적화 핸드북
블로그에서 다룬 Zabbix 관련 글들을 기반으로 실무 중심의 지침서로 재구성했습니다.
운영 환경에서 바로 적용할 수 있는 최적화·트러블슈팅 노하우까지 모두 포함되어 있습니다.
💡 Need Professional Support?
If you need deployment, optimization, or troubleshooting support for Zabbix, Kubernetes,
or any other open-source infrastructure in your production environment, or if you are interested in
sponsorships, ads, or technical collaboration, feel free to contact me anytime.
📧 Email: jikimy75@gmail.com
💼 Services: Deployment Support | Performance Tuning | Incident Analysis Consulting
📖 PDF eBook (Gumroad):
Zabbix Enterprise Optimization Handbook
A single, production-ready PDF that compiles my in-depth Zabbix and Kubernetes monitoring guides.
답글 남기기
댓글을 달기 위해서는 로그인해야합니다.