在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Prometheus这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


Prometheus - 监控 Docker 容器:cAdvisor 集成与容器指标分析

在现代云原生架构中,Docker 容器已经成为部署和运行应用程序的标准方式。然而,随着容器数量的激增和微服务架构的普及,如何有效地监控这些动态、短暂的容器实例成为了一个关键挑战。传统的监控工具往往难以适应容器化环境的快速变化和高动态性。幸运的是,Prometheus 与 cAdvisor 的组合为我们提供了一套强大而灵活的解决方案,能够深入洞察容器的运行状态和资源使用情况。

为什么需要监控 Docker 容器?

在深入技术细节之前,让我们先思考一下为什么监控 Docker 容器如此重要。容器化虽然带来了部署的便利性和环境的一致性,但也引入了新的复杂性:

  • 资源隔离与共享:多个容器共享主机资源,需要监控 CPU、内存、磁盘 I/O 和网络使用情况,防止资源争用
  • 动态生命周期:容器可以快速启动和停止,监控系统需要能够自动发现和跟踪这些变化
  • 性能瓶颈识别:当应用性能下降时,需要快速定位是哪个容器或服务导致的问题
  • 容量规划:基于历史数据预测未来的资源需求,优化基础设施成本
  • 故障排查:当容器崩溃或行为异常时,需要详细的指标数据来诊断问题根源

🎯 核心挑战:传统的监控工具通常基于静态的主机和服务配置,而容器环境是高度动态的。我们需要一个能够自动发现容器、收集细粒度指标、并提供强大查询能力的监控系统。

Prometheus 简介

Prometheus 是一个开源的系统监控和警报工具包,最初由 SoundCloud 开发,现在是 Cloud Native Computing Foundation (CNCF) 的毕业项目之一。它专为云原生环境设计,具有以下关键特性:

  • 多维数据模型:时间序列数据通过指标名称和键值对标签进行标识
  • 强大的查询语言:PromQL 允许进行复杂的查询、聚合和数学运算
  • 拉取式架构:Prometheus 主动从目标端点拉取指标数据
  • 服务发现:支持多种服务发现机制,包括 Docker、Kubernetes、Consul 等
  • 本地存储:高效的时间序列数据库,支持长期数据保留
  • 丰富的生态系统:大量的客户端库、导出器和可视化工具

Prometheus 的架构相对简单但功能强大。它包含以下几个核心组件:

  1. Prometheus Server:负责数据抓取、存储和查询
  2. Client Libraries:用于在应用程序中暴露指标
  3. Exporters:将第三方系统的指标转换为 Prometheus 格式
  4. Alertmanager:处理警报通知
  5. Pushgateway:用于处理短期作业的指标推送

cAdvisor 简介

cAdvisor(Container Advisor)是 Google 开发的一个开源容器分析工具,专门用于收集、聚合、处理和导出运行中容器的资源使用情况和性能数据。它能够自动发现给定机器上的所有容器,并收集 CPU、内存、文件系统和网络使用情况等统计信息。

cAdvisor 的主要特点包括:

  • 自动容器发现:无需手动配置,自动检测所有运行的容器
  • 丰富的指标:提供详细的容器资源使用指标
  • 多容器运行时支持:支持 Docker、containerd、CRI-O 等
  • Web UI:内置简单的 Web 界面用于查看实时数据
  • Prometheus 兼容:原生支持 Prometheus 指标格式

cAdvisor 本质上是一个容器监控的"导出器"(exporter),它将容器的底层指标以 Prometheus 能够理解的格式暴露出来。

架构概览

让我们通过一个简单的架构图来理解 Prometheus、cAdvisor 和 Docker 容器之间的关系:

定期拉取指标

监控

查询和告警

发送告警

Prometheus Server

cAdvisor

Docker Host

Container 1

Container 2

Container N

Grafana Dashboard

Alertmanager

在这个架构中:

  1. cAdvisor 运行在每个 Docker 主机上,监控该主机上的所有容器
  2. Prometheus Server 定期从 cAdvisor 实例拉取指标数据
  3. Grafana 用于可视化展示监控数据
  4. Alertmanager 处理基于指标的告警规则

