跳到主要内容

黑盒监控

前面我们主要介绍了 Prometheus 下如何进行白盒监控,我们监控主机的资源用量、容器的运行状态、数据库中间件的运行数据、自动发现 Kubernetes 集群中的资源等等,这些都是支持业务和服务的基础设施,通过白盒能够了解其内部的实际运行状态,通过对监控指标的观察能够预判可能出现的问题,从而对潜在的不确定因素进行优化。而从完整的监控逻辑的角度,除了大量的应用白盒监控以外,还应该添加适当的 Blackbox(黑盒)监控,黑盒监控即以用户的身份测试服务的外部可见性,常见的黑盒监控包括 HTTP 探针、TCP 探针等用于检测站点或者服务的可访问性以及访问效率等。

黑盒监控相较于白盒监控最大的不同在于黑盒监控是以故障为导向当故障发生时,黑盒监控能快速发现故障,而白盒监控则侧重于主动发现或者预测潜在的问题。一个完善的监控目标是要能够从白盒的角度发现潜在问题,能够在黑盒的角度快速发现已经发生的问题。

Blackbox Exporter 是 Prometheus 社区提供的官方黑盒监控解决方案,其允许用户通过:HTTP、HTTPS、DNS、TCP 以及 ICMP 的方式对网络进行探测,可以用于下面的这些场景:

  • HTTP 测试:定义 Request Header 信息、判断 Http status、Response Header、Body 内容
  • TCP 测试:业务组件端口状态监听、应用层协议定义与监听
  • ICMP 测试:主机探活机制
  • POST 测试:接口联通性
  • SSL 证书过期时间

Prometheus Operator 中提供了一个 Probe CRD 对象可以用来进行黑盒监控,我们需要单独运行一个 Blackbox 服务,然后作为一个 prober 提供给 Probe 对象使用。

部署 Blackbox Exporter​

运行 Blackbox Exporter 时,需要用户提供探针的配置信息,这些配置信息可能是一些自定义的 HTTP 头信息,也可能是探测时需要的一些 TSL 配置,也可能是探针本身的验证行为,在 Blackbox Exporter 中每一个探针配置称为一个 module,并且以 YAML 配置文件的形式提供,每一个 module 主要包含:探针类型(prober)、验证访问超时时间(timeout)、以及当前探针的具体配置项:

# 探针类型: http https tcp dns icmp
prober: <prober_string> # 必选
# 超时时间:
[timeout: <duration>] # 默认单位秒
# 探针的详细配置,最多只能配置其中一个
[ http: <http_probe> ]
[ tcp: <tcp_probe> ]
[ dns: <dns_probe> ]
[ icmp: <icmp_probe> ]
[ grpc: <grpc_probe> ]

比如下面的这段配置就包含两个 HTTP 探针配置项:

modules: # 配置检测的模块
http_2xx: # http 检测模块,可以随便命名,Blockbox Exporter 中所有的探针均是以 Module 的信息进行配置
prober: http
timeout: 5s
http:
valid_http_versions: ['HTTP/1.1', 'HTTP/2']
valid_status_codes: [200] # 这里最好作一个返回状态码,默认是 2xx
method: GET
http_post_2xx:
prober: http
http:
method: POST

在 Kubernetes 集群中运行 Blackbox Exporter 服务,其实在前面的 kube-prometheus 中已经安装过了,我们可以先看下其配置清单:

