← 返回文章列表

Prometheus 监控入门与 K8s 实践

27 分钟阅读
字号

Prometheus 监控入门与 K8s 实践

本文涵盖 Prometheus 监控理论、架构、二进制部署、K8s 部署、应用监控及 K8s 集群监控等核心知识点。


一、监控理论

监控分为两大类

类型说明特点
黑盒监控身体行不行,拉出来溜溜,有病没病走两步侧重于眼前问题,尽早发现(早于用户)、第一时间处理
白盒监控身体行不行,先做个全身体检,拿检测结果说话了解系统内部细节,做好预防,防患于未然

区别:

  • 黑盒:不需要了解系统内部细节 → 早于真正的用户找到问题
  • 白盒:要了解系统内部细节 → 预防

监控的目的

  1. 长期趋势分析 — 预测未来的扩容
  2. 故障根因分析 — 查历史监控
  3. 对照分析 — 明确不同版本的运行情况
  4. 告警通知 — 超过阈值则报警,提前处理问题
  5. 系统状态了然于胸 — 实时掌握运行状态

总结:

  • 通过白盒监控能够提前预知业务瓶颈
  • 通过黑盒监控能够第一时间发现业务故障并通过告警通告运维人员进行紧急恢复

二、Prometheus 架构

┌─────────────────────────────────────────────────────────────┐
│                        Prometheus 架构                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   上游(采集)              Prometheus Server        下游(使用)│
│   ┌──────────┐                                        ┌──────────┐│
│   │  targets │        ┌────────────────┐              │          ││
│   │  (监控目标)│─────→ │  Retrieval     │              │ Grafana  ││
│   │          │        │  (周期性拉取)  │              │          ││
│   │ - K8s    │        └───────┬────────┘              └──────────┘│
│   │ - Node   │                │                            ┌──────────┐│
│   │ - App    │        ┌───────┴────────┐              │          ││
│   │ - Exporter│       │     TSDB       │              │Alertmanager│
│   │ - Pushgateway│    │   (时序存储)    │              │          ││
│   └──────────┘        └───────┬────────┘              └──────────┘│
│                                │                               │
│                        ┌───────┴────────┐                       │
│                        │  HTTP Server   │                       │
│                        │   :9090        │                       │
│                        └────────────────┘                       │
└─────────────────────────────────────────────────────────────┘

架构三段式

阶段说明
上游targets:监控目标(K8s 组件、各种 Exporter、Pushgateway、Service Discovery)
中间Prometheus Server:Retrieval(周期性拉取)→ TSDB(时序存储)→ HTTP Server(对外暴露接口)
下游Alertmanager(告警发送)、Grafana(可视化出图)

三、二进制安装 Prometheus Server

1. 下载安装

# 下载(推荐 LTS 版本 2.53.x)
wget https://github.com/prometheus/prometheus/releases/download/v2.53.0/prometheus-2.53.0.linux-amd64.tar.gz
 
mkdir /monitor
tar xf prometheus-2.53.0.linux-amd64.tar.gz -C /monitor
ln -s /monitor/prometheus-2.53.0.linux-amd64 /monitor/prometheus
mkdir /monitor/prometheus/data

2. 配置系统服务

cat > /usr/lib/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=prometheus server daemon
 
[Service]
Restart=on-failure
ExecStart=/monitor/prometheus/prometheus \
  --config.file=/monitor/prometheus/prometheus.yml \
  --storage.tsdb.path=/monitor/prometheus/data \
  --storage.tsdb.retention.time=30d \
  --web.enable-lifecycle
 
[Install]
WantedBy=multi-user.target
EOF

3. 启动服务

systemctl daemon-reload
systemctl enable prometheus.service
systemctl start prometheus.service
systemctl status prometheus
netstat -tunalp | grep 9090

访问: http://IP:9090

4. 添加监控目标

编译测试程序(提供 /metrics 接口):

yum install golang -y
git clone https://github.com/prometheus/client_golang.git
cd client_golang/examples/random
export GO111MODULE=on
export GOPROXY=https://goproxy.cn
go build

启动 3 个服务:

./random -listen-address=:8080   # http://localhost:8080/metrics
./random -listen-address=:8081   # http://localhost:8081/metrics
./random -listen-address=:8082   # http://localhost:8080/metrics

配置 prometheus.yml:

scrape_configs:
  - job_name: 'example-random'
    scrape_interval: 5s
    static_configs:
      - targets: ['192.168.71.101:8080', '192.168.71.101:8081']
        labels:
          group: 'production'
      - targets: ['192.168.71.101:8082']
        labels:
          group: 'canary'
