- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. 개요
- 2. Discovery Manager 아키텍처
- 3. Provider 인터페이스
- 4. Kubernetes SD
- 5. Relabeling 메커니즘
- 6. File-based SD
- 7. HTTP SD
- 8. 기타 SD 구현체
- 9. 타겟 생명주기
- 10. 성능 고려사항
- 11. 디버깅과 문제 해결
- 12. 정리
1. 개요
Prometheus의 서비스 디스커버리(Service Discovery)는 모니터링 타겟을 자동으로 발견하고 관리하는 핵심 서브시스템입니다. 클라우드 네이티브 환경에서 서비스 인스턴스가 동적으로 생성/삭제되므로, 정적 설정만으로는 모든 타겟을 추적할 수 없습니다.
이 글에서는 Discovery Manager의 아키텍처, Provider 인터페이스, 각 SD 구현체의 동작 방식, relabeling 메커니즘, 타겟 생명주기를 소스코드 레벨에서 분석합니다.
2. Discovery Manager 아키텍처
2.1 전체 구조
prometheus.yml의 scrape_configs
|
v
+-------------------+
| Discovery Manager |
| |
| +-- Provider 1 (kubernetes_sd) -- goroutine
| +-- Provider 2 (consul_sd) -- goroutine
| +-- Provider 3 (file_sd) -- goroutine
| +-- Provider 4 (static_config) -- goroutine
| |
+--------+----------+
|
Target Groups Channel
|
v
+-------------------+
| Scrape Manager |
+-------------------+
2.2 Discovery Manager의 역할
Discovery Manager는 다음을 담당합니다:
- 프로바이더 관리: 각 서비스 디스커버리 프로바이더의 생명주기 관리
- 업데이트 수집: 프로바이더로부터 타겟 그룹 변경 사항 수집
- 일괄 전달: 변경 사항을 버퍼링하여 Scrape Manager에 일괄 전달
- 설정 리로드: 새 설정 적용 시 프로바이더 재생성
2.3 업데이트 흐름
Provider 변경 감지
|
v
업데이트를 내부 채널로 전송
|
v
Discovery Manager가 수신
|
v
5초간 추가 업데이트 대기 (디바운싱)
|
v
모든 프로바이더의 최신 타겟 그룹 병합
|
v
Scrape Manager에 전체 타겟 맵 전달
디바운싱(debouncing)은 빈번한 변경이 발생하는 환경에서 Scrape Manager의 과도한 업데이트를 방지합니다.
3. Provider 인터페이스
3.1 Discoverer 인터페이스
모든 서비스 디스커버리 프로바이더는 Discoverer 인터페이스를 구현합니다:
type Discoverer interface {
Run(ctx context.Context, up chan<- []*targetgroup.Group)
}
Run 메서드의 계약:
- context가 취소될 때까지 실행을 유지
- 타겟 그룹 변경 시 up 채널로 전체 그룹 목록 전송
- 초기 실행 시 현재 알고 있는 전체 타겟 전송
3.2 TargetGroup 구조
TargetGroup:
Source: "kubernetes/pod/default/nginx-abc123" (고유 식별자)
Targets:
- __address__: "10.0.1.5:8080"
- __address__: "10.0.1.6:8080"
Labels:
__meta_kubernetes_namespace: "default"
__meta_kubernetes_pod_name: "nginx-abc123"
...
3.3 프로바이더 등록
프로바이더는 팩토리 함수로 등록됩니다:
등록 과정:
1. 설정 파일에서 *_sd_config 섹션 파싱
2. 해당 SD 타입의 NewDiscoverer 팩토리 호출
3. Discovery Manager에 프로바이더 등록
4. 별도 goroutine에서 Run() 실행
4. Kubernetes SD
4.1 kubernetes_sd 개요
Kubernetes SD는 Prometheus에서 가장 많이 사용되는 서비스 디스커버리입니다. Kubernetes API 서버의 Watch 메커니즘을 사용하여 리소스 변경을 실시간으로 감지합니다.
4.2 역할(Role) 타입
kubernetes_sd는 6가지 역할 타입을 지원합니다:
1. node:
- Kubernetes 노드 목록
- __address__: 노드의 Kubelet 주소
- __meta_kubernetes_node_name, __meta_kubernetes_node_label_*
2. service:
- Kubernetes Service 목록
- __address__: Service의 ClusterIP:Port
- __meta_kubernetes_service_name, __meta_kubernetes_service_port_name
3. pod:
- Kubernetes Pod 목록
- __address__: Pod IP:Container Port
- __meta_kubernetes_pod_name, __meta_kubernetes_pod_container_name
4. endpoints:
- Kubernetes Endpoints 목록
- __address__: 개별 엔드포인트 주소
- __meta_kubernetes_endpoints_name
5. endpointslice:
- Kubernetes EndpointSlice 목록 (Endpoints의 확장형)
- 대규모 클러스터에서 더 효율적
6. ingress:
- Kubernetes Ingress 목록
- __address__: Ingress 호스트
- __meta_kubernetes_ingress_name, __meta_kubernetes_ingress_path
4.3 Watch 메커니즘
Kubernetes SD Watch 동작:
1. 초기 동기화:
a. List API로 전체 리소스 목록 조회
b. 모든 리소스를 TargetGroup으로 변환
c. 전체 목록을 Discovery Manager에 전송
2. Watch 시작:
a. Watch API로 이벤트 스트림 연결
b. resourceVersion 기반 증분 업데이트
3. 이벤트 처리:
ADDED -> 새 TargetGroup 생성
MODIFIED -> 기존 TargetGroup 업데이트
DELETED -> 빈 Targets로 TargetGroup 업데이트
4. 에러 처리:
Watch 연결 끊김 -> 자동 재연결
410 Gone 에러 -> 전체 재목록화(re-list)
타임아웃 -> Watch 재시작
4.4 Informer/Reflector 패턴
kubernetes_sd는 client-go의 Informer 패턴을 활용합니다:
Informer 구조:
Reflector
|-- List: 초기 전체 동기화
|-- Watch: 증분 업데이트 수신
|-- Store: 로컬 캐시에 저장
v
Informer
|-- EventHandler: 이벤트 콜백 등록
|-- Indexer: 효율적인 검색을 위한 인덱스
v
Prometheus SD
|-- 이벤트를 TargetGroup으로 변환
|-- Discovery Manager에 전달
4.5 __meta 레이블
kubernetes_sd는 풍부한 메타 레이블을 제공합니다:
공통:
__meta_kubernetes_namespace
Pod 역할:
__meta_kubernetes_pod_name
__meta_kubernetes_pod_ip
__meta_kubernetes_pod_container_name
__meta_kubernetes_pod_container_port_name
__meta_kubernetes_pod_container_port_number
__meta_kubernetes_pod_label_*
__meta_kubernetes_pod_annotation_*
__meta_kubernetes_pod_node_name
__meta_kubernetes_pod_ready
__meta_kubernetes_pod_phase
Node 역할:
__meta_kubernetes_node_name
__meta_kubernetes_node_label_*
__meta_kubernetes_node_annotation_*
__meta_kubernetes_node_address_*
Service 역할:
__meta_kubernetes_service_name
__meta_kubernetes_service_port_name
__meta_kubernetes_service_port_number
__meta_kubernetes_service_label_*
__meta_kubernetes_service_annotation_*
5. Relabeling 메커니즘
5.1 Relabeling 개요
Relabeling은 타겟의 레이블을 변환하는 강력한 메커니즘입니다. 두 단계에서 적용됩니다:
1단계: relabel_configs (스크래핑 전)
- 디스커버리에서 받은 __meta_* 레이블 처리
- 타겟 레이블 결정 (job, instance 등)
- 타겟 유지/삭제 결정
2단계: metric_relabel_configs (스크래핑 후)
- 수집된 메트릭의 레이블 변환
- 불필요한 메트릭 삭제
- 레이블 이름/값 변환
5.2 Relabeling 액션
replace: 소스 레이블 값을 정규식 매칭 후 대상 레이블에 설정
keep: 정규식에 매칭되지 않는 타겟 삭제
drop: 정규식에 매칭되는 타겟 삭제
hashmod: 소스 레이블의 해시값을 모듈로 연산하여 대상 레이블에 설정
labelmap: 정규식에 매칭되는 레이블 이름을 변환
labeldrop: 정규식에 매칭되는 레이블 삭제
labelkeep: 정규식에 매칭되지 않는 레이블 삭제
lowercase: 대상 레이블 값을 소문자로 변환
uppercase: 대상 레이블 값을 대문자로 변환
keepequal: 소스와 대상 레이블 값이 같은 타겟만 유지
dropequal: 소스와 대상 레이블 값이 같은 타겟 삭제
5.3 Relabeling 처리 흐름
__meta_* 레이블 + __address__ + __scheme__ + __metrics_path__
|
v
relabel_configs 순차 적용
|
v
__address__ -> instance 레이블로 복사
__scheme__, __metrics_path__ 등 내부 레이블 제거
|
v
최종 타겟 레이블 셋 결정
5.4 일반적인 Relabeling 패턴
Pod 어노테이션 기반 스크래핑:
relabel_configs:
# prometheus.io/scrape 어노테이션이 true인 Pod만 스크래핑
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
# 포트 변경
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)
replacement: __meta_kubernetes_pod_ip:$1
# 경로 변경
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
네임스페이스 필터링:
relabel_configs:
- source_labels: [__meta_kubernetes_namespace]
action: keep
regex: production|staging
6. File-based SD
6.1 개요
File SD는 JSON 또는 YAML 파일에서 타겟을 읽는 가장 단순한 동적 디스커버리입니다:
# prometheus.yml
scrape_configs:
- job_name: 'file_sd'
file_sd_configs:
- files:
- '/etc/prometheus/targets/*.json'
refresh_interval: 5m
6.2 타겟 파일 형식
JSON 형식:
[
{
"targets": ["10.0.1.1:9090", "10.0.1.2:9090"],
"labels": {
"env": "production",
"team": "backend"
}
}
]
YAML 형식:
- targets:
- '10.0.1.1:9090'
- '10.0.1.2:9090'
labels:
env: production
team: backend
6.3 파일 감시 메커니즘
File SD 동작:
1. 초기 로드: 지정된 파일 패턴에 매칭되는 모든 파일 읽기
2. inotify 감시: Linux에서 파일 변경 이벤트 구독
3. 주기적 폴링: refresh_interval(기본 5분)마다 전체 재로드
4. 파일 변경 시: 변경된 파일만 재파싱하여 TargetGroup 업데이트
5. 파일 삭제 시: 해당 파일의 모든 타겟 제거
6.4 Custom SD Bridge 패턴
File SD는 커스텀 서비스 디스커버리의 브릿지로 활용됩니다:
커스텀 SD 프로세스 (외부):
1. 자체 서비스 레지스트리 조회
2. 결과를 JSON/YAML 파일로 생성
3. Prometheus가 감시하는 디렉토리에 저장
Prometheus (File SD):
1. 파일 변경 감지
2. 타겟 목록 업데이트
3. 스크래핑 시작/중지
이 패턴은 Prometheus에 직접 통합되지 않은 서비스 레지스트리(Zookeeper, etcd 등)와 연동할 때 유용합니다.
7. HTTP SD
7.1 개요
HTTP SD는 HTTP 엔드포인트에서 타겟 목록을 주기적으로 폴링합니다:
scrape_configs:
- job_name: 'http_sd'
http_sd_configs:
- url: 'http://service-registry:8080/targets'
refresh_interval: 30s
7.2 응답 형식
HTTP SD 엔드포인트는 JSON 배열을 반환해야 합니다:
[
{
"targets": ["10.0.1.1:9090"],
"labels": {
"__meta_datacenter": "us-east",
"__meta_env": "production"
}
}
]
7.3 동작 방식
HTTP SD 처리:
1. refresh_interval마다 URL에 GET 요청
2. 응답 JSON 파싱
3. TargetGroup으로 변환
4. Discovery Manager에 전달
5. HTTP 에러 시 이전 결과 유지
6. 연속 실패 시 메트릭으로 알림
8. 기타 SD 구현체
8.1 Consul SD
Consul SD:
- Consul의 Service Catalog API 사용
- Watch/Blocking Query로 변경 감지
- 서비스 이름, 태그, 데이터센터 기반 필터링
- __meta_consul_service, __meta_consul_tags 등 메타 레이블
8.2 EC2 SD
EC2 SD:
- AWS EC2 DescribeInstances API 사용
- 리전, 가용 영역, 태그 기반 필터링
- IAM 역할 또는 액세스 키 인증
- __meta_ec2_instance_id, __meta_ec2_tag_* 등 메타 레이블
- refresh_interval 기반 폴링 (Watch 미지원)
8.3 DNS SD
DNS SD:
- DNS SRV 또는 A/AAAA 레코드 조회
- 주기적 폴링 방식
- 간단한 환경에서 유용
- __meta_dns_name 메타 레이블
8.4 Static Config
Static Config:
- 가장 단순한 타겟 정의 방식
- 설정 파일에 직접 타겟 주소 기입
- 테스트나 고정 인프라에 적합
- 동적 업데이트 불가 (리로드 필요)
9. 타겟 생명주기
9.1 타겟 상태 전이
타겟 생명주기:
Discovered (발견됨)
|
v
Relabeled (레이블 적용됨)
|
+-- 삭제 결정 --> Dropped (삭제됨)
|
v
Active (활성화됨, 스크래핑 시작)
|
+-- 스크래핑 성공 --> up=1
+-- 스크래핑 실패 --> up=0
|
v
Disappeared (사라짐)
|
v
Stale (stale marker 추가)
|
v
Removed (Scrape Loop 종료)
9.2 Dropped 타겟
타겟이 삭제(Drop)되는 조건:
1. relabel_configs에서 drop 액션 적용
2. relabel_configs에서 keep 액션에 매칭되지 않음
3. __address__ 레이블이 비어있음
4. 중복 타겟 (동일 레이블 셋)
삭제된 타겟은 /targets UI의 "Dropped Targets" 섹션에 표시됩니다.
이를 통해 디스커버리와 relabeling 설정을 디버깅할 수 있습니다.
9.3 타겟 건강 상태 모니터링
내장 메트릭:
up: 0 또는 1 (스크래핑 성공 여부)
scrape_duration_seconds: 스크래핑 소요 시간
scrape_samples_scraped: 수집된 샘플 수
scrape_samples_post_metric_relabeling: relabeling 후 샘플 수
scrape_series_added: 새로 추가된 시계열 수
API 엔드포인트:
GET /api/v1/targets: 전체 타겟 목록과 상태
GET /api/v1/targets/metadata: 타겟별 메트릭 메타데이터
10. 성능 고려사항
10.1 대규모 클러스터에서의 최적화
Kubernetes SD 성능 팁:
1. 네임스페이스 제한: namespaces 필드로 감시 범위 축소
2. 레이블 셀렉터: selectors 필드로 리소스 필터링
3. attach_metadata: 불필요하면 비활성화
4. EndpointSlice 사용: 대규모 클러스터에서 Endpoints보다 효율적
10.2 디스커버리 부하 모니터링
주요 메트릭:
prometheus_sd_discovered_targets: 발견된 타겟 수 (SD 타입별)
prometheus_sd_received_updates_total: 수신된 업데이트 수
prometheus_sd_updates_total: 전달된 업데이트 수
prometheus_sd_updates_delayed_total: 지연된 업데이트 수
경고 신호:
- 발견된 타겟 수의 급격한 변동
- 높은 업데이트 빈도
- 지연된 업데이트 증가
11. 디버깅과 문제 해결
11.1 일반적인 문제
1. 타겟이 발견되지 않음:
- SD 설정 확인 (namespace, selector 등)
- Prometheus 로그에서 SD 에러 확인
- /service-discovery UI 페이지에서 발견된 타겟 확인
2. 타겟이 Dropped 상태:
- relabel_configs 규칙 순서 확인
- keep/drop 액션의 regex 검증
- /targets 페이지에서 Dropped Targets 확인
3. 타겟 레이블이 예상과 다름:
- __meta_* 레이블 확인 (/service-discovery 페이지)
- relabel_configs의 replace 규칙 확인
- 레이블 충돌 시 honor_labels 설정 확인
11.2 디버깅 도구
1. /service-discovery UI:
- 각 SD 프로바이더에서 발견된 원시 타겟 그룹 표시
- __meta_* 레이블 전체 확인 가능
2. /targets UI:
- 활성/삭제된 타겟 목록
- 각 타겟의 건강 상태, 마지막 스크래핑 시간
- 적용된 레이블 확인
3. Prometheus 로그:
- --log.level=debug로 상세 SD 로그 활성화
- SD 프로바이더별 연결/에러 로그
12. 정리
Prometheus의 서비스 디스커버리는 플러그인 아키텍처를 통해 다양한 인프라 환경을 지원합니다. Kubernetes SD의 Watch 메커니즘, relabeling의 강력한 레이블 변환, 그리고 File SD/HTTP SD를 통한 커스텀 확장이 핵심입니다.
다음 글에서는 Prometheus의 알림 파이프라인을 분석합니다. Rule Manager의 평가 메커니즘, Alert 상태 머신, Alertmanager의 라우팅과 알림 전달 과정을 살펴볼 예정입니다.