# blackboxExporter-configuration.yaml
apiVersion: v1
data:
config.yml: |-
"modules":
"http_2xx":
"http":
"preferred_ip_protocol": "ip4"
"prober": "http"
"http_post_2xx": # POST 请求
"http":
"method": "POST"
"preferred_ip_protocol": "ip4"
"prober": "http"
"irc_banner": # irc 协议
"prober": "tcp"
"tcp":
"preferred_ip_protocol": "ip4"
"query_response":
- "send": "NICK prober"
- "send": "USER prober prober prober :prober"
- "expect": "PING :([^ ]+)"
"send": "PONG ${1}"
- "expect": "^:[^ ]+ 001"
"pop3s_banner": # pop3 检测
"prober": "tcp"
"tcp":
"preferred_ip_protocol": "ip4"
"query_response":
- "expect": "^+OK"
"tls": true
"tls_config":
"insecure_skip_verify": false
"ssh_banner": # ssh 检测
"prober": "tcp"
"tcp":
"preferred_ip_protocol": "ip4"
"query_response":
- "expect": "^SSH-2.0-"
"tcp_connect": # tcp 连接
"prober": "tcp"
"tcp":
"preferred_ip_protocol": "ip4"
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: blackbox-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 0.20.0
name: blackbox-exporter-configuration
namespace: monitoring

可以根据我们自己的需求来修改该配置文件,这里我们将 irc、ssh 和 pop3 的检测模块去掉,新增 dns 模块,修改后的配置文件如下所示:

# blackboxExporter-configuration2.yaml
apiVersion: v1
data:
config.yml: |-
"modules":
"http_2xx":
"http":
"preferred_ip_protocol": "ip4"
"valid_http_versions": ["HTTP/1.1", "HTTP/2"]
"method": "GET"
"prober": "http"
"timeout": "5s"
"http_post_2xx": # POST 请求
"http":
"method": "POST"
"preferred_ip_protocol": "ip4"
"prober": "http"
"tcp_connect": # tcp 连接
"prober": "tcp"
"timeout": "10s"
"tcp":
"preferred_ip_protocol": "ip4"
"dns": # DNS 检测模块
"prober": "dns"
"dns":
"transport_protocol": "udp" # 默认是 udp,tcp
"preferred_ip_protocol": "ip4" # 默认是 ip6
query_name: "kubernetes.default.svc.cluster.local" # 利用这个域名来检查dns服务器
icmp: # ping 检测服务器的存活
prober: icmp
kind: ConfigMap
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: blackbox-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 0.20.0
name: blackbox-exporter-configuration
namespace: monitoring

配置文件准备完成后,现在我们可以去看下 blackbox-exporter 应用的部署清单,如下所示:

# blackboxExporter-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: blackbox-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 0.20.0
name: blackbox-exporter
namespace: monitoring
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: blackbox-exporter
app.kubernetes.io/part-of: kube-prometheus
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: blackbox-exporter
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: blackbox-exporter
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 0.20.0
spec:
automountServiceAccountToken: true
containers:
- args:
- --config.file=/etc/blackbox_exporter/config.yml
- --web.listen-address=:19115
image: quay.io/prometheus/blackbox-exporter:v0.20.0
name: blackbox-exporter
ports:
- containerPort: 19115
name: http
resources:
limits:
cpu: 20m
memory: 40Mi
requests:
cpu: 10m
memory: 20Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
volumeMounts:
- mountPath: /etc/blackbox_exporter/
name: config
readOnly: true
- args:
- --webhook-url=http://localhost:19115/-/reload
- --volume-dir=/etc/blackbox_exporter/
image: jimmidyson/configmap-reload:v0.5.0
name: module-configmap-reloader
resources:
limits:
cpu: 20m
memory: 40Mi
requests:
cpu: 10m
memory: 20Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 65534
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: FallbackToLogsOnError
volumeMounts:
- mountPath: /etc/blackbox_exporter/
name: config
readOnly: true
- args:
- --logtostderr
- --secure-listen-address=:9115
- --tls-cipher-suites=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
- --upstream=http://127.0.0.1:19115/
image: quay.io/brancz/kube-rbac-proxy:v0.12.0
name: kube-rbac-proxy
ports:
- containerPort: 9115
name: https
resources:
limits:
cpu: 20m
memory: 40Mi
requests:
cpu: 10m
memory: 20Mi
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: blackbox-exporter
volumes:
- configMap:
name: blackbox-exporter-configuration
name: config