systemctl restart prometheus

访问 http://192.168.71.101:9090 → Status → Targets 查看监控目标。


四、安装 Prometheus Server 到 K8s

1. 创建命名空间

kubectl create namespace monitor

2. ConfigMap 配置

# prometheus-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: monitor
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
      scrape_timeout: 15s
      evaluation_interval: 15s
    scrape_configs:
      - job_name: "prometheus"
        static_configs:
          - targets: ["localhost:9090"]

3. PV 和 PVC

# prometheus-pv-pvc.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: prometheus-local
  labels:
    app: prometheus
spec:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 20Gi
  storageClassName: local-storage
  local:
    path: /data/k8s/prometheus
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - master01
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: prometheus-data
  namespace: monitor
spec:
  selector:
    matchLabels:
      app: prometheus
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi
  storageClassName: local-storage

4. RBAC 权限

# prometheus-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: monitor
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus
rules:
  - apiGroups:
      - ''
    resources:
      - nodes
      - services
      - endpoints
      - pods
      - nodes/proxy
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - 'extensions'
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ''
    resources:
      - configmaps
      - nodes/metrics
    verbs:
      - get
  - nonResourceURLs:
      - /metrics
    verbs:
      - get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
  - kind: ServiceAccount
    name: prometheus
    namespace: monitor

5. Deployment 部署

# prometheus-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus
  namespace: monitor
spec:
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      serviceAccountName: prometheus
      securityContext:
        runAsUser: 0
      containers:
        - image: prom/prometheus:v2.53.0
          name: prometheus
          args:
            - '--config.file=/etc/prometheus/prometheus.yml'
            - '--storage.tsdb.path=/prometheus'
            - '--storage.tsdb.retention.time=24h'
            - '--web.enable-admin-api'
            - '--web.enable-lifecycle'
          ports:
            - containerPort: 9090
              name: http
          volumeMounts:
            - mountPath: '/etc/prometheus'
              name: config-volume
            - mountPath: '/prometheus'
              name: data
          resources:
            requests:
              cpu: 100m
              memory: 512Mi
            limits:
              cpu: 100m
              memory: 512Mi
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: prometheus-data
        - configMap:
            name: prometheus-config
          name: config-volume

6. Service 暴露

# prometheus-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: prometheus
  namespace: monitor
spec:
  selector:
    app: prometheus
  type: NodePort
  ports:
    - name: web
      port: 9090
      targetPort: 9090

7. 部署命令

# 在 PV 所亲和的节点上创建目录
mkdir /data/k8s/prometheus
 
kubectl apply -f prometheus-cm.yaml
kubectl apply -f prometheus-pv-pvc.yaml
kubectl apply -f prometheus-rbac.yaml
kubectl apply -f prometheus-deploy.yaml
kubectl apply -f prometheus-svc.yaml
 
# 停掉二进制部署的 prometheus
systemctl stop prometheus
systemctl disable prometheus

8. 热更新配置

修改 ConfigMap 后执行:

# 获取 prometheus pod IP
kubectl -n monitor get pods -o wide
 
# 热重载配置
curl -X POST "http://<PROMETHEUS_POD_IP>:9090/-/reload"

五、监控应用软件

监控目标分类

类别监控对象方式
应用自带 /metricsRedis、MySQL、K8s 组件直接配置
无 /metrics 接口大多数应用部署对应 Exporter

5.1 监控 K8s 组件(自带接口)

- job_name: "coredns"
  static_configs:
    - targets: ["kube-dns.kube-system.svc.cluster.local:9153"]

5.2 监控 Redis(使用 Exporter)

安装 Redis:

yum install redis -y
sed -ri 's/bind 127.0.0.1/bind 0.0.0.0/g' /etc/redis.conf
sed -ri 's/port 6379/port 16379/g' /etc/redis.conf
echo "requirepass 123456" >> /etc/redis.conf
systemctl restart redis

安装 Redis Exporter:

wget https://github.com/oliver006/redis_exporter/releases/download/v1.61.0/redis_exporter-v1.61.0.linux-amd64.tar.gz
tar xf redis_exporter-v1.61.0.linux-amd64.tar.gz
mv redis_exporter /usr/bin/
 
cat > /usr/lib/systemd/system/redis_exporter.service << 'EOF'
[Unit]
Description=Redis Exporter
After=network.target
 
[Service]
ExecStart=/usr/bin/redis_exporter \
  --redis.addr=redis://127.0.0.1:16379 \
  --redis.password=123456 \
  --web.listen-address=0.0.0.0:9122
 