这种架构的优势在于它的分布式特性和可扩展性。每个主机只需要运行一个 cAdvisor 实例,Prometheus 可以集中管理多个主机的监控数据。

环境准备

在开始集成之前,我们需要准备一个基本的实验环境。假设你已经安装了以下工具:

  • Docker Engine(版本 18.09 或更高)
  • Docker Compose(版本 1.25.0 或更高)

如果你还没有安装这些工具,可以参考 Docker 官方文档 进行安装。

创建项目目录结构

首先,创建一个项目目录来组织我们的配置文件:

mkdir prometheus-cadvisor-demo
cd prometheus-cadvisor-demo

编写 docker-compose.yml

我们将使用 Docker Compose 来一键启动整个监控栈。创建 docker-compose.yml 文件:

version: '3.8'

services:
  # cAdvisor 服务
  cadvisor:
    image: gcr.io/cadvisor/cadvisor:v0.47.0
    container_name: cadvisor
    privileged: true
    devices:
      - /dev/kmsg
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:ro
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
      - /dev/disk/:/dev/disk:ro
    ports:
      - "8080:8080"
    restart: unless-stopped

  # Prometheus 服务
  prometheus:
    image: prom/prometheus:v2.45.0
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/etc/prometheus/console_libraries'
      - '--web.console.templates=/etc/prometheus/consoles'
      - '--web.enable-lifecycle'
    restart: unless-stopped

  # Grafana 服务
  grafana:
    image: grafana/grafana:10.0.3
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana_data:/var/lib/grafana
    restart: unless-stopped

volumes:
  prometheus_data:
  grafana_data:

这个配置文件定义了三个服务:

  1. cadvisor:运行 cAdvisor 容器,需要特权模式和挂载多个主机目录来访问容器信息
  2. prometheus:运行 Prometheus 服务器,挂载配置文件
  3. grafana:运行 Grafana 仪表板,用于数据可视化

配置 Prometheus

创建 prometheus.yml 配置文件:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

这个配置告诉 Prometheus:

  • 每 15 秒抓取一次指标数据
  • 监控自身(Prometheus)的指标
  • 从 cAdvisor 服务(在 Docker 网络中可通过 cadvisor:8080 访问)抓取容器指标

启动监控栈

现在我们可以启动整个监控栈:

docker-compose up -d

启动完成后,你可以通过以下 URL 访问各个服务:

  • cAdvisor: http://localhost:8080
  • Prometheus: http://localhost:9090
  • Grafana: http://localhost:3000 (用户名: admin, 密码: admin)

cAdvisor 指标详解

cAdvisor 提供了大量关于容器资源使用的指标。让我们深入了解一些关键指标:

CPU 相关指标

  • container_cpu_usage_seconds_total:容器 CPU 使用时间(秒),按 CPU 核心分类
  • container_cpu_system_usage_seconds_total:容器系统 CPU 使用时间
  • container_cpu_user_usage_seconds_total:容器用户 CPU 使用时间
  • container_cpu_load_average_10s:过去 10 秒的 CPU 负载平均值

内存相关指标

  • container_memory_usage_bytes:容器当前内存使用量(字节)
  • container_memory_working_set_bytes:容器工作集内存使用量(活跃内存)
  • container_memory_rss:容器 RSS(Resident Set Size)内存
  • container_memory_cache:容器缓存内存
  • container_memory_swap:容器交换内存使用量

磁盘 I/O 相关指标

  • container_fs_reads_bytes_total:容器文件系统读取总字节数
  • container_fs_writes_bytes_total:容器文件系统写入总字节数
  • container_fs_reads_total:容器文件系统读取操作次数
  • container_fs_writes_total:容器文件系统写入操作次数

网络相关指标

  • container_network_receive_bytes_total:容器网络接收总字节数
  • container_network_transmit_bytes_total:容器网络发送总字节数
  • container_network_receive_packets_total:容器网络接收数据包总数
  • container_network_transmit_packets_total:容器网络发送数据包总数

