应用容器的调试与监控
1. 应用监控指标
在应用中,自定义计数器可以显示 URL 和响应代码。例如,能看到对值控制器根 URL 的十次请求,以及十个状态码为 200 的响应。后续可以使用 Prometheus 对这些统计数据进行可视化展示。
要记录有用的指标,可以向项目添加 NuGet 包并运行 MetricServer,不过这意味着需要修改应用代码。而在某些情况下,可能希望在不更改应用代码的前提下添加监控,这时可以在应用旁边运行一个导出器。导出器会从应用进程中提取指标,并将其暴露给 Prometheus。
2. 为现有应用添加 Prometheus 导出器
在 Docker 化的解决方案中,Prometheus 会按计划调用容器暴露的指标端点,并存储结果。对于现有应用,无需添加指标端点,可以在当前应用旁边运行一个控制台应用,并在该控制台应用中托管指标。
例如,在之前设置的 Bonobo Git 服务器中添加了 Prometheus 端点,而无需更改 Bonobo 的任何代码。在
dockeronwindows/ch11-bonobo-with-metrics
镜像中,有一个控制台应用提供指标端点,它使用与前面示例相同的 NuGet 包和
MetricsServer
类。该控制台应用会监视托管 Bonobo 的
w3wp
进程,从而在不更改 Bonobo 应用的情况下暴露其指标。
DotNetExporter
控制台应用实现了一个自定义计数器收集器,它可以读取系统上指定进程的性能计数器值。它使用与 NuGet 包中默认收集器相同的一组计数器,但通过针对不同的进程,可以监控同一容器中运行的其他进程。
在
Program
类中,使用环境变量配置应用,并为每个配置的进程启动计数器收集器:
var collectors = new List<IOnDemandCollector>();
foreach (var process in Config.MetricsTargets)
{
WriteLine($"Adding collectors for process: {process}");
collectors.Add(new ProcessPerfCounterCollector(process));
}
然后创建并启动
MetricServer
对象,使用配置的收集器并监听配置的指标端点:
var server = new MetricServer(Config.MetricsPort, collectors);
server.Start();
WriteLine($"Metrics server listening on port: {Config.MetricsPort}");
控制台应用是一个轻量级组件,它会无限期运行,并且仅在调用指标端点时使用计算资源,因此在按 Prometheus 计划运行时影响极小。
为了为 Bonobo 提供指标,需要创建一个 Dockerfile,将导出器应用与 Bonobo 打包在一起。以下是 Dockerfile 的示例:
FROM dockeronwindows/ch10-bonobo
EXPOSE 50505
ENV METRICS_TARGETS="w3wp"
WORKDIR C:\prometheus-exporter
COPY --from=builder C:\out\dotnet-exporter .
COPY bootstrap.ps1 /
ENTRYPOINT ["powershell", "C:\\bootstrap.ps1"]
在
bootstrap.ps1
脚本中,启动 IIS Windows 服务并进行 HTTP 调用,以启动
w3wp
工作进程来处理请求:
Start-Service W3SVC
Invoke-WebRequest http://localhost/Bonobo.Git.Server -UseBasicParsing | Out-Null
& C:\prometheus-exporter\DotNetExporter.Console.exe
构建此镜像并运行容器后,可以正常使用 Bonobo,同时额外的导出器进程会运行并提供对指标的访问。可以使用 PowerShell 启动容器并打开浏览器:
docker container run -d -P --name bonobo dockeronwindows/ch11-bonobo-with-metrics
$ip = docker inspect -f '{{.NetworkSettings.Networks.nat.IPAddress}}' bonobo
start "http://$($ip)/Bonobo.Git.Server"
可以在浏览器中使用 Bonobo,导出器会暴露 Bonobo 工作进程的指标。使用相同的指标端点,可以在端口 50505 上查看统计信息:
> (iwr -useb "http://$($ip):50505/metrics").Content
# HELP process_pct_processor_time % Processor Time Perf Counter
# TYPE process_pct_processor_time GAUGE
process_pct_processor_time{process="w3wp"} 6.06265497207642
# HELP process_working_set Working Set Perf Counter
# TYPE process_working_set GAUGE
process_working_set{process="w3wp"} 329969664
...
在这种情况下,应用没有自定义计数器,所有指标都来自标准的 Windows 和 .NET 性能计数器。导出器应用可以读取运行中的
w3wp
进程的这些性能计数器值,因此应用无需更改即可向 Prometheus 提供基本信息。要记录自定义指标,则需要对代码进行插桩并显式记录感兴趣的数据点。
3. 在 Windows Docker 容器中运行 Prometheus 服务器
Prometheus 是一个用 Go 编写的跨平台应用程序,可以在 Nano Server 上运行。Prometheus 的安装程序是一个 GZipped Tar 文件,在 Windows 中无法直接提取。为了在 Docker 中打包 Prometheus,使用多阶段构建,在第一阶段下载并提取包。
在 Windows 中提取 GZipped TAR 文件的最佳工具是 7-Zip,有一个安装了 7-Zip 的 Docker 镜像
dockeronwindows/ch11-7zip
。
dockeronwindows/ch11-prometheus
镜像的 Dockerfile 从这个镜像开始,然后运行 PowerShell cmdlet 下载包并提取它:
RUN Invoke-WebRequest "https://github.com/prometheus/prometheus/releases/download/v$($env:PROMETHEUS_VERSION)/prometheus-$($env:PROMETHEUS_VERSION).windows-amd64.tar.gz" `
-OutFile 'prometheus.tar.gz' -UseBasicParsing; `
& 'C:\Program Files\7-Zip\7z.exe' x prometheus.tar.gz; `
& 'C:\Program Files\7-Zip\7z.exe' x prometheus.tar; `
Rename-Item -Path "C:\prometheus-$($env:PROMETHEUS_VERSION).windows-amd64" -NewName 'C:\prometheus'
Dockerfile 的第二(也是最后)阶段从 Nano Server 开始,并从安装阶段复制提取的文件。这些文件被复制到特定位置,以便容器用户可以通过卷挂载覆盖内容,以使用不同的配置运行 Prometheus:
FROM microsoft/nanoserver:10.0.14393.1198
COPY --from=installer /prometheus/prometheus.exe /bin/prometheus.exe
COPY --from=installer /prometheus/promtool.exe /bin/promtool.exe
COPY --from=installer /prometheus/prometheus.yml /etc/prometheus/prometheus.yml
COPY --from=installer /prometheus/console_libraries/ /etc/prometheus/
COPY --from=installer /prometheus/consoles/ /etc/prometheus/
Prometheus 有很多可以配置的地方,但通常只需指定 JSON 配置文件即可开始使用。Dockerfile 有一个
ENTRYPOINT
,其中包含所有设置的默认值,以及一个
CMD
,允许用户覆盖配置文件的位置:
ENTRYPOINT ["C:\\bin\\prometheus.exe", `
"-storage.local.path=/prometheus", `
"-web.console.libraries=/etc/prometheus/console_libraries", `
"-web.console.templates=/etc/prometheus/consoles" ]
CMD ["-config.file=/etc/prometheus/prometheus.yml"]
有运行中的容器,它们从插桩的 API 和 Bonobo Git 服务器镜像中暴露了供 Prometheus 使用的指标端点。为了在 Prometheus 中监控它们,需要在配置文件中指定指标位置。Prometheus 会按可配置的计划轮询这些端点,这称为刮擦(scraping),可以在刮擦配置中添加容器名称和端口:
scrape_configs:
- job_name: 'Api'
static_configs:
- targets: ['api:50505']
- job_name: 'Bonobo'
static_configs:
- targets: ['bonobo:50505']
每个要监控的应用都被指定为一个作业,每个端点都被列为一个目标。Prometheus 将在同一 Docker 网络上的容器中运行,因此可以通过容器名称引用目标。现在可以在容器中启动 Prometheus 服务器,挂载本地文件夹以存储配置文件和数据卷,并在命令中指定配置文件的位置:
docker container run -d -P `
--name prometheus `
-v "C:\prometheus\data:C:\prometheus" `
-v "C:\prometheus:C:\config" `
dockeronwindows/ch11-prometheus '-config.file=/config/prometheus.yml'
Prometheus 会轮询所有配置的指标端点并存储数据。可以将 Prometheus 用作丰富 UI 组件(如 Grafana)的后端,将所有运行时关键绩效指标(KPI)构建到单个仪表板中。对于基本监控,Prometheus 服务器也提供了一个简单的 Web UI。
可以访问 Prometheus 服务器的 IP 地址和端口 9090,设置一个图形视图,显示 Web API 的响应,每个请求 URL 和响应状态代码都会有一条不同的线。这些计数器在容器的生命周期内会不断增加,因此图形会一直上升。Prometheus 有丰富的函数,可以绘制随时间的变化率、聚合指标以及选择数据投影。
从 Prometheus NuGet 包中获取的其他计数器是快照,如性能计数器统计信息。可以通过查看工作集来比较 Bonobo 实例和 API 的内存使用情况。使用堆叠图可以看出 Bonobo 使用的内存更多,但会有一个急剧下降,这可能是在 .NET 垃圾回收器运行之后。
以下是添加 Prometheus 导出器和运行 Prometheus 服务器的步骤总结:
|步骤|操作|
|----|----|
|1|为现有应用添加 Prometheus 导出器,创建控制台应用并配置收集器|
|2|创建 Dockerfile 打包导出器应用与现有应用|
|3|构建并运行包含导出器的容器|
|4|使用多阶段构建在 Docker 中打包 Prometheus|
|5|配置 Prometheus 刮擦目标|
|6|启动 Prometheus 服务器容器并挂载配置文件和数据卷|
整个流程可以用以下 mermaid 流程图表示:
graph LR
A[现有应用] --> B[添加 Prometheus 导出器]
B --> C[创建 Dockerfile 打包]
C --> D[构建并运行容器]
E[准备 Prometheus 安装包] --> F[多阶段构建打包 Prometheus]
F --> G[配置刮擦目标]
G --> H[启动 Prometheus 服务器容器]
D --> I[暴露指标端点]
I --> H
应用容器的调试与监控
4. 容器监控的优势与价值
在 Docker 平台中,像 Prometheus 这样的工具展示了其开放性所带来的优势。Prometheus 作为轻量级服务器,非常适合在容器中运行。为应用添加对 Prometheus 的支持,既可以通过在应用中添加指标端点,也可以在现有应用旁边运行指标导出器。
通过这种方式,可以轻松地为所有应用添加插桩,深入了解解决方案的运行情况。而且,在每个环境(开发、测试、生产)中都能拥有相同的监控设施,这在从其他环境复制错误进行调试时非常有用。例如,在开发和测试阶段看到的指标与生产环境一致,有助于快速定位和解决问题。
5. Docker 中的 bug 修复工作流
在修复生产缺陷时,最大的困难之一是在开发环境中复现问题。这不仅是确认是否存在 bug 的第一步,也是深入查找问题的起点,而且往往是最耗时的部分。
5.1 Bug 修复前的困境
大型 .NET 项目通常发布频率较低,因为发布过程复杂,需要大量手动测试来验证新功能和检查回归问题。一年可能只有三到四次发布,开发人员可能需要在发布过程的不同阶段支持应用的多个版本。
例如,可能在生产环境中运行版本 1.0,在用户验收测试(UAT)中运行版本 1.1,在系统测试中运行版本 1.2。而开发团队可能正在开发版本 1.3 甚至 2.0 的重大升级,此时可能会在任何版本中发现 bug,需要进行跟踪和修复。
在没有 Docker 的情况下,修复 bug 的过程非常繁琐。例如,从正在开发的 2.0 代码库切换到 1.1 代码库进行 bug 修复时,不仅上下文切换成本高,而且在开发环境中重现 1.1 的 UAT 环境更是困难重重。
具体的工作流程及问题如下:
-
编译源代码
:在本地使用 Visual Studio 编译应用,但发布版本使用 MSBuild 脚本,该脚本会执行许多额外操作。
-
运行应用
:本地使用 Windows 10 上的 IIS Express,而发布版本使用 MSI 部署到 Windows Server 2012 上的 IIS 8。
-
数据库配置
:本地 SQL Server 数据库是为 2.0 架构设置的,而发布版本有从 1.0 到 1.1 的升级脚本,但没有从 2.0 到 1.1 的降级脚本,需要手动修复本地架构。
-
依赖处理
:本地对无法运行的依赖项使用存根,而发布版本使用真实的应用组件。
即使能够获取到 1.1 版本的准确源代码,开发环境与 UAT 环境也存在巨大差异。为了减少时间,可能会采取一些捷径,但这会使本地环境与目标环境的差异更大。在这种情况下,如果 bug 是由数据问题或环境问题引起的,可能无法复现,并且可能需要花费一整天的时间才能发现这一点。如果怀疑问题与 UAT 的设置有关,也无法在本地环境中验证,需要与运维团队一起查看 UAT 配置。
如果能够复现问题,编写一个失败的测试来重现问题,当更改代码并使测试通过时,由于本地环境与 UAT 环境存在差异,也不能确定修复是否能在 UAT 环境中生效,需要等到下一次发布才能验证。而且,如果工具链在 1.1 和 2.0 之间有更新,会使配置本地环境、运行应用、分析问题和推送修复的每一步都变得更加困难。
5.2 使用 Docker 进行 Bug 修复
使用 Docker 可以大大简化 bug 修复过程。要在本地复现 UAT 环境,只需从与 UAT 中运行的相同镜像启动容器。由于有 Docker compose 或 stack 文件描述整个解决方案,并且该文件是版本化的,因此部署版本 1.1 可以获得与 UAT 完全相同的环境,而无需从源代码构建。
在这个阶段,应该能够复现问题,并确认是编码问题、数据问题还是环境问题。如果是配置问题,应该会看到与 UAT 相同的问题,可以使用更新后的 compose 文件测试修复。如果是编码问题,则需要深入研究代码。
此时,可以从版本 1.1 标签克隆源代码,并以调试模式构建 Docker 镜像。但在确定问题出在应用之前,无需花费时间进行此操作。如果在 Dockerfile 中使用多阶段构建并固定所有版本,本地构建将生成与 UAT 中运行的镜像相同的镜像,但会包含用于调试的额外工件。
接下来,可以找到问题、编写测试并修复 bug。当新的集成测试通过时,由于测试是针对即将部署到 UAT 的相同 Docker 化解决方案执行的,因此可以非常确定 bug 已修复。
如果 1.1 分支没有配置持续集成(CI),设置起来应该很简单,因为构建任务只需运行
docker image build
或
docker-compose build
命令。如果需要快速反馈,甚至可以将本地构建的镜像推送到注册表,并更新 UAT 环境以验证修复,同时进行 CI 设置。
使用 Docker 的工作流更加简洁、快速,而且风险要小得多。在本地复现问题时,使用的是与 UAT 环境完全相同的应用组件和平台。测试修复时,知道修复将在 UAT 中生效,因为将部署相同的新工件。在应用 Docker 化上投入的时间将通过支持应用多个版本时节省的时间得到回报。
以下是使用 Docker 进行 bug 修复的步骤总结:
|步骤|操作|
|----|----|
|1|从与 UAT 相同的镜像启动容器,复现问题|
|2|确认问题类型(编码、数据、环境)|
|3|如果是编码问题,克隆源代码并以调试模式构建 Docker 镜像|
|4|找到问题,编写测试并修复 bug|
|5|运行集成测试验证修复|
|6|如果需要,设置 CI 并推送修复|
整个 bug 修复流程可以用以下 mermaid 流程图表示:
graph LR
A[生产环境发现 bug] --> B[使用 Docker 复现 UAT 环境]
B --> C{确认问题类型}
C -->|编码问题| D[克隆代码并调试构建镜像]
C -->|数据或环境问题| E[使用更新的 compose 文件测试]
D --> F[找到问题并修复]
E --> F
F --> G[运行集成测试]
G -->|通过| H[设置 CI 并推送修复]
G -->|未通过| D
综上所述,在应用容器的调试与监控中,使用 Prometheus 等工具可以有效监控应用指标,而 Docker 则为 bug 修复提供了更高效、更可靠的解决方案。通过合理运用这些技术,可以提升应用的稳定性和开发效率。
超级会员免费看
17万+

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