[Install]
WantedBy=multi-user.target
EOF
 
systemctl daemon-reload
systemctl restart redis_exporter

Prometheus 配置:

- job_name: "redis-server"
  static_configs:
    - targets: ["192.168.71.101:9122"]

5.3 监控 MySQL

安装 MySQL:

yum install mariadb-server -y
systemctl start mariadb
 
# 创建账号
mysql -e "CREATE USER 'mysql_exporter'@'localhost' IDENTIFIED BY '123456'"
mysql -e "GRANT ALL ON *.* TO 'mysql_exporter'@'localhost'"
 
cat >> /etc/my.cnf << 'EOF'
[client]
user=mysql_exporter
password=123456
EOF

安装 MySQL Exporter:

wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.15.1/mysqld_exporter-0.15.1.linux-amd64.tar.gz
tar xf mysqld_exporter-0.15.1.linux-amd64.tar.gz
mv mysqld_exporter /usr/bin/
 
cat > /etc/systemd/system/mysqld_exporter.service << 'EOF'
[Unit]
Description=Prometheus MySQL Exporter
After=network.target
 
[Service]
ExecStart=/usr/bin/mysqld_exporter --config.my-cnf=/etc/my.cnf
 
[Install]
WantedBy=multi-user.target
EOF
 
systemctl daemon-reload
systemctl restart mysqld_exporter

Prometheus 配置:

- job_name: "mysql-server"
  static_configs:
    - targets: ["192.168.71.102:9104"]

5.4 Sidecar 模式监控 K8s 中的应用

# redis-deployment.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
          ports:
            - containerPort: 6379
        - name: redis-exporter
          image: oliver006/redis_exporter:latest
          ports:
            - containerPort: 9121
---
apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: monitor
spec:
  selector:
    app: redis
  ports:
    - name: redis
      port: 6379
      targetPort: 6379
    - name: prom
      port: 9121
      targetPort: 9121

Prometheus 配置(使用 Service 名字):

- job_name: 'redis'
  static_configs:
    - targets: ['redis:9121']

六、监控物理节点(node-exporter)

二进制安装(每个节点都要)

wget https://github.com/prometheus/node_exporter/releases/download/v1.3.1/node_exporter-1.3.1.linux-amd64.tar.gz
tar xf node_exporter-1.3.1.linux-amd64.tar.gz
mv node_exporter /usr/bin/
 
cat > /usr/lib/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target
 
[Service]
ExecStart=/usr/bin/node_exporter
 
[Install]
WantedBy=multi-user.target
EOF
 
systemctl daemon-reload
systemctl restart node_exporter

Prometheus 配置(手动):

- job_name: "node-exporter"
  static_configs:
    - targets: ["192.168.71.101:9100", "192.168.71.102:9100", "192.168.71.103:9100"]

K8s 部署(DaemonSet 方式)

# prometheus-node-exporter.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-exporter
  namespace: monitor
spec:
  selector:
    matchLabels:
      app: node-exporter
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      hostPID: true
      hostIPC: true
      hostNetwork: true
      tolerations:
        - operator: 'Exists'
      nodeSelector:
        kubernetes.io/os: linux
      containers:
        - name: node-exporter
          image: quay.io/prometheus/node-exporter:latest
          args:
            - --web.listen-address=$(HOSTIP):9100
            - --path.procfs=/host/proc
            - --path.sysfs=/host/sys
            - --path.rootfs=/host/root
            - --no-collector.hwmon
            - --no-collector.nfs
            - --no-collector.nfsd
            - --no-collector.nvme
            - --no-collector.dmi
            - --no-collector.arp
            - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/containerd/.+|/var/lib/docker/.+|var/lib/kubelet/pods/.+)($|/)
            - --collector.filesystem.ignored-fs-types=^(autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$
          ports:
            - containerPort: 9100
          env:
            - name: HOSTIP
              valueFrom:
                fieldRef:
                  fieldPath: status.hostIP
          resources:
            requests:
              cpu: 150m
              memory: 180Mi
            limits:
              cpu: 150m
              memory: 180Mi
          volumeMounts:
            - name: proc
              mountPath: /host/proc
            - name: sys
              mountPath: /host/sys
            - name: root
              mountPath: /host/root
              mountPropagation: HostToContainer
              readOnly: true
      volumes:
        - name: proc
          hostPath:
            path: /proc
        - name: dev
          hostPath:
            path: /dev
        - name: sys
          hostPath:
            path: /sys
        - name: root
          hostPath:
            path: /

Prometheus 配置(自动发现):

- job_name: 'nodes'
  kubernetes_sd_configs:
    - role: node
  relabel_configs:
    - source_labels: [__address__]
      regex: '(.*):10250'
      replacement: '${1}:9100'
      target_label: __address__
      action: replace
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)