容器状态指标

  • container_start_time_seconds:容器启动时间戳
  • container_last_seen:容器最后被看到的时间戳
  • container_spec_cpu_quota:容器 CPU 配额
  • container_spec_memory_limit_bytes:容器内存限制

这些指标都带有丰富的标签,如 container_nameimagenamespace 等,使得我们可以进行多维度的查询和分析。

PromQL 查询实战

Prometheus Query Language (PromQL) 是 Prometheus 的查询语言,它允许我们对时间序列数据进行复杂的查询和分析。让我们通过一些实际例子来学习如何使用 PromQL 查询容器指标。

基础查询

首先,在 Prometheus Web UI 中,我们可以直接查询指标名称来查看原始数据:

container_memory_usage_bytes

这将返回所有容器的内存使用量。由于数据量可能很大,我们可以添加标签过滤器:

container_memory_usage_bytes{container_name="prometheus"}

计算容器 CPU 使用率

CPU 使用率是一个派生指标,需要通过计算得到。以下查询计算每个容器的 CPU 使用率(百分比):

rate(container_cpu_usage_seconds_total{container_name!="",container_name!="POD"}[1m]) * 100

这里使用了 rate() 函数来计算每秒的平均增长率,然后乘以 100 得到百分比。我们还排除了空容器名和 Kubernetes 的 POD 容器。

容器内存使用率

要计算容器的内存使用率,我们需要知道容器的内存限制:

(container_memory_usage_bytes{container_name!="",container_name!="POD"} 
/ 
container_spec_memory_limit_bytes{container_name!="",container_name!="POD"}) * 100

网络流量监控

监控容器的网络流量对于识别异常行为非常重要:

# 接收速率(字节/秒)
rate(container_network_receive_bytes_total{container_name!="POD"}[1m])

# 发送速率(字节/秒)
rate(container_network_transmit_bytes_total{container_name!="POD"}[1m])

磁盘 I/O 监控

磁盘 I/O 性能对某些应用至关重要:

# 读取速率(字节/秒)
rate(container_fs_reads_bytes_total{container_name!="POD"}[1m])

# 写入速率(字节/秒)
rate(container_fs_writes_bytes_total{container_name!="POD"}[1m])

容器重启监控

容器频繁重启通常表明存在问题:

changes(container_start_time_seconds{container_name!="POD"}[1h])

这个查询返回在过去一小时内每个容器的重启次数。

Java 应用程序集成示例

现在让我们创建一个简单的 Java 应用程序,并将其容器化,然后通过 Prometheus 监控它。我们将使用 Spring Boot 和 Micrometer 来暴露应用程序级别的指标。

创建 Spring Boot 应用

首先,创建一个简单的 Spring Boot 应用程序。pom.xml 文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>prometheus-demo-app</artifactId>
    <version>1.0.0</version>
    <packaging>jar</packaging>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.0</version>
        <relativePath/>
    </parent>
    
    <properties>
        <java.version>17</java.version>
    </properties>
    
    <dependencies>
        <!-- Spring Boot Web Starter -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <!-- Spring Boot Actuator for metrics -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        
        <!-- Micrometer Prometheus registry -->
        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
            <scope>runtime</scope>
        </dependency>
        
        <!-- Lombok for cleaner code -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

主应用程序类

创建主应用程序类 PrometheusDemoApplication.java

package com.example.prometheusdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class PrometheusDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(PrometheusDemoApplication.class, args);
    }
}

REST 控制器

创建一个简单的 REST 控制器来提供一些业务逻辑:

package com.example.prometheusdemo.controller;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/api")
public class DemoController {
    
    private final Counter requestCounter;
    private final Timer processingTimer;
    
    @Autowired
    public DemoController(MeterRegistry meterRegistry) {
        // 创建自定义计数器指标
        this.requestCounter = Counter.builder("demo_requests_total")
                .description("Total number of demo requests")
                .register(meterRegistry);
                
        // 创建自定义计时器指标
        this.processingTimer = Timer.builder("demo_processing_duration_seconds")
                .description("Time spent processing demo requests")
                .register(meterRegistry);
    }
    
