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

👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕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 的架构相对简单但功能强大。它包含以下几个核心组件:
- Prometheus Server:负责数据抓取、存储和查询
- Client Libraries:用于在应用程序中暴露指标
- Exporters:将第三方系统的指标转换为 Prometheus 格式
- Alertmanager:处理警报通知
- Pushgateway:用于处理短期作业的指标推送
cAdvisor 简介
cAdvisor(Container Advisor)是 Google 开发的一个开源容器分析工具,专门用于收集、聚合、处理和导出运行中容器的资源使用情况和性能数据。它能够自动发现给定机器上的所有容器,并收集 CPU、内存、文件系统和网络使用情况等统计信息。
cAdvisor 的主要特点包括:
- 自动容器发现:无需手动配置,自动检测所有运行的容器
- 丰富的指标:提供详细的容器资源使用指标
- 多容器运行时支持:支持 Docker、containerd、CRI-O 等
- Web UI:内置简单的 Web 界面用于查看实时数据
- Prometheus 兼容:原生支持 Prometheus 指标格式
cAdvisor 本质上是一个容器监控的"导出器"(exporter),它将容器的底层指标以 Prometheus 能够理解的格式暴露出来。
架构概览
让我们通过一个简单的架构图来理解 Prometheus、cAdvisor 和 Docker 容器之间的关系:
在这个架构中:
- cAdvisor 运行在每个 Docker 主机上,监控该主机上的所有容器
- Prometheus Server 定期从 cAdvisor 实例拉取指标数据
- Grafana 用于可视化展示监控数据
- 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:
这个配置文件定义了三个服务:
- cadvisor:运行 cAdvisor 容器,需要特权模式和挂载多个主机目录来访问容器信息
- prometheus:运行 Prometheus 服务器,挂载配置文件
- 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_name、image、namespace 等,使得我们可以进行多维度的查询和分析。
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 正在从两个来源收集指标:
- cAdvisor:提供容器级别的系统指标(CPU、内存、网络等)
- 应用程序:提供应用程序级别的业务指标(请求计数、处理时间等)
高级监控场景
有了基础的监控设置后,让我们探索一些更高级的监控场景。
容器资源使用趋势分析
我们可以使用 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 数据源
- 访问 http://localhost:3000
- 登录(admin/admin)
- 点击左侧齿轮图标(Configuration)→ Data Sources
- 点击 “Add data source”
- 选择 “Prometheus”
- URL 设置为
http://prometheus:9090 - 点击 “Save & Test”
创建仪表板
点击左侧 “+” → “Dashboard” → “New dashboard”。
容器概览面板
添加以下面板:
-
容器 CPU 使用率:
- Query:
rate(container_cpu_usage_seconds_total{container_name!="",container_name!="POD"}[1m]) * 100 - Visualization: Time series
- Legend: {{container_name}}
- Query:
-
容器内存使用量:
- Query:
container_memory_usage_bytes{container_name!="",container_name!="POD"} - Visualization: Time series
- Unit: bytes
- Query:
-
容器网络流量:
- 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
- Query A:
应用程序指标面板
-
HTTP 请求率:
- Query:
sum(rate(http_server_requests_seconds_count{application="prometheus-demo-app"}[1m])) - Visualization: Time series
- Unit: reqps
- Query:
-
HTTP 错误率:
- Query:
sum(rate(http_server_requests_seconds_count{status=~"4..|5..", application="prometheus-demo-app"}[1m])) - Visualization: Time series
- Unit: reqps
- Query:
-
请求延迟:
- Query:
histogram_quantile(0.95, sum(rate(http_server_requests_seconds_bucket{application="prometheus-demo-app"}[1m])) by (le)) - Visualization: Time series
- Unit: s
- Query:
-
自定义业务指标:
- Query:
demo_requests_total{application="prometheus-demo-app"} - Visualization: Time series
- Unit: short
- Query:
仪表板变量
为了提高仪表板的交互性,我们可以添加变量:
- 点击仪表板设置 → Variables → New
- Name:
container - Label: Container
- Query:
label_values(container_name) - 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 实例的数据汇总到一个全局实例中。
远程存储
对于需要长期保留数据的场景,可以配置远程存储后端,如 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! 📊
🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)