七、采集 K8s 集群指标

监控 kubelet/cAdvisor

- job_name: 'kubelet'
  kubernetes_sd_configs:
    - role: node
  scheme: 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:
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)

监控容器指标(cAdvisor)

- job_name: 'kubernetes-cadvisor'
  kubernetes_sd_configs:
    - role: node
  scheme: 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:
    - action: labelmap
      regex: __meta_kubernetes_node_label_(.+)
    - source_labels: [__meta_kubernetes_node_name]
      regex: (.+)
      replacement: /metrics/cadvisor
      target_label: __metrics_path__

cAdvisor 详解

cAdvisor = Container Advisor,K8s 内置的容器监控组件,自动采集容器运行指标。

┌─────────────────────────────────────────────────────────┐
│                     Node                                 │
│   ┌─────────────────────────────────────────┐          │
│   │              kubelet                     │          │
│   │   ┌─────────────────────────────┐      │          │
│   │   │       cAdvisor              │      │          │
│   │   │  (kubelet 内置组件)        │      │          │
│   │   └─────────────────────────────┘      │          │
│   │            ↑                           │          │
│   │   采集本节点所有容器的指标              │          │
│   └─────────────────────────────────────────┘          │
└─────────────────────────────────────────────────────────┘

自动发现与认证流程

# 1. 自动发现节点(role: node)
kubernetes_sd_configs:
  - role: node
 
# 自动获取:
# __address__ = 192.168.71.101:10250
# __meta_kubernetes_node_name = node1
# 2. HTTPS + Token 认证
scheme: https
tls_config:
  ca_file: /var/run/secrets/.../ca.crt
  insecure_skip_verify: true
bearer_token_file: /var/run/secrets/.../token

认证流程:

Prometheus 用 ServiceAccount 运行
→ K8s 自动挂载 token 到 Pod 内
→ Prometheus 访问 kubelet 时带上 Bearer Token
→ kubelet 验证 Token 权限
→ 有权限返回数据,无权限返回 403

relabel_configs 详解

第一步:复制 Node 标签

- action: labelmap
  regex: __meta_kubernetes_node_label_(.+)
K8s Node 标签:
  kubernetes.io/os: linux
  hostname: master01
 
Prometheus 标签:
  os: linux
  hostname: master01

第二步:修改采集路径

- source_labels: [__meta_kubernetes_node_name]
  regex: (.+)
  replacement: /metrics/cadvisor
  target_label: __metrics_path__
替换前:/metrics
替换后:/metrics/cadvisor

最终采集地址生成

┌─────────────────────────────────────────────────────────┐
│              最终采集地址生成过程                        │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  自动发现的 Node:                                       │
│    __address__ = 192.168.71.101:10250                 │
│                                                          │
│  relabel 后:                                           │
│    __metrics_path__ = /metrics                          │
│                    ↓                                    │
│    __metrics_path__ = /metrics/cadvisor                 │
│                                                          │
│  最终地址:                                              │
│    https://192.168.71.101:10250/metrics/cadvisor       │
│                                                          │
└─────────────────────────────────────────────────────────┘

cAdvisor 返回的常用指标

container_cpu_usage_seconds_total      # CPU 使用累计
container_memory_usage_bytes          # 内存使用字节
container_network_receive_bytes_total # 网络接收字节累计
container_network_transmit_bytes_total # 网络发送字节累计
container_fs_reads_bytes_total       # 磁盘读取字节累计
container_fs_writes_bytes_total       # 磁盘写入字节累计
container_spec_memory_limit_bytes    # 内存限制
container_spec_cpu_quota             # CPU 配额

常用 PromQL 查询

# CPU 使用率
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
 
# 内存使用率
100 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
 
# Pod CPU 使用率
sum(rate(container_cpu_usage_seconds_total{image!="",pod!=""}[5m])) by (namespace, pod)
 
# Pod 内存使用
container_memory_usage_bytes{image!="",pod!=""}
 
# 节点磁盘使用率
100 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100

八、总结

