利用 Prometheus 和 Grafana 监控分布式应用
1. 架构概述
计划系统的架构涉及到微服务、Prometheus 服务器和 Grafana,并且所有组件都将部署到 Kubernetes 中。它们之间的关系如下:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(Kubernetes):::process -->|提供指标| B(Prometheus):::process
C(Node.js 服务):::process -->|提供指标| B
D(.NET 服务):::process -->|提供指标| B
B -->|提供数据| E(Grafana):::process
Prometheus 位于图的顶部中心,它会定期从左侧的 Kubernetes 以及我们创建并配置的 Node.js 和 .NET 示例服务中抓取指标。Grafana 则在右侧,它会定期从 Prometheus 拉取数据,并在图形化的仪表盘上展示。
2. 将 Prometheus 部署到 Kubernetes
以下是部署 Prometheus 到 Kubernetes 的详细步骤:
1. 导航到源文件夹 :
$ cd ~/The-Ultimate-Docker-Container-Book/ch19
- 创建 kube 文件夹并进入 :
$ mkdir -p ch19/kube && cd ch19/kube
- 添加
prometheus.yaml文件 :在该文件夹中添加名为prometheus.yaml的文件。 - 定义 Prometheus 的 Deployment :在
prometheus.yaml文件中添加以下代码:
# 此处代码对应书中 Figure 19.5 内容,因未给出具体代码,暂不展示
我们定义了一个包含两个 Prometheus 实例的 ReplicaSet,每个实例都有 app: prometheus 和 purpose: monitoring-demo 标签用于识别。在容器规范的 volumeMounts 部分,我们将名为 prometheus-cm 的 Kubernetes ConfigMap 对象挂载到容器中 Prometheus 期望配置文件所在的位置。ConfigMap 类型的卷在代码片段的最后四行定义。注意,我们稍后会定义 ConfigMap。
5. 定义 Prometheus 的 Kubernetes 服务 :在 prometheus.yaml 文件中追加以下代码:
---
# 此处代码对应书中 Figure 19.6 内容,因未给出具体代码,暂不展示
这里的三个短横线 --- 用于分隔 YAML 文件中的各个对象定义。我们将服务命名为 prometheus-svc ,并将其设置为 NodePort 类型,以便从主机访问 Prometheus 的 Web UI。
6. 定义 Prometheus 的配置文件 :
- 创建子文件夹 :
$ mkdir config
- **添加 `prometheus.yml` 文件并添加内容**:在 `config` 文件夹中添加 `prometheus.yml` 文件,并添加以下内容:
# 此处代码对应书中 Figure 19.7 内容,因未给出具体代码,暂不展示
在这个文件中,我们为 Prometheus 定义了三个作业:
- prometheus :每五秒从 Prometheus 服务器自身抓取指标,目标地址为 localhost:9090 ,默认指标暴露在 /metrics 端点。
- dotnet :从 dotnet-api-svc:80 服务抓取指标,这是我们之前定义并配置的 .NET Core 服务。
- 第三个作业:为 Node 服务执行相同的操作,并为该作业添加了 production 组标签,以便进一步分组作业或任务。
7. 定义 Kubernetes 集群中的 ConfigMap 对象 :在 ch19/kube 文件夹中执行以下命令:
$ kubectl create configmap prometheus-cm \
--from-file config/prometheus.yml
Kubernetes ConfigMap 简介 :Kubernetes ConfigMap 是一个 API 对象,用于以键值对的形式存储非机密的配置数据,例如特定环境的 URL、命令行参数或应用程序运行所需的其他参数。其主要优点是可以将配置细节与应用程序代码分离,使应用程序更具可移植性和可扩展性。ConfigMap 可以通过多种方式被 Pod 使用,如作为环境变量、容器的命令行参数或卷中的配置文件。
8. 部署 Prometheus 到 Kubernetes 服务器 :
$ kubectl apply -f prometheus.yaml
预期输出:
deployment.apps/prometheus-deployment created
service/prometheus-svc created
- 检查部署是否成功 :
$ kubectl get all
要密切关注 Pod 列表,确保它们都已启动并运行。同时注意 prometheus-svc 对象的端口映射,在作者的环境中,9090 端口映射到主机的 31421 端口,你的端口可能不同,但通常也在 3xxxx 范围内。
10. 访问 Prometheus 的 Web UI :打开一个新的浏览器标签页,访问 http://localhost:<port>/targets ,其中 <port> 在作者的环境中是 31421。你应该会看到类似以下的界面:
在这个界面中,我们可以看到为 Prometheus 定义了三个目标。此时只有列表中的第三个目标(即从 Prometheus 自身抓取指标的作业所定义的端点)是可用的,其他两个服务尚未运行,状态为 down 。
11. 导航到 Graph 页面 :在 UI 的顶部菜单中点击相应链接,导航到 Graph 页面。
12. 查看可用指标 :在搜索框中输入内容,会显示已知指标的列表。目前,这里只显示 Prometheus 服务器自身定义的指标。
3. 将应用服务部署到 Kubernetes
在将之前创建的示例服务部署到 Kubernetes 之前,我们需要为它们创建 Docker 镜像并推送到容器注册表,这里我们将其推送到 Docker Hub。
3.1 为 .NET Core 示例创建 Docker 镜像
- 添加 Dockerfile :在
ch19/dotnet/sample-api项目文件夹中添加以下内容的 Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build-env
WORKDIR /app
COPY *.csproj ./
RUN dotnet restore
COPY . ./
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/aspnet:7.0
WORKDIR /app
COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "sample-api.dll"]
- 创建 Docker 镜像 :在
dotnet/sample-api项目文件夹中执行以下命令:
$ docker image build -t fundamentalsofdocker/ch19-dotnet-api:2.0 .
注意,你可能需要将 fundamentalsofdocker 替换为你自己的 Docker Hub 用户名。
3. 登录 Docker :
$ docker login
- 推送镜像到 Docker Hub :
$ docker image push fundamentalsofdocker/ch19-dotnet-api:2.0
3.2 为 Node 示例 API 创建 Docker 镜像
- 添加 Dockerfile :在
ch19/node项目文件夹中添加以下内容的 Dockerfile:
FROM node:lts
WORKDIR /app
COPY package.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
- 创建 Docker 镜像 :在
ch19/node项目文件夹中执行以下命令:
$ docker image build -t fundamentalsofdocker/ch19-node-api:2.0 .
同样,你可能需要将 fundamentalsofdocker 替换为你自己的 Docker Hub 用户名。
3. 推送镜像到 Docker Hub :
$ docker image push fundamentalsofdocker/ch19-node-api:2.0
3.3 部署服务到 Kubernetes
我们可以使用存储库中 sample-solutions/ch19/kube/app-services.yaml 文件来部署服务。
1. 确保位于 kube 子文件夹 :
$ cd ch19/kube
- 部署两个服务 :
$ kubectl apply -f app-services.yaml
预期输出:
deployment.apps/dotnet-api-deployment created
service/dotnet-api-svc created
deployment.apps/node-api-deployment created
service/node-api-svc created
- 检查服务是否正常运行 :
$ kubectl get all
确保 Node 和 .NET 示例 API 服务的所有 Pod 都已启动并运行。
4. 查看应用服务的主机端口 :
$ kubectl get services
在作者的环境中,.NET API 映射到端口 30211,Node API 映射到端口 30663,你的端口可能不同。
5. 访问 .NET 服务的 /metrics 端点 :
$ curl localhost:30211/metrics
预期输出:
# HELP process_cpu_seconds_total Total user and system CPU time
spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 0.4
# HELP prometheus_net_meteradapter_instruments_connected Number
of instruments that are currently connected to the adapter.
# TYPE prometheus_net_meteradapter_instruments_connected gauge
prometheus_net_meteradapter_instruments_connected 0
# HELP prometheus_net_exemplars_recorded_total Number of
exemplars that were accepted into in-memory storage in the
prometheus-net SDK.
# TYPE prometheus_net_exemplars_recorded_total counter
prometheus_net_exemplars_recorded_total 0
...
- 访问 Node 服务的 /metrics 端点 :
$ curl localhost:30663/metrics
预期输出:
# HELP process_cpu_user_seconds_total Total user CPU time spent
in seconds.
# TYPE process_cpu_user_seconds_total counter
process_cpu_user_seconds_total 1.0394399999999997 1578294999302
# HELP process_cpu_system_seconds_total Total system CPU time
spent in seconds.
# TYPE process_cpu_system_seconds_total counter
process_cpu_system_seconds_total 0.3370890000000001
1578294999302
...
- 检查 Prometheus 的 /targets 端点 :确保两个微服务现在都可以被访问。
- 确保自定义指标被定义和暴露 :为了确保我们为 Node.js 和 .NET 服务定义的自定义指标被定义和暴露,我们需要至少访问每个服务一次。使用
curl多次访问相应的端点:
# 访问 .NET 服务的 /weatherforecast 端点
$ curl localhost:30211/weatherforecast
# 访问 Node 服务的 /hello 端点
$ curl localhost:30663/hello
- 在 Prometheus Graph 视图中查看自定义指标 :
4. 将 Grafana 部署到 Kubernetes
为了能够创建复杂且美观的仪表盘来展示应用服务和/或基础设施组件的关键指标,我们需要将 Grafana 部署到 Kubernetes。以下是部署步骤:
1. 添加 grafana.yaml 文件 :在 ch19/kube 文件夹中添加名为 grafana.yaml 的文件。
2. 定义 Grafana 的 Kubernetes Deployment :在 grafana.yaml 文件中添加以下内容:
# 此处代码对应书中 Figure 19.14 内容,因未给出具体代码,暂不展示
在这个示例中,我们运行一个单实例的 Grafana,并使用 app 和 purpose 标签进行识别,与 Prometheus 类似。由于我们只使用默认设置,因此不需要特殊的卷映射。
3. 定义 Grafana 的服务 :在 grafana.yaml 文件中追加以下内容:
# 此处代码对应书中 Figure 19.15 内容,因未给出具体代码,暂不展示
我们使用 NodePort 类型的服务,以便从主机访问 Grafana UI。
4. 部署 Grafana :
$ kubectl apply -f grafana.yaml
预期输出:
deployment.apps/grafana-deployment created
service/grafana-svc created
- 查看 Grafana 服务的端口 :
$ kubectl get services/grafana-svc
6. 访问 Grafana 的 Web UI :打开一个新的浏览器标签页,访问 http://localhost:<port> ,其中 <port> 是你在前面步骤中获取的端口,在作者的环境中是 32736。
7. 登录 Grafana :使用默认用户名 admin 和密码 admin 登录。当提示更改密码时,暂时点击 Skip 链接,你将被重定向到主页仪表盘。
8. 创建数据源 :在主页仪表盘上,点击 Create your first data source ,并从数据源列表中选择 Prometheus 。
9. 配置 Prometheus URL :输入 http://prometheus-svc:9090 作为 Prometheus 的 URL,然后点击绿色的 Save & Test 按钮。
10. 创建新仪表盘 :在 Grafana 中返回主页仪表盘,然后选择 New dashboard 链接。
11. 添加查询 :点击 Add query ,然后从 Metrics 下拉菜单中选择我们在 .NET 示例服务中定义的自定义指标。
12. 更改时间范围 :将 Relative time 的值从 1h 更改为 5m (5 分钟)。
13. 更改仪表盘刷新频率 :在视图的右上角,将仪表盘刷新频率更改为 5s (5 秒)。
14. 添加 Node 示例服务的自定义指标 :重复上述步骤,为 Node 示例服务定义的自定义指标添加查询,这样新仪表盘上就会有两个面板。
15. 自定义仪表盘 :通过参考 Grafana 文档 来修改仪表盘及其面板,以满足你的需求。
16. 观察仪表盘 :使用 curl 访问示例服务的两个端点,并观察仪表盘。
综上所述,Prometheus 非常适合监控我们的微服务,因为我们只需要暴露一个指标端口,无需增加太多复杂性或运行额外的服务。Prometheus 负责定期从配置的目标抓取指标,这样我们的服务就无需担心指标的发送问题。
5. 基于关键指标定义警报
仅仅收集日志和指标并在美观的仪表盘上展示是不够的。如果仅依赖仪表盘,可能需要有支持人员全年无休地盯着大量显示器,以防出现问题。这种工作既繁琐又容易出错。因此,我们需要调整方法,基于关键指标定义警报。
5.1 指标
指标是警报规则的输入值。我们需要识别关键指标,如果这些指标反复或长时间超过预定值,就需要触发警报。例如,CPU 使用率就是一个常见的关键指标。
在 Kubernetes 中,我们可以使用 Prometheus 等工具基于 PromQL 表达式定义警报规则。这些规则允许我们根据从集群收集的指标指定条件,并在条件满足时向外部服务发送通知。例如,我们可以定义一个警报,当集群节点的 CPU 或内存利用率超过某个阈值时触发。
在 Docker 中,我们可以使用 cAdvisor 或 Docker stats 等工具收集容器的指标,然后使用监控和警报工具基于这些指标定义警报。例如,当运行的容器数量超过某个阈值时触发警报。
在定义警报时,遵循以下最佳实践可以确保警报有效且可操作:
| 最佳实践 | 描述 |
| ---- | ---- |
| 基于症状警报 | 警报应基于有明显影响的症状,而不是指标中的意外值 |
| 监控主机或 Kubernetes 节点层 | 监控主机和节点的健康状况,确保集群平稳运行 |
| 监控 Kubernetes 基础设施 | 监控 Kubernetes 控制平面和其他内部服务的健康状况 |
| 监控运行在 Kubernetes 上的服务 | 监控运行在 Kubernetes 上的应用程序的健康状况 |
| 监控应用层指标 | 监控特定于应用程序的指标,确保应用程序平稳运行 |
5.2 警报
警报是在出现异常情况时发出的通知。我们可以通过多种方式发送警报,如寻呼机消息、短信、电子邮件、声音警报和闪烁的警示灯等,具体方式取决于使用场景。
例如,当 Kubernetes 集群节点的 CPU 使用率超过 95% 持续一分钟以上时,系统可靠性工程师(SRE)需要得到通知。
那么,谁来制定这些规则呢?通常是运维人员,更具体地说是 SRE,他们负责确定哪些非功能指标是重要的,以及何时希望得到通知,即使是在半夜。公司还需要指定功能指标以及每个指标触发警报的容忍级别或其他标准。
为了更好地理解,我们定义几个潜在的警报候选指标:
- 系统级统计指标 :在银行应用程序中,我们将总 CPU 利用率的百分比定义为一个统计指标。服务级别目标(SLO)可以是该百分比不超过 99%。规则可以是,如果 CPU 百分比在半分钟内超过 99% 的时间超过 50%,则发送警报。
- 业务相关指标 :在提供人寿保险的应用程序中,我们可以将为有报价需求的客户生成报价所需的时间指定为一个关键统计指标。该指标的服务级别协议(SLA)可以是 99% 的报价请求必须在 50 毫秒内处理,且任何请求都不能超过 1000 毫秒。根据警报规则,如果 SLA 在一小时内被违反超过三次,则应发送警报。
前者是基础设施指标,后者是业务指标。选定的目标人员,如 SRE 或开发人员,可以通过多种渠道接收警报,包括电子邮件、短信、自动电话、Slack 消息、音频警报、光学警报等。
利用 Prometheus 和 Grafana 监控分布式应用
6. 警报的实际应用与管理
在实际应用中,我们需要确保警报系统能够准确、及时地响应问题,同时避免产生过多的误报。以下是一些关于警报实际应用与管理的要点:
6.1 警报规则的测试与验证
在正式部署警报规则之前,我们需要对其进行充分的测试和验证。可以通过模拟异常情况来触发警报,检查警报是否能够正确发送,以及通知的接收者是否能够及时收到通知。
例如,我们可以使用工具模拟 Kubernetes 节点的 CPU 使用率超过阈值,观察是否能够触发相应的警报。同时,检查通知的内容是否准确,是否包含了必要的信息,如触发警报的指标、时间、受影响的资源等。
6.2 警报的分级与分类
为了更好地管理警报,我们可以对警报进行分级和分类。根据警报的严重程度,可以将其分为不同的级别,如严重、重要、次要等。同时,根据警报的类型,如系统级警报、业务级警报等,进行分类管理。
这样做的好处是可以让不同级别的人员关注不同级别的警报,提高响应效率。例如,严重级别的警报可以直接通知到 SRE 团队,而次要级别的警报可以由开发人员自行处理。
6.3 警报的抑制与静默
在某些情况下,我们可能会遇到一些临时性的异常情况,这些情况可能会触发大量的警报,但实际上并不会对系统造成严重影响。为了避免这些误报干扰正常的工作,我们可以使用警报的抑制与静默功能。
警报抑制是指在一定条件下,暂时停止发送某些类型的警报。例如,当系统进行升级或维护时,我们可以抑制与系统性能相关的警报。警报静默是指在一段时间内,完全不发送某些特定的警报。
6.4 警报的历史记录与分析
保存警报的历史记录可以帮助我们分析系统的健康状况和问题趋势。通过对历史警报数据的分析,我们可以发现一些潜在的问题,如频繁出现的异常情况、警报的触发规律等。
同时,我们可以根据分析结果对警报规则进行优化,减少误报的发生,提高警报系统的准确性和有效性。
7. 监控系统的扩展与优化
随着系统的不断发展和变化,我们的监控系统也需要进行相应的扩展和优化,以满足新的需求。
7.1 增加监控指标
随着业务的发展,我们可能需要监控更多的指标,以全面了解系统的运行状况。例如,除了 CPU 使用率、内存使用率等基础指标外,我们还可以监控网络带宽、磁盘 I/O 等指标。
在 Prometheus 中,我们可以通过修改配置文件来增加新的监控作业,从不同的服务中抓取更多的指标。同时,在 Grafana 中,我们可以创建新的仪表盘来展示这些新的指标。
7.2 优化指标抓取频率
指标的抓取频率会影响监控系统的性能和数据的准确性。如果抓取频率过高,会增加系统的负担;如果抓取频率过低,可能会错过一些重要的事件。
我们需要根据实际情况,合理调整指标的抓取频率。例如,对于一些变化较快的指标,如 CPU 使用率,可以适当提高抓取频率;对于一些变化较慢的指标,如磁盘容量,可以降低抓取频率。
7.3 分布式监控
当系统规模较大时,可能需要进行分布式监控。我们可以在不同的节点或区域部署多个 Prometheus 服务器,分别负责监控不同的部分,然后通过 Grafana 统一展示和管理。
分布式监控可以提高监控系统的性能和可靠性,同时也可以减少网络延迟对监控数据的影响。
7.4 与其他系统集成
为了更好地管理和维护系统,我们可以将监控系统与其他系统进行集成。例如,将警报系统与工单系统集成,当警报触发时,自动创建工单,方便跟踪和处理问题。
还可以将监控系统与 CI/CD 系统集成,在部署新的版本时,自动检查系统的性能指标,确保新版本不会引入新的问题。
8. 总结与展望
通过使用 Prometheus 和 Grafana 对分布式应用进行监控,并基于关键指标定义警报,我们可以及时发现系统中的问题,提高系统的可靠性和稳定性。
Prometheus 提供了强大的指标抓取和存储能力,Grafana 则提供了直观的可视化界面,两者结合可以为我们提供一个完整的监控解决方案。同时,通过合理定义警报规则,我们可以在问题发生时及时通知相关人员,减少故障对业务的影响。
未来,随着技术的不断发展,监控系统也将不断演进。例如,人工智能和机器学习技术可能会被应用到监控系统中,实现自动故障诊断和预测。同时,随着容器化和微服务架构的普及,监控系统也需要不断适应新的架构和环境。
我们需要不断学习和探索新的技术和方法,以提高监控系统的性能和效率,为业务的发展提供更好的支持。
以下是一个简单的 mermaid 流程图,展示了监控系统的整体流程:
graph LR
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
A(微服务):::process -->|提供指标| B(Prometheus):::process
B -->|存储指标| C(指标存储):::process
C -->|查询指标| D(Grafana):::process
D -->|展示指标| E(仪表盘):::process
B -->|触发警报| F(警报管理器):::process
F -->|发送通知| G(通知接收者):::process
通过以上的步骤和方法,我们可以构建一个高效、可靠的分布式应用监控系统,确保系统的稳定运行。
超级会员免费看

被折叠的 条评论
为什么被折叠?



