팰월드 프로메테우스 익스포터를 파이썬 50줄로 자작하기
집 서버에는 Prometheus + Grafana + Alertmanager 모니터링 스택이 돌고 있고, 마크 서버는 mc-monitor라는 기성 익스포터로 감시 중이다. 팰월드 서버를 새로 팠으니 얘도 같은 스택에 넣고 싶은데... mc-monitor는 마크 전용이라 팰월드를 모른다.
찾아보면 팰월드용 커뮤니티 익스포터가 있긴 할 거다. 근데 팰월드는 공식 REST API가 서버 지표를 이미 다 준다.
{"currentplayernum": 0, "serverfps": 59, "maxplayernum": 8, "uptime": 2604, ...}
이걸 프로메테우스 텍스트 포맷으로 바꿔주기만 하면 되는 일이다. 남의 이미지 검증할 시간에 그냥 만드는 게 빠르겠다 싶었음.
50줄이면 된다
외부 라이브러리 없이 파이썬 표준 라이브러리만 썼다. 스크레이프 요청이 올 때마다 팰월드 API를 찔러서 변환해주는 HTTP 서버가 전부다. 핵심만 보면
GAUGES = [
("palworld_players_online", "currentplayernum"),
("palworld_players_max", "maxplayernum"),
("palworld_server_fps", "serverfps"),
("palworld_uptime_seconds", "uptime"),
]
def render():
lines = []
try:
data = fetch_metrics() # REST API /v1/api/metrics
lines.append("palworld_up 1")
for name, key in GAUGES:
lines.append(f"{name} {data[key]}")
except Exception:
lines.append("palworld_up 0") # API가 죽었으면 그 자체가 지표
return "\n".join(lines)
API 응답이 없으면 palworld_up 0을 내보낸다. 실패도 지표다. 알림 규칙은 이거 하나 걸었다.
- alert: PalworldServerDown
expr: palworld_up == 0
for: 5m
labels: { severity: critical }
디스코드 알림 템플릿은 마크 때 한글로 만들어둔 걸 그대로 타니까 추가 작업이 없다. "팰월드 서버 응답 없음 → 발생함" 이렇게 온다.
네트워크 양다리
익스포터 컨테이너는 도커 네트워크 두 개에 걸쳐놨다. 모니터링 망에서는 프로메테우스한테 긁히고, 팰월드 망에서는 컨테이너 이름으로 API를 부른다. compose에서 external 네트워크 하나 더 붙이면 끝이라, 팰월드 쪽 포트를 호스트에 노출할 필요가 없다. 관리용 API는 도커 내부망 밖으로 안 나가는 게 맞다.
소소한 삽질
배포하고 프로메테우스 컨테이너에서 wget으로 익스포터를 찔러봤는데 이름이 안 풀렸다. bad address. 어? 같은 네트워크인데? 하고 한참 봤는데, 정작 프로메테우스 본체는 스크레이프를 잘만 하고 있었다. busybox wget의 리졸버랑 Go 리졸버가 도커 내장 DNS를 대하는 방식이 다른 모양. 검증 도구가 거짓말을 하면 멀쩡한 걸 의심하게 된다...
마치며
기성품 찾아 헤매는 것보다 표준 라이브러리 50줄이 빠른 경우가 있다. 이게 그런 경우였다.