┌─────────────────────────────────────────────────────────┐
│               Prometheus 监控核心要点                    │
├─────────────────────────────────────────────────────────┤
│                                                          │
│  监控分类:                                               │
│  ├─ 黑盒监控:早于用户发现问题                           │
│  └─ 白盒监控:提前预防                                   │
│                                                          │
│  Prometheus 架构:                                        │
│  ├─ 上游:targets(K8s/Node/Exporter)                 │
│  ├─ 中间:Retrieval → TSDB → HTTP Server               │
│  └─ 下游:Grafana / Alertmanager                        │
│                                                          │
│  监控方式:                                               │
│  ├─ 应用自带 /metrics → 直接配置                        │
│  ├─ 无 /metrics → 部署对应 Exporter                    │
│  └─ K8s 集群 → ServiceMonitor / 自动发现               │
│                                                          │
│  K8s 集群监控:                                          │
│  ├─ kubelet:节点基础指标                               │
│  ├─ cAdvisor:容器指标                                  │
│  ├─ kube-state-metrics:K8s 资源状态                    │
│  └─ node-exporter:节点硬件/系统指标                     │
│                                                          │
│  常用 Exporter:                                         │
│  ├─ node-exporter:物理节点                            │
│  ├─ redis_exporter:Redis                              │
│  └─ mysqld_exporter:MySQL                             │
│                                                          │
└─────────────────────────────────────────────────────────┘

九、补充说明

1. Prometheus Server 本质是什么

本质上是一个:时序数据库 + HTTP 服务器

┌─────────────────────────────────────┐
│  Prometheus Server                   │
├─────────────────────────────────────┤
│                                      │
│   时序数据库(TSDB)                 │
│   = 存储带时间戳的数据               │
│   = 存的不是文档,是"指标随时间变化"  │
│                                      │
│   HTTP 服务器                        │
│   = 提供查询接口                     │
│   = Grafana/Alertmanager 来调用      │
│                                      │
└─────────────────────────────────────┘
不是说明
不是消息队列拉模式,不是推模式
不是传统数据库不是存业务数据的
不是监控 agent它是服务端,不是装在每台机器上的采集器

Prometheus Server = 一个专门存"监控指标历史"的数据库 + 查询接口。


2. PV 和 PVC 为什么要分离

PV 和 PVC 分离是为了"解耦",让不同角色做不同的事。

对比直接绑定 PVPV + PVC 分离
开发者要知道存储细节(路径、存储类型)只管申请"我需要 20Gi 存储"
灵活性
换存储类型要改 Pod 配置换个 StorageClass 就行

类比:租房

  • 直接绑定 PV = 买房子(不灵活)
  • PV + PVC = 租房(灵活,Pod 删除后 PVC 可以回收)

3. ConfigMap 中 prometheus.yml: | 是什么意思

| 是 YAML 语法,表示"多行字符串"。

data:
  prometheus.yml: |        # 文件名
    global:                  # 文件内容从这里开始
      scrape_interval: 15s
    scrape_configs:
      - job_name: 'prometheus'

展开后等价于:

data:
  "prometheus.yml": "global:\n  scrape_interval: 15s\n..."

K8s 挂载后,Pod 里会看到文件:

/etc/prometheus/
  └── prometheus.yml    ← 文件内容就是 | 后面的内容

4. redis_exporter 是谁开发的

开源项目,由个人维护。

信息内容
作者Oliver
GitHuboliver006/redis_exporter
Stars7000+
语言Go

所有 Exporter 汇总: https://prometheus.io/docs/instrumenting/exporters/


5. node-exporter DaemonSet 配置详解

为什么要用 DaemonSet

Deployment:部署 N 个 Pod,不一定在哪
DaemonSet:每个节点都部署 1 个 Pod(自动保证)

三个关键配置

(1)共享宿主机的命名空间:

hostPID: true      # 容器能看到主机的进程
hostIPC: true      # 容器能与主机共享 IPC
hostNetwork: true  # 容器使用主机网络

原因: 监控需要读取 /proc/stat、/proc/meminfo 等主机目录。

(2)挂载宿主机目录:

volumes:
  - name: proc
    hostPath:
      path: /proc      # 容器内 /host/proc → 主机 /proc

这样容器内读取 /host/proc 就等于读取主机的 /proc。

(3)容忍所有污点:

tolerations:
  - operator: 'Exists'

作用: 让 Pod 能调度到 Master 节点(Master 有污点,普通 Pod 调度不上去)。


6. relabel_configs 原理

自动发现节点后,默认端口是 10250(kubelet),需要改成 9100(node-exporter)。

relabel_configs:
  - source_labels: [__address__]    # 原始值:192.168.71.101:10250
    regex: '(.*):10250'              # 匹配 :10250
    replacement: '${1}:9100'         # 替换成 :9100
    target_label: __address__         # 重新赋值

