Prometheus 监控 k8s 集群

k8s 集群需要监控的目标

  • k8s 集群运行的服务
    • 组件服务:kube-apiserver、 kube-scheduler、kube-controller-manager、etcd、coredns
    • 业务服务:业务 pod
      • 业务服务必须要暴漏 /metrics 接口,如果 Pod 里的服务没有暴漏该接口,那么应该塞进一个 sidecar 容器(exporter)来负责暴漏。
      • 创建一个 svc,svc 会自动生成 endpoint 资源,以便被 prometheus server 筛选到。
      • svc 带上指定的注解或标签。如 prometheus.io/scrape: “true”
  • 监控资源的状态:Pod、DaemonSet、Deployment、Job、CronJob 等各种资源状态的监控。
  • 监控容器的状态:需要用到组件 cAdvisor,而 cAdvisor 已经内置在了 kubelet 组件之中。

实现示例

  • 抓取 apiserver 的监控指标
- job_name: 'kubernetes-apiservers'  # 作业名称:用于监控 Kubernetes API Server
  kubernetes_sd_configs:
    - role: endpoints  # 使用 endpoints 服务发现角色
  
  scheme: https  # API Server 使用 HTTPS 协议
  tls_config:
    # 使用 Pod 内默认挂载的 Service Account 的 CA 证书
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    # 跳过 TLS 证书验证(生产环境不建议)
    insecure_skip_verify: true
  # 使用 Service Account token 进行认证
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  
  # Prometheus 服务发现会找到所有的 endpoints,但通过这个重标签规则,只保留:
  # 命名空间 = default
  # Service名称 = kubernetes
  # 端口名称 = https
  relabel_configs:
    - source_labels: 
        [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep  # 保留匹配的 target,丢弃不匹配的
      regex: default;kubernetes;https  # 匹配规则:命名空间;服务名称;端口名称
  
YAML
  • 抓取 kube-controller-manager 的监控指标
# 1、创建 Service,通过标签选择器关联到 kube-controller-manager
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: kube-controller-manager
    app.kubernetes.io/name: kube-controller-manager
    k8s-app: kube-controller-manager
  name: kube-controller-manager
  namespace: kube-system
spec:
  clusterIP: None  # 使用 Headless Service,不分配 ClusterIP
  ports:
  - name: https-metrics  # 端口名称,在 Prometheus 重标签中会用到
    port: 10257         # Service 端口
    targetPort: 10257    # 目标 Pod 端口
    protocol: TCP
  selector:
    component: kube-controller-manager  # 选择标签为 component: kube-controller-manager 的 Pod
YAML

注意:每台机器上的 controller-manager 都监听在127.0.0.1,所以是无法访问的,需要修改其默认监听。

# 2、在 /etc/kubernetes/manifests/kube-controller-manager.yaml 中修改 

--bind-address=0.0.0.0  # 从 127.0.0.1 改为 0.0.0.0
Bash
# 3、添加 Prometheus 监控配置
- job_name: 'kube-controller-manager'  # 作业名称
  kubernetes_sd_configs:
    - role: endpoints  # 使用 endpoints 服务发现
  scheme: https  # 使用 HTTPS 协议
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt  # CA 证书路径
    insecure_skip_verify: true  # 跳过 TLS 证书验证(生产环境不推荐)
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token  # 认证 token
  relabel_configs:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep  # 只保留匹配的 target
      regex: kube-system;kube-controller-manager;https-metrics  # 匹配规则
YAML
  • 抓取 kube-scheduler 的监控指标,配置方式同上。
  • 抓取 etcd 的监控指标
# 在每个 master 节点上修改 etcd 的静态 Pod 配置
# 文件位置:/etc/kubernetes/manifests/etcd.yaml
spec:
  containers:
  - command:
    - etcd
    # 添加或修改以下参数:
    - --listen-metrics-urls=http://0.0.0.0:2381  # 从 127.0.0.1 改为 0.0.0.0
    # 其他原有参数...
YAML
# 创建 etcd Service
apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: etcd
  labels:
    k8s-app: etcd
spec:
  selector:
    component: etcd  # 选择标签为 component: etcd 的 Pod
  type: ClusterIP
  clusterIP: None  # Headless Service,直接使用 Pod IP
  ports:
    - name: http  # 端口名称,在 Prometheus 重标签中会用到
      port: 2381  # Service 端口
      targetPort: 2381  # Pod 实际监听的端口
      protocol: TCP
YAML
# 添加 etcd 监控配置
- job_name: 'etcd'  # 作业名称
  kubernetes_sd_configs:
    - role: endpoints  # 使用 endpoints 服务发现
  scheme: http  # etcd metrics 使用 HTTP 协议(非加密)
  
  relabel_configs:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep  # 只保留匹配的 target
      regex: kube-system;etcd;http  # 匹配规则:命名空间;服务名称;端口名称
YAML
  • 配置自动发现业务服务 Pod
- job_name: 'kubernetes-endpoints'
  kubernetes_sd_configs:
    - role: endpoints  # 发现所有 Kubernetes endpoints
  
  relabel_configs:
    # 1. 根据注解过滤:只保留包含 prometheus.io/scrape=true 的 Service
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep  # 保留匹配的 target
      regex: true   # 匹配注解值为 "true"
    
    # 2. 设置抓取协议:根据注解动态配置 HTTP/HTTPS
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      action: replace  # 替换操作
      target_label: __scheme__  # 设置协议标签(http/https)
      regex: (https?)  # 匹配 "http" 或 "https"
    
    # 3. 设置指标路径:自定义 metrics 端点路径
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__  # 设置指标路径
      regex: (.+)  # 匹配任意非空字符串
    
    # 4. 重构访问地址:组合 IP 和端口
    - source_labels: 
        [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__  # 设置最终访问地址
      regex: ([^:]+)(?::\d+)?;(\d+)  # 正则表达式解析
      replacement: $1:$2  # 格式:IP:Port
    
    # 5. 映射 Service 标签
    - action: labelmap
      regex: __meta_kubernetes_service_label_(.+)  # 匹配所有 Service 标签
    
    # 6. 添加命名空间标签
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: kubernetes_namespace  # 标准化命名空间标签名
    
    # 7. 添加 Service 名称标签
    - source_labels: [__meta_kubernetes_service_name]
      action: replace
      target_label: kubernetes_service  # 标准化服务名称标签名
    
    # 8. 添加 Pod 名称标签
    - source_labels: [__meta_kubernetes_pod_name]
      action: replace
      target_label: kubernetes_pod_name  # 标准化 Pod 名称标签名
YAML

这是一个通用配置,允许通过 Service 注解来自动发现和监控应用:

apiVersion: v1
kind: Service
metadata:
  name: my-app
  annotations:
    prometheus.io/scrape: "true"           # 启用抓取
    prometheus.io/scheme: "https"          # 协议(可选,默认http)
    prometheus.io/path: "/custom/metrics"  # 路径(可选,默认/metrics)
    prometheus.io/port: "9090"             # 端口(可选,默认Service端口)
spec:
  ports:
  - port: 80
    targetPort: 8080
YAML

测试示例:

# prome-redis.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  namespace: monitor
spec:
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      containers:
        - name: redis
          image: redis:4
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
          ports:
            - containerPort: 6379
        - name: redis-exporter
          image: oliver006/redis_exporter:latest
          resources:
            requests:
              cpu: 100m
              memory: 100Mi
          ports:
            - containerPort: 9121
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: monitor
  annotations:  # --------------------------------》 Prometheus 自动发现注解
    prometheus.io/scrape: 'true'  # 启用 Prometheus 抓取
    prometheus.io/port: '9121'    # 指定 metrics 端口
spec:
  selector:
    app: redis
  ports:
    - name: redis  # Redis 服务端口
      port: 6379
      targetPort: 6379
    - name: prom   # Prometheus metrics 端口
      port: 9121
      targetPort: 9121
YAML
  • 资源的状态监控

需要部署 kube-state-metrics 来采集资源信息,metrics server 提供实时的资源监控指标给 HPA做决策用,不擅长做历史数据分析。kube-state-metrics 擅长做历史数据监控与分析,对接prometheus server。

# 下载
# 国外:git clone https://github.com/kubernetes/kube-state-metrics.git
# 国内:git clone https://gitee.com/egonlin/kube-state-metrics.git

cd kube-state-metrics/examples/standard

$ ls
cluster-role-binding.yaml  cluster-role.yaml  deployment.yaml  service-account.yaml  service.yaml

# 根据需要修改镜像地址

# 此外我们上面为 Prometheus 配置了 Endpoints 的自动发现,所以我们可以给 kube-state-metrics 的 Service 配置上对应的 annotations 来自动被发现,然后直接创建即可。
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: exporter
    app.kubernetes.io/name: kube-state-metrics
    app.kubernetes.io/version: 2.12.0
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    # kube-state-metrics暴露两个端口
    # 8080端口:Kubernetes资源指标(主要监控数据)
    # 8081端口:kube-state-metrics自身性能指标
    # 这里只监控了 8080 端口,如果想监控多个端口,可以单独配置一个 job 或者修改上面的 Endpoints 的自动发现逻辑,实现多端口监控
  name: kube-state-metrics
  namespace: kube-system
spec:
  clusterIP: None
  ports:
  - name: http-metrics
    port: 8080                  # 暴漏的监控端口
    targetPort: http-metrics
  - name: telemetry
    port: 8081
    targetPort: telemetry
  selector:
    app.kubernetes.io/name: kube-state-metrics
Bash
  • 容器的状态监控

需要用到组件 cAdvisor,而 cAdvisor 已经内置在了 kubelet 组件之中。

- job_name: 'kubernetes-cadvisor'  # 作业名称:用于收集容器和Pod的资源使用情况指标
  kubernetes_sd_configs:
    - role: node  # 自动发现集群中的所有节点
  scheme: https  # cAdvisor 通过 kubelet 的 HTTPS 接口暴露指标
  tls_config:
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    insecure_skip_verify: true
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    # 1. 将 Kubernetes 节点标签映射为 Prometheus 标签
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)  # 匹配所有节点标签
      replacement: $1  # 将匹配到的部分作为新标签名(去掉前缀)
    
    # 2. 重写指标路径:将默认的 /metrics 改为 /metrics/cadvisor
    - source_labels: [__meta_kubernetes_node_name]  # 源标签:节点名称
      regex: (.+)  # 匹配任何节点名称(实际上这个匹配在这里只是占位符)
      replacement: /metrics/cadvisor  # 替换为 cAdvisor 的指标路径
      target_label: __metrics_path__  # 目标标签:指定指标采集路径
      
      
kubectl apply -f prometheus-cm.yaml
curl -X POST "http://10.244.4.8:9090/-/reload"
ShellScript
  • Prometheus 监控 kubelet 组件示例
- job_name: 'kubelet'  # 作业名称,用于监控 Kubernetes 节点上的 kubelet 组件
  kubernetes_sd_configs:
    - role: node  # 使用 Kubernetes 服务发现,自动发现集群中的所有节点
  
  scheme: https  # kubelet 的 API 使用 HTTPS 协议
  tls_config:
    # 使用 Kubernetes Pod 内默认挂载的 Service Account 的 CA 证书来验证 kubelet 的 TLS 证书
    ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
    # 设置为 true 跳过 TLS 证书验证(生产环境不建议,但在某些自签名证书环境下可能需要)
    insecure_skip_verify: true
  # 使用 Service Account 的 token 进行认证,kubelet 需要认证才能访问 metrics 接口
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  relabel_configs:
    # 将 Kubernetes 节点的标签自动映射为 Prometheus 的标签
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)
      
      
      
      
kubectl apply -f prometheus-cm.yaml
curl -X POST "http://10.244.4.8:9090/-/reload"
Bash

上面的示例只实现了基本监控,而且要更新监控项配置也很繁琐,推荐使用 Prometheus Operator

上一篇
下一篇