    @GetMapping("/hello")
    public String hello() {
        requestCounter.increment();
        return "Hello from Prometheus Demo!";
    }
    
    @GetMapping("/process")
    public String process(@RequestParam(defaultValue = "100") int delayMs) {
        requestCounter.increment();
        
        // 模拟处理时间
        return processingTimer.recordCallable(() -> {
            try {
                TimeUnit.MILLISECONDS.sleep(delayMs);
                return "Processed with " + delayMs + "ms delay";
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("Processing interrupted", e);
            }
        });
    }
    
    @PostMapping("/data")
    public String handleData(@RequestBody String data) {
        requestCounter.increment();
        return "Received data: " + data.length() + " characters";
    }
}

配置文件

创建 application.yml 配置文件:

server:
  port: 8081

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus,metrics
  endpoint:
    health:
      show-details: always
  metrics:
    tags:
      application: ${spring.application.name}
  info:
    env:
      enabled: true

spring:
  application:
    name: prometheus-demo-app

这个配置启用了 Prometheus 指标端点,并将应用程序名称作为标签添加到所有指标中。

自定义指标示例

除了上面控制器中的自定义指标,我们还可以创建更复杂的指标。例如,监控业务逻辑中的特定事件:

package com.example.prometheusdemo.service;

import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.stereotype.Service;

import java.util.concurrent.atomic.AtomicInteger;

@Service
public class BusinessService {
    
    private final AtomicInteger activeUsers = new AtomicInteger(0);
    private final Gauge activeUsersGauge;
    
    public BusinessService(MeterRegistry meterRegistry) {
        // 创建 Gauge 指标来监控活跃用户数
        this.activeUsersGauge = Gauge.builder("demo_active_users")
                .description("Number of currently active users")
                .register(meterRegistry, activeUsers, AtomicInteger::get);
    }
    
    public void userLogin(String userId) {
        activeUsers.incrementAndGet();
        // 业务逻辑...
    }
    
    public void userLogout(String userId) {
        activeUsers.decrementAndGet();
        // 业务逻辑...
    }
    
    public int getActiveUsers() {
        return activeUsers.get();
    }
}

Dockerfile

创建 Dockerfile 来容器化我们的应用程序:

FROM openjdk:17-jdk-slim

WORKDIR /app

COPY target/prometheus-demo-app-1.0.0.jar app.jar

EXPOSE 8081

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:8081/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]

构建和运行应用程序

首先构建 Java 应用程序:

mvn clean package

然后构建 Docker 镜像:

docker build -t prometheus-demo-app:1.0.0 .

现在,我们需要更新我们的 docker-compose.yml 文件来包含这个应用程序:

version: '3.8'

services:
  # ... 其他服务保持不变 ...
  
  # 我们的 Java 应用程序
  demo-app:
    image: prometheus-demo-app:1.0.0
    container_name: demo-app
    ports:
      - "8081:8081"
    restart: unless-stopped

  # ... 其他服务保持不变 ...

同时,更新 prometheus.yml 来监控我们的应用程序:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'cadvisor'
    static_configs:
      - targets: ['cadvisor:8080']

  - job_name: 'demo-app'
    static_configs:
      - targets: ['demo-app:8081']
    metrics_path: '/actuator/prometheus'

重新启动整个栈:

docker-compose down
docker-compose up -d

现在,我们的 Java 应用程序正在运行,并且 Prometheus 正在从两个来源收集指标:

  1. cAdvisor:提供容器级别的系统指标(CPU、内存、网络等)
  2. 应用程序:提供应用程序级别的业务指标(请求计数、处理时间等)

高级监控场景

有了基础的监控设置后,让我们探索一些更高级的监控场景。

容器资源使用趋势分析

我们可以使用 PromQL 来分析容器资源使用的长期趋势。例如,计算过去 24 小时内内存使用的平均值、最大值和最小值:

avg_over_time(container_memory_usage_bytes{container_name="demo-app"}[24h])
max_over_time(container_memory_usage_bytes{container_name="demo-app"}[24h])
min_over_time(container_memory_usage_bytes{container_name="demo-app"}[24h])