转换过程:

192.168.71.101:10250
         ↓ regex (.*):10250
192.168.71.101       (.*) 捕获
         ↓ replacement: ${1}:9100
192.168.71.101:9100   最终结果

7. 自动发现 vs 手动配置

场景用哪种
K8s 集群内部的服务✅ 自动发现(推荐)
K8s 集群外部的服务(物理机/虚拟机/云数据库)❌ 必须手动配置
┌─────────────────────────────────────────┐
│          K8s 集群(Prometheus 在这)     │
│                                         │
│   自动发现 → 只能发现集群内部的东西       │
│                                         │
└─────────────────────────────────────────┘

         │ 集群外部(自动发现管不到)

┌─────────────────────────────────────────┐
│   物理机 MySQL、Redis                   │
│   云数据库 RDS                          │
│   → 只能用 static_configs 手动配置       │
└─────────────────────────────────────────┘

8. K8s 内部 DNS 访问格式

完整格式:

<service-name>.<namespace>.svc.<cluster-domain>
部分示例
<service-name>redis
<namespace>monitor
svc固定写法
<cluster-domain>cluster.local

不同写法:

# 同命名空间
redis:6379
 
# 不同命名空间
redis.monitor:6379
redis.monitor.svc.cluster.local:6379

9. 副本调度会到同一节点吗

默认不会,K8s 调度器会尽量分散。

Deployment replicas: 4
理想情况:
┌─────────┐  ┌─────────┐  ┌─────────┐
│ Node A  │  │ Node B  │  │ Node C  │
│ Pod 1   │  │ Pod 2   │  │ Pod 3   │
│         │  │         │  │ Pod 4   │
└─────────┘  └─────────┘  └─────────┘

但如果只有 2 个 Node,只能分散到 2 个节点上。


10. 制作系统服务是什么意思

让程序可以用 systemctl 管理,开机自启。

# 制作后可以用这些命令
systemctl start prometheus      # 启动
systemctl stop prometheus       # 停止
systemctl restart prometheus    # 重启
systemctl enable prometheus    # 开机自启

本质:把程序交给 systemd 管理。


八、K8s 监控详解

K8s 监控要做什么

监控对象说明
组件服务状态kube-apiserver、kube-scheduler、kube-controller-manager、etcd、coredns
业务服务状态业务 Pod → Endpoint
K8s 资源状态Pod、DaemonSet、Deployment、Job、CronJob 等资源的状态
容器状态cAdvisor 内置于 kubelet,负责采集容器指标

监控业务服务的条件

  1. 业务服务必须暴露 /metrics 接口
  2. 创建一个 Service,Service 会自动生成 Endpoint 资源
  3. 让 Service 带上指定的注解或标签
annotations:
  prometheus.io/scrape: "true"   # 开启监控
  prometheus.io/port: "9121"      # 监控端口

监控 API Server

- job_name: 'kubernetes-apiservers'
  kubernetes_sd_configs:
    - role: endpoints
  scheme: 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:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: default;kubernetes;https

监控 kube-controller-manager

1. 创建 Service:

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
  ports:
    - name: https-metrics
      port: 10257
      targetPort: 10257
  selector:
    component: kube-controller-manager

2. 修改默认监听地址:

# 每台 Master 节点都要改
vi /etc/kubernetes/manifests/kube-controller-manager.yaml
# 修改 --bind-address=127.0.0.1 → --bind-address=0.0.0.0

3. 添加监控配置:

- job_name: 'kube-controller-manager'
  kubernetes_sd_configs:
    - role: endpoints
  scheme: 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:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: kube-system;kube-controller-manager;https-metrics

监控 etcd

1. 修改 etcd 静态配置:

# 每台 Master 节点都要改
vi /etc/kubernetes/manifests/etcd.yaml
# 添加 --listen-metrics-urls=http://127.0.0.1:2381

2. 创建 etcd Service:

apiVersion: v1
kind: Service
metadata:
  namespace: kube-system
  name: etcd
  labels:
    k8s-app: etcd
spec:
  selector:
    component: etcd
  type: ClusterIP
  clusterIP: None
  ports:
    - name: http
      port: 2381
      targetPort: 2381

3. 添加监控配置:

- job_name: 'etcd'
  kubernetes_sd_configs:
    - role: endpoints
  scheme: http
  relabel_configs:
    - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
      action: keep
      regex: kube-system;etcd;http

自动发现业务服务

