10.1 모니터링
CloudNativePG는 각 PostgreSQL 인스턴스 안에 metrics exporter를 함께 띄웁니다. 이 exporter는 인스턴스에 접속해 상태를 SQL로 조회하고, 그 결과를 Prometheus가 이해하는 텍스트 포맷으로 HTTP에 노출합니다. 관찰의 큰 그림은 단순합니다. 각 Pod가 metrics를 내놓으면 Prometheus가 주기적으로 수집(scrape)해 저장하고, Grafana가 그 저장소를 읽어 대시보드로 그립니다.
metrics endpoint
인스턴스마다 metrics는 9187 포트의 /metrics 경로에 노출됩니다. exporter는 cnpg_metrics_exporter라는 role로 쿼리를 실행하며, 이 role은 pg_monitor 권한을 물려받아 통계 뷰를 읽습니다.
가장 빠르게 눈으로 확인하는 방법은 port-forward입니다.
kubectl port-forward cluster-example-1 9187:9187
# 다른 터미널에서
curl -s localhost:9187/metrics | head
Pod 안에서 직접 확인하려면 Pod IP로 붙습니다.
POD_IP=$(kubectl get pod cluster-example-1 -o jsonpath='{.status.podIP}')
kubectl exec -ti curl -- curl -s ${POD_IP}:9187/metrics
metrics 조회 결과는 기본적으로 30초 동안 캐시됩니다. 모니터링 쿼리가 매 scrape마다 인스턴스에 부하를 주지 않게 하려는 장치입니다. 캐시를 끄려면 .spec.monitoring.metricsQueriesTTL을 0으로 둡니다. 캐시 효율은 cache_hits·cache_misses metrics로 확인할 수 있습니다.
PodMonitor로 Prometheus에 연결
Prometheus Operator를 쓴다면, PodMonitor 리소스를 만들어 "이 label을 가진 Pod들의 metrics 포트를 scrape하라"라고 선언합니다. Prometheus는 이 선언을 읽어 scrape 대상에 자동으로 등록합니다.
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: cluster-example
spec:
selector:
matchLabels:
cnpg.io/cluster: cluster-example
podMetricsEndpoints:
- port: metrics
예전에는 .spec.monitoring.enablePodMonitor: true로 Operator가 PodMonitor를 대신 만들게 했지만, 이 필드는 deprecated입니다. 위처럼 PodMonitor를 직접 만드는 방식을 권장합니다.
기본 제공 metrics
Operator는 cnpg-default-monitoring이라는 ConfigMap을 설치해 두고, 여기에 담긴 기본 쿼리를 모든 클러스터에 적용합니다. 대표적인 것들만 추리면 다음과 같습니다.
| metric | 의미 |
|---|---|
cnpg_collector_up | 인스턴스가 살아 있는지 여부 |
cnpg_collector_pg_wal | WAL 파일 개수·크기 |
cnpg_collector_sync_replicas | synchronous replica 현황 |
cnpg_collector_nodes_used | 인스턴스가 퍼져 있는 노드 수 |
cnpg_collector_postgres_version | PostgreSQL 버전 정보 |
기본 metrics가 불필요하면 클러스터 단위로 .spec.monitoring.disableDefaultQueries: true를 주거나, Operator 설정에서 MONITORING_QUERIES_CONFIGMAP을 빈 문자열로 두어 전역에서 끌 수 있습니다.
custom query
기본 metrics로 부족하면 직접 쿼리를 정의해 새 metric을 만듭니다. 쿼리는 ConfigMap이나 Secret에 담고, 클러스터에서 이를 참조합니다.
spec:
monitoring:
customQueriesConfigMap:
- name: example-monitoring
key: custom-queries
참조하는 ConfigMap·Secret은 Cluster와 같은 namespace에 있어야 합니다. cnpg.io/reload: "" label을 붙여 두면 내용이 바뀔 때 자동으로 다시 읽힙니다.
쿼리 하나의 구조는 아래와 같습니다. query가 실제 SQL이고, metrics의 각 항목이 결과 컬럼을 어떤 종류의 metric으로 내보낼지 지정합니다.
pg_replication:
query: "SELECT CASE WHEN NOT pg_is_in_recovery() THEN 0 ELSE GREATEST(0, EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))) END AS lag, pg_is_in_recovery()::int AS in_recovery"
primary: false # replica에서도 실행
target_databases: ["postgres"]
metrics:
- lag:
usage: "GAUGE"
description: "복제 지연(초)"
- in_recovery:
usage: "GAUGE"
description: "recovery 상태 여부"
usage에는 컬럼의 성격에 맞는 종류를 지정합니다.
| usage | 쓰임 |
|---|---|
LABEL | 이 컬럼 값을 metric의 label로 |
GAUGE | 오르내리는 순간값 |
COUNTER | 누적 증가값 |
HISTOGRAM | 분포 |
DURATION | 소요 시간 |
DISCARD | 결과에서 버림 |
operator metrics
인스턴스뿐 아니라 Operator 자신도 metrics를 노출합니다. 이쪽은 8080 포트의 /metrics이며, 조정 루프 처리량이나 에러 같은 컨트롤러 지표를 담습니다. 별도의 PodMonitor로 수집합니다.
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: cnpg-controller-manager
namespace: cnpg-system
spec:
selector:
matchLabels:
app.kubernetes.io/name: cloudnative-pg
podMetricsEndpoints:
- port: metrics
metrics 범위의 한계와 OpenTelemetry
기본 metrics는 PostgreSQL 안에서 SQL로 얻을 수 있는 것에 치우쳐 있습니다. database 크기와 WAL 파일 개수, 크기는 있지만 PGDATA 볼륨의 파일시스템 사용률은 기본 제공에 없습니다(WAL은 cnpg_collector_pg_wal의 volume_size 값으로 볼륨 크기만 나옵니다). 디스크가 가득 차면 failover도 일어나지 않으므로(2.3) 이 지표는 따로 챙겨야 합니다. kubelet이 내는 kubelet_volume_stats_used_bytes와 kubelet_volume_stats_capacity_bytes를 PVC 이름으로 묶어 보는 것이 가장 간단한 보완책입니다.
OpenTelemetry Collector를 표준으로 쓰는 조직이라면 CloudNativePG 쪽에서 설정할 것은 없습니다. 1.30 기준으로 CloudNativePG는 OTLP를 직접 내보내지 않고, 다음 신호를 Collector가 받아 가는 구조가 됩니다.
| 신호 | 수집 방식 | 비고 |
|---|---|---|
| metrics | Collector의 prometheus receiver로 9187 포트 scrape | PodMonitor 대신 receiver 설정에 scrape 대상을 적는다 |
| logs | filelog receiver로 컨테이너 stdout 수집 | 이미 JSON이라 파싱 비용이 낮다(10.2) |
| traces | 없음 | CloudNativePG는 span을 만들지 않는다. 쿼리 단위 trace가 필요하면 애플리케이션이나 프록시 계층에서 계측한다 |
Grafana 대시보드
CloudNativePG는 곧바로 쓸 수 있는 Grafana 대시보드를 cloudnative-pg/grafana-dashboards 저장소에 공개해 둡니다. grafana-dashboard.json을 내려받아 Grafana의 Dashboard > New > Import로 불러오면, 앞서 본 기본 metrics를 기반으로 한 패널이 바로 채워집니다.
metrics endpoint를 TLS로 감싸려면 인스턴스는 .spec.monitoring.tls.enabled: true를 주고, Operator metrics는 METRICS_CERT_DIR 환경 변수로 인증서 디렉토리를 지정합니다. 사내망이 아니라 노출된 환경이라면 metrics도 접근 통제 대상임을 잊지 않습니다.
정리
- 각 인스턴스는 9187 포트
/metrics에 Prometheus 포맷 metrics를 노출하고, Operator 자신은 8080 포트에 따로 노출합니다 - PodMonitor로 scrape 대상을 선언하고, Grafana 공식 대시보드를 import해 시작합니다
- 기본 metrics는
cnpg-default-monitoringConfigMap에서, 부족하면 custom query로 확장합니다