异常检测

通过比较当前指标与历史基线,我们可以检测异常行为。例如,检测 CPU 使用率突然飙升:

# 当前 CPU 使用率
rate(container_cpu_usage_seconds_total{container_name="demo-app"}[5m]) * 100
>
# 过去一周同一时间的平均 CPU 使用率的 2 倍
avg_over_time(
  rate(container_cpu_usage_seconds_total{container_name="demo-app"}[5m])[7d:1h]
) * 100 * 2

服务级别指标 (SLI/SLO)

对于生产环境,我们通常需要定义服务级别指标。例如,计算 HTTP 请求的成功率:

# 成功请求率(HTTP 2xx 和 3xx)
sum(rate(http_server_requests_seconds_count{status=~"2..|3..", application="prometheus-demo-app"}[5m]))
/
sum(rate(http_server_requests_seconds_count{application="prometheus-demo-app"}[5m]))

延迟分位数分析

了解请求延迟的分布对于性能优化至关重要:

# 95th 百分位延迟
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application="prometheus-demo-app"}[5m])) by (le))

告警配置

监控的价值不仅在于观察,更在于及时发现问题。Prometheus 的告警功能可以帮助我们在问题发生时及时通知相关人员。

配置 Alertmanager

首先,我们需要配置 Alertmanager。创建 alertmanager.yml 文件:

global:
  resolve_timeout: 5m

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'email-notifications'

receivers:
- name: 'email-notifications'
  email_configs:
  - to: 'admin@example.com'
    from: 'alertmanager@example.com'
    smarthost: 'smtp.example.com:587'
    auth_username: 'alertmanager@example.com'
    auth_password: 'your-password'

更新 docker-compose.yml 添加 Alertmanager 服务:

  alertmanager:
    image: prom/alertmanager:v0.25.0
    container_name: alertmanager
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
    restart: unless-stopped

更新 prometheus.yml 配置告警规则和 Alertmanager:

global:
  scrape_interval: 15s
  evaluation_interval: 15s

alerting:
  alertmanagers:
    - static_configs:
        - targets: ['alertmanager:9093']

rule_files:
  - "alert_rules.yml"

# ... scrape_configs 保持不变 ...

创建告警规则

创建 alert_rules.yml 文件:

groups:
- name: container-alerts
  rules:
  - alert: HighContainerMemoryUsage
    expr: |
      (container_memory_usage_bytes{container_name!="",container_name!="POD"} 
      / 
      container_spec_memory_limit_bytes{container_name!="",container_name!="POD"}) > 0.8
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High memory usage on container {{ $labels.container_name }}"
      description: "Container {{ $labels.container_name }} is using more than 80% of its memory limit."

  - alert: HighContainerCPUUsage
    expr: rate(container_cpu_usage_seconds_total{container_name!="",container_name!="POD"}[5m]) * 100 > 80
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High CPU usage on container {{ $labels.container_name }}"
      description: "Container {{ $labels.container_name }} is using more than 80% CPU."

  - alert: ContainerDown
    expr: absent(container_last_seen{container_name!="POD"})
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "Container is down"
      description: "A container has disappeared from monitoring."

- name: application-alerts
  rules:
  - alert: HighRequestErrorRate
    expr: |
      sum(rate(http_server_requests_seconds_count{status=~"5..", application="prometheus-demo-app"}[5m]))
      /
      sum(rate(http_server_requests_seconds_count{application="prometheus-demo-app"}[5m])) > 0.05
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High error rate in demo application"
      description: "More than 5% of requests are returning 5xx errors."

  - alert: HighRequestLatency
    expr: histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application="prometheus-demo-app"}[5m])) by (le)) > 2
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "High request latency in demo application"
      description: "95th percentile request latency is above 2 seconds."

这些告警规则涵盖了容器和应用程序两个层面的关键指标。

Grafana 仪表板配置