- job_name: 'kubernetes-endpoints'
  kubernetes_sd_configs:
    - role: endpoints
  relabel_configs:
    # 1. 只保留 prometheus.io/scrape="true" 的 Service
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep
      regex: true
 
    # 2. 从注解获取协议(http/https)
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
      action: replace
      target_label: __scheme__
      regex: (https?)
 
    # 3. 从注解获取路径
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
 
    # 4. 拼接 IP:Port
    - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__
      regex: ([^:]+)(?::\d+)?;(\d+)
      replacement: $1:$2
 
    # 5. 复制 Service 标签
    - action: labelmap
      regex: __meta_kubernetes_service_label_(.+)
 
    # 6. 替换标签名
    - source_labels: [__meta_kubernetes_namespace]
      action: replace
      target_label: kubernetes_namespace
    - source_labels: [__meta_kubernetes_service_name]
      action: replace
      target_label: kubernetes_name
    - source_labels: [__meta_kubernetes_pod_name]
      action: replace
      target_label: kubernetes_pod_name

示例:Redis Service 自动发现

apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: monitor
  annotations:
    prometheus.io/scrape: 'true'
    prometheus.io/port: '9121'
spec:
  selector:
    app: redis
  ports:
    - name: redis
      port: 6379
      targetPort: 6379
    - name: prom
      port: 9121
      targetPort: 9121

kube-state-metrics(监控 K8s 资源状态)

kube-state-metrics 擅长历史数据分析,不适合实时 HPA 决策。

# 1. 下载
git clone https://github.com/kubernetes/kube-state-metrics.git
cd kube-state-metrics/examples/standard
 
# 2. 修改 deployment.yaml 中的镜像地址(可选)
# 原镜像:registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.12.0
# 国内可改为阿里云镜像
 
# 3. Service 添加注解
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: exporter
    app.kubernetes.io/name: kube-state-metrics
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
  name: kube-state-metrics
  namespace: kube-system
spec:
  clusterIP: None
  ports:
    - name: http-metrics
      port: 8080
      targetPort: http-metrics
  selector:
    app.kubernetes.io/name: kube-state-metrics

4. 部署:

kubectl apply -f service-account.yaml
kubectl apply -f cluster-role-binding.yaml
kubectl apply -f cluster-role.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

常用查询:

# 节点状态错误
kube_node_status_condition{condition="Ready", status="true"}==1
kube_node_status_condition{condition="Ready", status!="true"}==1
 
# 启动失败的 Pod
kube_pod_status_phase{phase=~"Failed|Unknown"}==1
 
# 最近 30 分钟有容器重启
changes(kube_pod_container_status_restarts_total[30m])>0

九、PromQL 详解

数据格式

HELP node_cpu_seconds_total Seconds the CPUs spent in each mode.
TYPE node_cpu_seconds_total counter
node_cpu_seconds_total{cpu="0",mode="idle"} 3853.38
node_cpu_seconds_total{cpu="0",mode="iowait"} 0.26

监控样本 = 指标 + 标签 + 值

部分说明示例
指标名反映监控含义node_cpu_seconds_total
标签描述样本特征/维度{cpu="0",mode="idle"}
样本的具体数值3853.38

TSDB 时序数据库

Prometheus 将数据以时间序列保存在内存数据库中。

时间序列 = 同一指标按时间顺序存放的多个值
 
X轴 = 时间
Y轴 = 值

样本的三个组成部分:

  1. 指标(metric):指标名 + 标签
  2. 时间戳(timestamp):精确到毫秒
  3. 样本值(value):float64 浮点数
<metric name>{<labels>} @ <timestamp> => <value>
 
http_request_total{status="200", method="GET"} @ 1434417560938 => 94355
http_request_total{status="200", method="GET"} @ 1434417561287 => 94334

四种指标类型

1. Counter(计数器)

只增不减的计数器,适合累计值。

应用场景:
- CPU 使用时间
- 网络流量
- HTTP 请求总数
 
常用操作:
rate(node_cpu_seconds_total[5m])           # 增长率
topk(3, kubelet_http_requests_total)       # 排名前3

2. Gauge(仪表盘)

可增可减的仪表盘,适合瞬时值。

应用场景:
- 内存使用量
- CPU 负载
- 当前连接数
 
常用操作:
delta(node_memory_MemFree_bytes[1h])        # 变化量
predict_linear(node_filesystem_free_bytes[1h], 4*3600)  # 趋势预测

3. Histogram(直方图)

将样本分段统计,用于分析数据分布。