可以看到这里最重要的就是将上面的 blackbox-exporter-configuration 这个 ConfigMap 对象挂载到 blackbox-exporter 中去,我们重新更新该配置即可,因为 Deployment 中我们添加有一个 reloader 的 sidecar 容器,会自动帮我们更新应用配置。

$ kubectl apply -f blackboxExporter-configuration2.yaml

如果是手动部署的 Prometheus 我们可以直接在 Prometheus 对应的配置文件中添加监控任务即可,比如我们要添加一个 ping 的任务:

- job_name: 'ping'
metrics_path: /probe # 这里的指标路径是 /probe
params:
modelus: [icmp] # 使用 icmp 模块
static_configs:
- targets: # 检测的目标
- x.x.x.x
lables: # 添加额外的标签
instance: aliyun
relabel_configs: # relabel 操作
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: x.x.x.x:9115

现在我们这里使用的是 Prometheus Operator,我们可以只有使用 Probe 这个 CRD 对象来添加网络探测任务,关于这个对象的使用方法可以通过 kubectl explain probe 或者 API 文档 来了解更多。

比如这里我们来新增一个对百度的 ping 任务,创建一个如下所示的 Probe 资源对象:

# blackboxExporter-probePing.yaml
apiVersion: monitoring.coreos.com/v1
kind: Probe
metadata:
name: ping
namespace: monitoring
spec:
jobName: ping # 任务名称
prober: # 指定blackbox的地址
url: blackbox-exporter.monitoring:19115
module: icmp # 配置文件中的检测模块
targets: # 目标(可以是static配置也可以是ingress配置)
# ingress <Object>
staticConfig: # 如果配置了 ingress,静态配置优先
static:
- https://www.baidu.com
relabelingConfigs:
- sourceLabels: [__address__]
targetLabel: __param_target
- sourceLabels: [__param_target]
targetLabel: instance

直接创建上面的资源清单即可:

$ kubectl apply -f blackboxExporter-probePing.yaml
$ kubectl get probe -n monitoring
NAME AGE
ping 35m

创建后正常隔一会儿在 Prometheus 里面就可以看到抓取的任务了。

ping 任务

回到 Graph 页面,可以使用 probe_duration_seconds{job="ping"} 来查看检测的时间,这样就实现了对 ICMP 的黑盒监控。

probe duration

我们再创建一个用于检测网站 HTTP 服务是否正常的任务:

# blackboxExporter-probeDomain.yaml
apiVersion: monitoring.coreos.com/v1
kind: Probe
metadata:
name: domain-probe
namespace: monitoring
spec:
jobName: domain-probe # 任务名称
prober: # 指定blackbox的地址
url: blackbox-exporter:19115
module: http_2xx # 配置文件中的检测模块
targets: # 目标(可以是static配置也可以是ingress配置)
# ingress <Object>
staticConfig: # 如果配置了 ingress,静态配置优先
static:
- prometheus.io
relabelingConfigs:
- sourceLabels: [__address__]
targetLabel: __param_target
- sourceLabels: [__param_target]
targetLabel: instance

直接创建该资源对象:

$ kubectl apply -f blackboxExporter-probeDomain.yaml
$ kubectl get probe -n monitoring
NAME AGE
domain-probe 5s
ping 77m

创建后同样可以在 Prometheus 中看到对应的任务。

domain job

我们可以使用 probe_ssl_earliest_cert_expiry 来判断 TLS 证书是否过期了:

- name: ssl_expiry
rules:
- alert: Ssl Cert Will Expire in 7 days
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 7
for: 5m
labels:
severity: warning
annotations:
summary: '域名证书即将过期 (instance {{ $labels.instance }})'
description: "域名证书 7 天后过期 \n VALUE = {{ $value }}\n LABELS: {{ $labels }}"

当配置的任务有问题的时候,我们可以使用 blackbox-exporter 的 probe 接口加上 debug=true 来进行调试:http://192.168.0.106:31266/probe?target=prometheus.io&module=http_2xx&debug=true

probe debug