使用dotnet-monitor sidecar模式 dump docker運行的dotnet程序.

前情概要隨著容器和云技術的發展, 大量的應用運行在云上的容器中, 它們的好處是毋庸置疑的, 例如極大的提高了我們的研發部署速度, 快速的擴縮容等等, 但是也存在一些小小的問題, 例如難以調試.基于VM的部署我們可以通過安全的方式登錄到主機上做一些你想做的事情, 但是云上的容器那就是不太方便了(目前AWS的ECS已經有類似docker exec的方式直接進入容器中了, 其他的云未作了解).但是就算能進入容器也不意味著調試就好做了, 通常來說使用的鏡像都是經過優化和精簡的(如果要調式可能需要安裝大量的組件).
所以, 接下來介紹一下使用dotnet-monitor 來內存轉儲(memory dump)運行在容器中的 dotnet 程序.
需要提前知曉的一些知識點什么是 dotnet-monitor?Announcing dotnet monitor in .NET 6 官方博客的原文:
Running a .NET application in diverse environments can make collecting diagnostics artifacts (e.g., logs, traces, process dumps) challenging. dotnet monitor is a tool that provides an unified way to collect these diagnostic artifacts regardless of whether running you’re running on your desktop machine or in a kubernetes cluster.There are two different mechanisms for collection of these diagnostic artifacts:An HTTP API for on demand collection of artifacts. You can call these API endpoints when you already know your application is experiencing an issue and you are interested in gathering more information.Triggers for rule-based configuration for always-on collection of artifacts. You may configure rules to collect diagnostic artifacts when a desired condition is met, for example, collect a process dump when you have sustained high CPU.google翻譯:
在不同的環境中運行 .NET 應用程序會使收集診斷工件(例如,日志、跟蹤、進程轉儲)具有挑戰性 。dotnet monitor是一個工具 , 它提供了一種統一的方式來收集這些診斷工件,無論您是在臺式機上運行還是在 kubernetes 集群中運行 。
收集這些診斷工件有兩種不同的機制:
用于按需收集工件的HTTP API。當您已經知道您的應用程序遇到問題并且您有興趣收集更多信息時,您可以調用這些 API 端點 ?;谝巹t的配置觸發器,用于始終在線收集工件 。您可以配置規則以在滿足所需條件時收集診斷工件,例如,當您持續使用高 CPU 時收集進程轉儲 。
dotnet-monitor工作在什么位置?借用官方博客中的一張圖說明一下dotnet-monitor工作在什么地方

使用dotnet-monitor sidecar模式 dump docker運行的dotnet程序.

文章插圖
dotnet-monitor是如何能對我們的目標程序進行操作的?dotnet-monitor 可以連接到dotnet運行時公開的一個診斷端口(diagnostic port)(3.0新提供的新功能), 并通過自定義協議(ipc protocol)與運行時交互,
使用dotnet-monitor sidecar模式 dump docker運行的dotnet程序.

文章插圖
更多調試知識和工具例如ETW, eventpipe, lldb, dotnet-trace, dotent-counters 等可以查看 dotnet diagnostics.
目標應用程序容器準備首先, 我們得讓我們被調試的目標程序公開這個診斷端口, 因為默認情況下這個診斷端口只能由運行這個程序的用戶或者root用戶來訪問, 顯然sidecar 模式啟動的dotnet-monitor是不可能和目標程序用的是同一個用戶的.
未作特別聲明的話, 后文給出的實驗都是基于AWS FargateLinux 配置.
#添加環境變量DOTNET_DiagnosticPorts=/my_diagnostic_volume/diag.sock,suspend,connect/my_diagnostic_volume/diag.sockUnix Domain Socket 文件路徑, my_diagnostic_volume 是掛載的一個volume.suspend 意思是讓運行時等待dotnet-monitor 連接進來之后在執行托管代碼.connect 接受dotnet-monitor連接, 詳細解釋看這里diagnostic ports上述配置的完整語法結構是 address[,(listen|connect)][,(suspend|nosuspend)]詳情請查看文檔configure additional diagnostic ports
如果我們的需要dump內存文件, 可能會遇到WriteDumpAsync failed - HRESULT: 0x00000000 issues 1783這樣的錯誤, 是因為權限問題.比如我在AWS Fargate中遇到的就是 /dump API 返回400錯誤 Write dump failed - HRESULT: 0x00000000, 目標程序輸出日志 ptrace(ATTACH, 1) FAILED Operation not permitted.解決這個需要吧SYS_PTRACE權限給到目標程序. AWS Fargate 是編輯任務定義的json文件增加這一部分, docker 啟動是通過增加--cap-add=SYS_PTRACE 參數.
{"linuxParameters": {"capabilities": {"add": ["SYS_PTRACE"]}}}最后, 配置目標程序容器依賴dotnet-monitor容器, 這樣可以先讓dotnet-monitor容器啟動后, 在啟動目標程序容器.到此, 目標程序容器的配置就完成了, 接下來配置dotnet-monitor

推薦閱讀