postgresql在prometheus stack中没有采集到metrics的排查
目录
背景#
我在homelab的k8s集群中使用helm部署了postgresql数据库,使用的是bitnami/postgresql这个chart。
setup-postgres: add-repos
helm upgrade --install postgresql bitnami/postgresql -n database \
--create-namespace \
-f values/postgresql-values.yaml
启用了postgresql的metrics功能,prometheus operator会自动发现了这个服务,并创建了对应的ServiceMonitor对象。
... other settings ...
metrics:
enabled: true # 启用 Prometheus 监控
serviceMonitor:
enabled: true
namespace: monitoring # ServiceMonitor 创建在哪个命名空间(Prometheus 能访问)
labels: # 保证与 Prometheus CR 的 selector 匹配
release: prometheus # 问题配置
interval: 30s
安装完成后查看prometheus的targets,发现没有采集到postgresql的指标数据。
# 端口转发
kubectl port-forward svc/kube-prometheus-stack-prometheus -n monitoring 9090:9090
# 在另一终端查看 active targets(或在浏览器打开 http://localhost:9090 -> Status -> Targets)
curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets[] | select(.labels.job|test("postgres|postgresql"))'
为什么呢?
ServiceMonitor 动态发现服务的过程#
对于PostgreSQL这种通过ServiceMonitor动态发现的服务,Prometheus Operator 会根据 ServiceMonitor 的配置动态生成 Prometheus 的抓取配置。
graph LR
subgraph Kubernetes
SM[ServiceMonitor CRD] -- 1 声明 --> OP(Prometheus Operator);
S[Target Service] -- 2 匹配 Selector --> OP;
OP -- 3 动态生成 Config --> P(Prometheus Server);
end
P -- 4 周期性 Pull --> S;
style OP fill:#9f9,stroke:#333,stroke-width:2px
style P fill:#ff9,stroke:#333,stroke-width:2px
-
声明 (SM $\rightarrow$ OP): 用户创建 ServiceMonitor (SM),声明需要监控哪个 Service。
-
匹配 (S $\rightarrow$ OP): Operator (OP) 通过 Service 的标签与 SM 的 selector 进行匹配。
-
转换 (OP $\rightarrow$ P): Operator 自动将 SM 的意图转换成 Prometheus 的抓取配置,并应用到 Prometheus Server (P)。
-
执行 (P $\rightarrow$ S): Prometheus Server 动态地开始拉取目标 Service 的指标。
思路#
根据上述过程,可以从以下几个方面排查问题:
- 检查
PostgreSQL是否暴露 metrics 端点。 - 检查
ServiceMonitor的配置是否可以正确匹配到PostgreSQL服务。 - 检查
Prometheus Operator是否可以正确匹配到ServiceMonitor,并生成正确的抓取配置。
排查步骤#
1. 检查PostgreSQL是否暴露metrics端点#
kubectl port-forward svc/postgresql-metrics -n database 9187:9187
curl http://localhost:9187/metrics
可以看到返回了大量的指标数据,说明PostgreSQL的metrics端点是正常的。
2. 检查ServiceMonitor的配置是否正确#
kubectl get servicemonitor -n monitoring
可以看到输出
NAME AGE
kube-prometheus-stack-alertmanager 23h
kube-prometheus-stack-apiserver 23h
kube-prometheus-stack-coredns 23h
kube-prometheus-stack-grafana 23h
kube-prometheus-stack-kube-proxy 23h
kube-prometheus-stack-kube-state-metrics 23h
kube-prometheus-stack-kubelet 23h
kube-prometheus-stack-operator 23h
kube-prometheus-stack-prometheus 23h
kube-prometheus-stack-prometheus-node-exporter 23h
postgresql 4h33m
说明postgresql的ServiceMonitor已经创建成功。
kubectl get servicemonitor postgresql -n monitoring -o yaml
输出
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
annotations:
meta.helm.sh/release-name: postgresql
meta.helm.sh/release-namespace: database
creationTimestamp: "2025-10-26T02:10:26Z"
generation: 2
labels:
app.kubernetes.io/component: metrics
app.kubernetes.io/instance: postgresql
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: postgresql
app.kubernetes.io/version: 18.0.0
helm.sh/chart: postgresql-18.1.1
release: prometheus
name: postgresql
namespace: monitoring
resourceVersion: "258365"
uid: cc371f23-fd28-47b5-99f9-ef410a7ba0fa
spec:
endpoints:
- interval: 30s
port: http-metrics
namespaceSelector:
matchNames:
- database
selector:
matchLabels:
app.kubernetes.io/component: metrics
app.kubernetes.io/instance: postgresql
app.kubernetes.io/name: postgresql
从spec.namespaceSelector和spec.selector可以看到,ServiceMonitor配置的是监控database命名空间下,带有如下标签的服务:
app.kubernetes.io/component: metrics
app.kubernetes.io/instance: postgresql
app.kubernetes.io/name: postgresql
查看postgresql-metrics服务的标签:
kubectl get svc postgresql-metrics -n database --show-labels
输出
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE LABELS
postgresql-metrics ClusterIP 10.152.183.222 <none> 9187/TCP 4h42m app.kubernetes.io/component=metrics,app.kubernetes.io/instance=postgresql,app.kubernetes.io/managed-by=Helm,app.kubernetes.io/name=postgresql,app.kubernetes.io/version=18.0.0,helm.sh/chart=postgresql-18.1.1
所有标签都匹配成功,说明ServiceMonitor的配置是正确的。
3. 检查Prometheus Operator是否能正确匹配到ServiceMonitor#
kubectl get prometheus -n monitoring
可以看到输出
NAME VERSION DESIRED READY RECONCILED AVAILABLE AGE
kube-prometheus-stack-prometheus v3.7.2 1 1 True True 23h
{}
这里可以看到prometheus的实例名称是kube-prometheus-stack-prometheus,该实例运行正常。
kubectl get prometheus kube-prometheus-stack-prometheus -n monitoring -o yaml | yq '.spec.serviceMonitorNamespaceSelector, .spec.serviceMonitorSelector'
可以看到Prometheus的serviceMonitorSelector配置如下:
{}
matchLabels:
release: kube-prometheus-stack
这说明Prometheus只会抓取带有release: kube-prometheus-stack标签的ServiceMonitor。
而我们的postgresql的ServiceMonitor标签是release: prometheus,不匹配。
解决方法#
这个release标签是kube-prometheus-stack helm chart自动添加的,默认值是release: {{ .Release.Name }}。
所以我们需要修改postgresql的ServiceMonitor的release标签,使其与Prometheus的serviceMonitorSelector匹配。
修改values/postgresql-values.yaml,添加如下内容:
metrics:
enabled: true # 启用 Prometheus 监控
serviceMonitor:
enabled: true
namespace: monitoring # ServiceMonitor 创建在哪个命名空间(Prometheus 能访问)
labels: # 保证与 Prometheus CR 的 selector 匹配
release: kube-prometheus-stack
interval: 30s
然后重新执行helm升级命令:
just setup-postgres
总结#
通过以上排查步骤,发现ServiceMonitor的release标签与Prometheus的serviceMonitorSelector不匹配,导致Prometheus没有抓取到PostgreSQL的指标数据。修改标签后,Prometheus成功采集到了PostgreSQL的指标。
大多数应用中,我们并不需要考虑ServiceMonitor,而是直接对service增加prometheus相关的annotations就可以让prometheus operator自动对我们的服务进行metrics采集了。这个到写具体的服务的时候再说吧。