Prometheus 설정 리로드 실패 — 단일 파일 bind mount와 inode
Prometheus 를 docker compose 로 띄우고, 설정 파일은 호스트에 두고 컨테이너
안으로 마운트해서 씁니다. 타겟을 추가하거나 룰을 고칠 때는 호스트 파일을
갱신하고 /-/reload 만 부르면 되는 구조입니다.
그런데 설정을 고쳐 올려도 반영이 안 됐습니다. /-/reload 는 HTTP 200 을
주고 로그에도 “configuration reloaded successfully” 가 찍히는데 옛날 설정이
그대로 돌고, docker compose restart 를 해도 똑같았습니다.
믿을 수 없는 reload 응답
/-/reload 의 200 응답은 “파일을 다시 읽었다” 지
“내가 방금 고친 내용이 반영됐다” 가 아닙니다. 컨테이너가 보고 있는 파일을
다시 읽었을 뿐이고, 그 파일이 여전히 옛날 내용이면 옛날 걸로 잘 리로드됩니다.
그래서 반영 여부는 응답이 아니라 /api/v1/targets 를 직접 쿼리해서 봐야
합니다. 타겟 목록이 그대로면 리로드는 됐지만 내용이 안 바뀐 겁니다.
원인 — 단일 파일 bind mount의 inode 고정
compose 에서 설정을 이렇게 마운트하고 있었습니다.
volumes:
- ./prometheus.prod.yml:/etc/prometheus/prometheus.yml
파일 하나를 콕 집어 마운트하면, 도커는 그 파일의 inode 를 컨테이너 안에 묶습니다. 경로가 아니라 inode 입니다.
그런데 rsync 는 파일을 제자리에서 고치지 않습니다. 임시 파일에 쓴 다음
원자적으로 rename 합니다. mv, 그리고 임시 파일 후 교체하는 대부분의 에디터도
마찬가지입니다. rename 하면 새 inode 가 생깁니다. 호스트의 경로는 새
inode 를 가리키지만, 컨테이너는 여전히 옛날 inode 를 붙잡고 있습니다. 그래서
컨테이너 안에서는 파일 내용이 안 바뀐 겁니다.
restart 가 안 통한 이유도 같습니다. restart 는 프로세스만 다시 띄우지,
마운트(inode 바인딩)를 다시 걸지 않습니다.
해결 — 강제 재생성, 그리고 디렉토리 마운트
당장은 컨테이너를 재생성하면 마운트가 새로 걸립니다.
docker compose up -d --force-recreate
근본적으로는 파일이 아니라 디렉토리를 마운트하면 됩니다. 디렉토리를 마운트하면 안에서 파일이 rename 돼도 컨테이너는 경로로 접근하니 새 파일을 봅니다.
volumes:
- ./prometheus/:/etc/prometheus/
타겟이 자주 바뀌는 거라면 file_sd_config 로 빼고 refresh_interval 을 주면,
Prometheus 가 파일을 주기적으로 다시 읽어 reload 자체가 필요 없어집니다.
inode 고정과 파일 교체 — 설정은 디렉토리째 마운트
단일 파일 bind mount 는 inode 를 고정하고 원자적 교체(rsync·mv·에디터)는
inode 를 바꾸기 때문에, 이 둘이 겹치면 호스트에서 아무리 고쳐도 컨테이너엔
안 들어갑니다. 그리고 reload 200 은 성공의 증거가
아닙니다 — 실제 반영은 /api/v1/targets 처럼 결과를 직접 조회해서 확인해야
합니다. “설정 파일은 디렉토리째 마운트한다” 를 기본으로 두면 이 문제를
안 만납니다.
댓글 0