跳转至

黑盒监控

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

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

Blackbox Exporter 是 Prometheus 社区提供的官方黑盒监控解决方案,其允许用户通过:HTTPHTTPSDNSTCP 以及 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