Prometheus 설정 리로드 실패 — 단일 파일 bind mount와 inode

기초·개념3분조회

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 처럼 결과를 직접 조회해서 확인해야 합니다. “설정 파일은 디렉토리째 마운트한다” 를 기본으로 두면 이 문제를 안 만납니다.

  1. 불러오는 중