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 的抓取配置。
-
声明 (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,并生成正确的抓取配置。
排查步骤#
前三节沿着 metrics 的流向逐段排除:exporter 有没有吐、ServiceMonitor 写没写对、Operator 认不认这个 ServiceMonitor。第四节是查到之后怎么改。
检查PostgreSQL是否暴露 metrics 端点#
kubectl port-forward svc/postgresql-metrics -n database 9187:9187
curl http://localhost:9187/metrics
可以看到返回了大量的指标数据,说明PostgreSQL的 metrics 端点是正常的。
检查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的配置是正确的。
检查 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 采集了。这个到写具体的服务的时候再说吧。