虽然 Prometheus 提供了基本的查询界面,但 Grafana 提供了更强大的可视化能力。让我们创建一个综合的仪表板来监控我们的容器和应用程序。

配置 Prometheus 数据源

  1. 访问 http://localhost:3000
  2. 登录(admin/admin)
  3. 点击左侧齿轮图标(Configuration)→ Data Sources
  4. 点击 “Add data source”
  5. 选择 “Prometheus”
  6. URL 设置为 http://prometheus:9090
  7. 点击 “Save & Test”

创建仪表板

点击左侧 “+” → “Dashboard” → “New dashboard”。

容器概览面板

添加以下面板:

  1. 容器 CPU 使用率

    • Query: rate(container_cpu_usage_seconds_total{container_name!="",container_name!="POD"}[1m]) * 100
    • Visualization: Time series
    • Legend: {{container_name}}
  2. 容器内存使用量

    • Query: container_memory_usage_bytes{container_name!="",container_name!="POD"}
    • Visualization: Time series
    • Unit: bytes
  3. 容器网络流量

    • Query A: rate(container_network_receive_bytes_total{container_name!="POD"}[1m])
    • Query B: rate(container_network_transmit_bytes_total{container_name!="POD"}[1m])
    • Visualization: Time series
    • Unit: Bps
应用程序指标面板
  1. HTTP 请求率

    • Query: sum(rate(http_server_requests_seconds_count{application="prometheus-demo-app"}[1m]))
    • Visualization: Time series
    • Unit: reqps
  2. HTTP 错误率

    • Query: sum(rate(http_server_requests_seconds_count{status=~"4..|5..", application="prometheus-demo-app"}[1m]))
    • Visualization: Time series
    • Unit: reqps
  3. 请求延迟

    • Query: histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application="prometheus-demo-app"}[1m])) by (le))
    • Visualization: Time series
    • Unit: s
  4. 自定义业务指标

    • Query: demo_requests_total{application="prometheus-demo-app"}
    • Visualization: Time series
    • Unit: short

仪表板变量

为了提高仪表板的交互性,我们可以添加变量:

  1. 点击仪表板设置 → Variables → New
  2. Name: container
  3. Label: Container
  4. Query: label_values(container_name)
  5. Regex: /^(?!$|POD).*/

现在我们可以在查询中使用 $container 变量来动态过滤特定容器。

性能优化和最佳实践

在生产环境中部署 Prometheus 监控时,需要考虑性能和可扩展性。以下是一些重要的最佳实践:

数据保留策略

Prometheus 默认保留 15 天的数据。对于生产环境,你可能需要调整这个设置:

# 在 prometheus.yml 中添加
storage:
  tsdb:
    retention.time: 30d  # 保留 30 天数据

或者在启动命令中指定:

command:
  - '--storage.tsdb.retention.time=30d'

抓取间隔优化

默认的 15 秒抓取间隔对于大多数场景是合适的,但对于高频率变化的指标,可能需要更短的间隔;对于稳定的指标,可以使用更长的间隔以减少存储压力。

scrape_configs:
  - job_name: 'high-frequency'
    scrape_interval: 5s
    static_configs:
      - targets: ['target:port']
      
  - job_name: 'low-frequency'
    scrape_interval: 60s
    static_configs:
      - targets: ['target:port']

标签管理

过多的标签组合会导致时间序列爆炸(cardinality explosion)。避免使用高基数的标签,如用户 ID、请求 ID 等。

// ❌ 不好的做法 - 高基数标签
Counter.builder("requests_total")
    .tag("user_id", userId)  // 用户 ID 可能有成千上万个
    .register(registry);

// ✅ 好的做法 - 有限的标签值
Counter.builder("requests_total")
    .tag("endpoint", "/api/users")  // 有限的端点数量
    .tag("status", "200")           // 有限的状态码
    .register(registry);

联邦集群

对于大规模部署,可以考虑使用 Prometheus 联邦(Federation)模式,将多个 Prometheus 实例的数据汇总到一个全局实例中。

federate

federate

federate

Global Prometheus

Region 1 Prometheus

Region 2 Prometheus

Region 3 Prometheus