# 示例:HTTP 请求延迟分布
http_request_duration_seconds_bucket{le="0.1"} 20     # 20 个请求 < 0.1s
http_request_duration_seconds_bucket{le="0.5"} 40     # 40 个请求 < 0.5s
http_request_duration_seconds_bucket{le="1"} 45       # 45 个请求 < 1s
http_request_duration_seconds_bucket{le="+Inf"} 50   # 总共 50 个请求
 
# 计算 99 分位数
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))

4. Summary(摘要)

预先计算百分位数,提供实时延迟分布。

# 示例
go_gc_duration_seconds{quantile="0"} 2.1928e-05    # 0% 分位
go_gc_duration_seconds{quantile="0.25"} 3.225e-05  # 25% 分位
go_gc_duration_seconds{quantile="0.5"} 3.5691e-05  # 50% 分位(中位数)
go_gc_duration_seconds{quantile="0.75"} 3.7185e-05 # 75% 分位
go_gc_duration_seconds{quantile="0.99"} 0.001       # 99% 分位

向量类型

类型说明示例
瞬时向量(Instant Vector)每个时间序列只有一个最新值node_cpu_seconds_total{mode="idle"}
区间向量(Range Vector)每个时间序列包含一段时间的数据node_cpu_seconds_total{mode="idle"}[5m]
标量(Scalar)单独的浮点数100

PromQL 语法

标签过滤

# 精确匹配
node_cpu_seconds_total{instance="master01", mode="idle"}
 
# 不等于
node_cpu_seconds_total{instance!="node01"}
 
# 正则匹配
node_cpu_seconds_total{instance=~"master.*"}
 
# 正则不匹配
node_cpu_seconds_total{instance!~"master.*"}

时间范围

# 默认(当前)
node_cpu_seconds_total{instance="master01"}
 
# 最近 5 分钟
node_cpu_seconds_total{instance="master01"}[5m]
 
# 偏移量(查过去)
node_cpu_seconds_total{instance="master01"} offset 5m
 
# 5 小时前到 5 分钟前的数据
node_cpu_seconds_total[5m] offset 5h

rate vs irate

# rate:计算平均速率(稳定、平滑)
rate(node_cpu_seconds_total{mode="idle"}[5m])
 
# irate:计算瞬时速率(对变化敏感)
irate(node_cpu_seconds_total{mode="idle"}[5m])

运算符

算术运算符

# 单位转换
node_memory_MemFree_bytes / 1024 / 1024  # 字节转 MB
 
# 磁盘读写总量
node_disk_read_bytes_total{device="sda"} + node_disk_written_bytes_total{device="sda"}
 
# 计算百分比
(node_memory_MemFree_bytes / node_memory_MemTotal_bytes) * 100

比较运算符

# 内存使用率
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 80

逻辑运算符

# and:同时满足
# or:满足其一
# unless:排除

聚合运算

# sum:求和
sum(rate(node_cpu_seconds_total[5m]))
 
# count:计数
count(node_cpu_seconds_total)
 
# avg:平均值
avg(rate(node_cpu_seconds_total[5m])) by (instance)
 
# max/min:最大/最小值
max(node_network_receive_bytes_total) by (instance)
 
# topk/bottomk:最大/最小的 N 个
topk(3, node_cpu_seconds_total)
bottomk(5, node_memory_MemFree_bytes)
 
# by/without:按标签分组/排除
sum(rate(node_network_receive_bytes_total[5m])) by (instance)
sum(rate(node_network_receive_bytes_total[5m])) without (device)

常用 PromQL 示例

# CPU 使用率
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
 
# 内存使用率
100 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100
 
# Pod CPU 使用率
sum(rate(container_cpu_usage_seconds_total{image!=""}[5m])) by (namespace, pod)
 
# Pod 内存使用
sum(container_memory_usage_bytes{image!=""}) by (namespace, pod)
 
# HTTP 请求增长率
rate(http_requests_total[5m])
 
# 99 分位延迟
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
 
# 预测磁盘空间(4 小时后)
predict_linear(node_filesystem_free_bytes{mountpoint="/"}[1h], 4*3600)

长尾问题与 Histogram/Summary

长尾问题: 大部分请求正常,但少量请求极慢,平均值无法反映真实情况。

比如 100 个请求:
- 99 个请求 100ms
- 1 个请求 10s
 
平均值 = (99*0.1 + 10) / 100 = 199ms(看起来还行)
实际用户体验很差

Histogram: 统计每个区间的请求数量,精确分析分布。 Summary: 预先计算百分位数,快速判断长尾。

# Histogram:查看 99% 请求在多少秒内完成
histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le))
# 结果:0.5s 表示 99% 请求 < 0.5s
分享

// RELATED_POSTS

0%