Local Targets

Local Targets

Local Targets

远程存储

对于需要长期保留数据的场景,可以配置远程存储后端,如 Thanos、Cortex 或 VictoriaMetrics。

故障排查常见问题

在实际使用过程中,可能会遇到各种问题。以下是一些常见问题及其解决方案:

1. cAdvisor 无法获取容器指标

问题:cAdvisor 显示没有容器数据,或者只有部分容器数据。

解决方案

  • 确保 cAdvisor 容器以特权模式运行
  • 检查挂载的卷是否正确
  • 确认 Docker 版本兼容性
  • 查看 cAdvisor 日志:docker logs cadvisor

2. Prometheus 无法抓取目标

问题:Prometheus 的 Targets 页面显示目标为 DOWN 状态。

解决方案

  • 检查网络连通性:docker exec prometheus curl -v http://cadvisor:8080/metrics
  • 确认目标服务是否正常运行
  • 检查防火墙设置
  • 查看 Prometheus 日志中的错误信息

3. 指标数据不完整

问题:某些预期的指标没有出现在 Prometheus 中。

解决方案

  • 检查应用程序的指标端点是否正确暴露
  • 确认 Micrometer 配置是否正确
  • 使用 curl 直接访问指标端点验证数据
  • 检查 Prometheus 抓取配置中的 metrics_path

4. 高内存使用

问题:Prometheus 或 cAdvisor 占用过多内存。

解决方案

  • 调整 Prometheus 的内存限制
  • 优化抓取配置,减少不必要的指标
  • 使用指标重写(metric relabeling)来删除不需要的标签
  • 考虑使用远程存储来减少本地存储压力

扩展监控范围

除了基本的容器监控,我们还可以扩展监控范围到其他方面:

主机级别监控

虽然 cAdvisor 提供了容器级别的监控,但我们可能还需要监控主机级别的指标。可以使用 Node Exporter:

# 在 docker-compose.yml 中添加
node-exporter:
  image: prom/node-exporter:v1.6.1
  container_name: node-exporter
  ports:
    - "9100:9100"
  volumes:
    - /proc:/proc:ro
    - /sys:/sys:ro
    - /:/rootfs:ro
  command:
    - '--path.procfs=/proc'
    - '--path.sysfs=/sys'
    - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
  restart: unless-stopped

日志监控

虽然本文主要关注指标监控,但日志监控同样重要。可以考虑集成 Loki 或 ELK Stack 来实现日志的集中收集和分析。

分布式追踪

对于微服务架构,分布式追踪可以帮助理解请求在不同服务间的流转。可以集成 Jaeger 或 Zipkin。

总结

通过本文的详细介绍,我们已经建立了一个完整的 Docker 容器监控解决方案,包括:

基础架构搭建:使用 Docker Compose 一键部署 Prometheus、cAdvisor、Grafana 和 Alertmanager

容器指标监控:深入理解 cAdvisor 提供的各种容器指标

应用程序集成:通过 Spring Boot 和 Micrometer 将应用程序指标暴露给 Prometheus

高级查询技巧:掌握 PromQL 进行复杂的指标分析和异常检测

告警配置:设置合理的告警规则,及时发现问题

可视化展示:使用 Grafana 创建直观的监控仪表板

最佳实践:了解性能优化和故障排查的关键要点

这套监控方案不仅适用于开发和测试环境,经过适当的调整和优化后,完全可以用于生产环境。通过持续监控容器和应用程序的健康状态,我们可以确保系统的稳定性和可靠性,快速响应潜在问题,并为容量规划提供数据支持。

容器化时代的监控不再是可选项,而是必需品。Prometheus 与 cAdvisor 的组合为我们提供了一个强大、灵活且开源的解决方案,帮助我们在复杂的容器环境中保持清晰的视野和快速的响应能力。🚀

记住,监控的目标不仅仅是收集数据,更重要的是通过这些数据获得洞察,做出更好的决策。正如 Prometheus 官方网站 所说:“From metrics to insight” —— 从指标到洞察。

Happy Monitoring! 📊


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