使用 dotnet-monitor 在 Kubernetes 中收集 .NET metrics
使用 dotnet-monitor 在 Kubernetes 中收集 .NET metrics
Intro
dotnet-monitor 是微軟推出的一個幫助我們診斷和監控 .NET 應用程序的工具,在 Kubernetes 中我們可以讓 dotnet-monitor 作為 sidecar 運行,無侵入地監控 .NET 應用,今天我們就來介紹一下如果在 Kubernetes 中使用吧
GetStarted
作為 sidecar 運行的時候,我們只需要修改應用的 deployment 對應的 yaml 文件即可,下面是一個示例:
apiVersion:?apps/v1 kind:?Deployment metadata:name:?sparktodo-apilabels:app:?sparktodo-api spec:replicas:?1revisionHistoryLimit:?0selector:matchLabels:app:?sparktodo-apiminReadySeconds:?0strategy:type:?RollingUpdaterollingUpdate:maxUnavailable:?1maxSurge:?1template:metadata:annotations:prometheus.io/scrape:?"true"prometheus.io/port:?"52323"labels:app:?sparktodo-apispec:containers:-?name:?sparktodo-apiimage:?weihanli/sparktodo-api:latestimagePullPolicy:?Alwaysresources:requests:memory:?"64Mi"cpu:?"20m"limits:memory:?"128Mi"cpu:?"50m"env:-?name:?DOTNET_DiagnosticPortsvalue:?/diag/portports:-?name:?httpcontainerPort:?80protocol:?TCPlivenessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30readinessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30volumeMounts:-?mountPath:?/diagname:?diagvol-?mountPath:?/dumpsname:?dumpsvol-?name:?monitorimage:?mcr.microsoft.com/dotnet/monitorargs:?[?"--no-auth"?]imagePullPolicy:?Alwaysports:-?containerPort:?52323env:-?name:?DOTNETMONITOR_DiagnosticPort__ConnectionModevalue:?Listen-?name:?DOTNETMONITOR_DiagnosticPort__EndpointNamevalue:?/diag/port-?name:?DOTNETMONITOR_Storage__DumpTempFoldervalue:?/dumps-?name:?DOTNETMONITOR_Urlsvalue:?"http://+:52323"volumeMounts:-?mountPath:?/diagname:?diagvol-?mountPath:?/dumpsname:?dumpsvolresources:requests:cpu:?20mmemory:?32Milimits:cpu:?50mmemory:?256Mivolumes:-?name:?diagvolemptyDir:?{}-?name:?dumpsvolemptyDir:?{}為了方便對比,下面是一個變更對比
template:metadata: +??????annotations: +????????prometheus.io/scrape:?"true" +????????prometheus.io/port:?"52323"labels:app:?sparktodo-apispec:containers:-?name:?sparktodo-apiimage:?weihanli/sparktodo-api:latestimagePullPolicy:?Alwaysresources:requests:memory:?"64Mi"cpu:?"20m"limits:memory:?"128Mi"cpu:?"50m" +??????????env: +??????????-?name:?DOTNET_DiagnosticPorts +????????????value:?/diag/portports:-?name:?httpcontainerPort:?80protocol:?TCPlivenessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30readinessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30 +??????????volumeMounts: +??????????-?mountPath:?/diag +????????????name:?diagvol +??????????-?mountPath:?/dumps +????????????name:?dumpsvol +????????-?name:?monitor +??????????image:?mcr.microsoft.com/dotnet/monitor +??????????args:?[?"--no-auth"?] +??????????imagePullPolicy:?Always +??????????ports: +????????????-?containerPort:?52323 +??????????env: +??????????-?name:?DOTNETMONITOR_DiagnosticPort__ConnectionMode +????????????value:?Listen +??????????-?name:?DOTNETMONITOR_DiagnosticPort__EndpointName +????????????value:?/diag/port +??????????-?name:?DOTNETMONITOR_Storage__DumpTempFolder +????????????value:?/dumps +??????????-?name:?DOTNETMONITOR_Urls +????????????value:?"http://+:52323" +??????????volumeMounts: +??????????-?mountPath:?/diag +????????????name:?diagvol +??????????-?mountPath:?/dumps +????????????name:?dumpsvol +??????????resources: +????????????requests: +??????????????cpu:?20m +??????????????memory:?32Mi +????????????limits: +??????????????cpu:?50m +??????????????memory:?256Mi +??????volumes: +??????-?name:?diagvol +????????emptyDir:?{} +??????-?name:?dumpsvol +????????emptyDir:?{}與沒有使用 dotnet-monitor 之前相比,主要的變化有這幾個方面:
增加了一個 dotnet-monitor 的容器
增加了 volume 和 DiagnosticPorts 配置以支持 .NET 應用和 dotnet-monitor 的通信
增加了 Prometheus 的配置以讓 Prometheus 從 dotnet-monitor 拉取 metrics
實際效果:
metrics 示例:
dotnet-monitor 默認會收集很多信息,包括了 CPU、內存、GC、線程池等等信息,可以幫助我們更好的了解 .NET 應用的運行狀況,通過 Prometheus 收集到數據之后,我們可以進一步通過 Grafana 來做更好的 UI 展示以及可以根據指定的指標來做監控報警(做了幾個小示例,數據僅供參考)
Sample 2
默認地,dotnet-monitor 會監控三個來源的數據,可以認為就是 dotnet-counters 中的三個 Provider,
分別是 System.Runtime/Microsoft.AspNetCore.Hosting/Grpc.AspNetCore.Server
我們也可以自定義 dotnet-monitor 的配置來禁用默認的 provider 或者添加更多新的 provider,我們可以提供兩種類型的配置,一種是環境變量形式的配置,配置分隔符使用 __ 來表示,比如
Metrics__IncludeDefaultProviders: true也可以使用 Json 文件配置(推薦):
{"Metrics":?{"IncludeDefaultProviders":?true} }更加推薦使用 JSON 方式,因為更加直觀,而且更便于維護
這兩種方式配置方式配置文件的路徑是不一樣的,對于第一種配置配置文件放在 /etc/dotnet-monitor 中,而對于 Json 方式的配置則可以更加靈活的自定義,可以使用 XDG_CONFIG_HOME 來定義配置根目錄,如果配置為 /etc 則配置文件對應的路徑則是 /etc/dotnet-monitor/settings.json,下面是一個使用自定義配置的示例,無論哪種方式配置都可以通過 ConfigMap 來定義,掛載到容器的指定路徑
apiVersion:?apps/v1 kind:?Deployment metadata:name:?reservation-servernamespace:?defaultlabels:app:?reservation-server spec:replicas:?1revisionHistoryLimit:?2selector:matchLabels:app:?reservation-serverminReadySeconds:?0strategy:type:?RollingUpdaterollingUpdate:maxUnavailable:?1maxSurge:?1template:metadata:labels:app:?reservation-serverspec:containers:????????-?name:?reservation-serverimage:?openreservation/reservation-server:latestimagePullPolicy:?Alwaysresources:requests:cpu:?30mmemory:?32Milimits:cpu:?80mmemory:?256MireadinessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30livenessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30ports:-?containerPort:?80env:-?name:?DOTNET_DiagnosticPortsvalue:?/diag/portvolumeMounts:-?name:?settingsmountPath:?/app/appsettings.Production.jsonsubPath:?appsettings-?mountPath:?/diagname:?diagvol-?mountPath:?/dumpsname:?dumpsvol-?mountPath:?/tmpname:?tmpvol-?name:?dotnet-monitorimage:?mcr.microsoft.com/dotnet/monitorargs:?[?"--no-auth"?]imagePullPolicy:?Alwaysports:-?containerPort:?52323env:-?name:?DOTNETMONITOR_DiagnosticPort__ConnectionModevalue:?Listen-?name:?DOTNETMONITOR_DiagnosticPort__EndpointNamevalue:?/diag/port-?name:?DOTNETMONITOR_Storage__DumpTempFoldervalue:?/dumps-?name:?DOTNETMONITOR_Urlsvalue:?"http://+:52323"-?name:?XDG_CONFIG_HOMEvalue:?"/etc"volumeMounts:-?mountPath:?/diagname:?diagvol-?mountPath:?/dumpsname:?dumpsvol-?mountPath:?/tmpname:?tmpvol-?name:?monitor-configsmountPath:?/etc/dotnet-monitor/settings.jsonsubPath:?defaultresources:requests:cpu:?30mmemory:?32Milimits:cpu:?50mmemory:?256Mivolumes:-?name:?settingsconfigMap:name:?reservation-configs-?name:?monitor-configsconfigMap:name:?dotnet-monitor-configs-?name:?diagvolemptyDir:?{}-?name:?dumpsvolemptyDir:?{}-?name:?tmpvolemptyDir:?{}對于 dotnet-monitor 的配置可以放在一個 ConfigMap 中,通過掛載的方式掛載到 dotnet-monitor 容器中,dotnet-monitor 配置 ConfigMap 示例如下:
apiVersion:?v1 kind:?ConfigMap metadata:name:?dotnet-monitor-configsnamespace:?default data:default:?|{"urls":?"http://*:52323","Metrics":?{"IncludeDefaultProviders":?true,"Providers":?[{"ProviderName":?"System.Net.Http"},{"ProviderName":?"Microsoft.EntityFrameworkCore"},{"ProviderName":?"Microsoft.Data.SqlClient.EventSource"}]}}這里另外配置了 Metrics 來源
System.Net.Http 提供 HttpClient 相關的 EventCounters 數據
Microsoft.EntityFrameworkCore 提供 EF Core 相關的 EventCounters 數據
如果我們自己應用程序中有自己封裝的一些 Event counters 數據也是可以收集的
Connection Mode
細心的小伙伴們可能會發現我們前面示例中在?dotnet-monitor 容器中都配置了一個環境變量?DOTNETMONITOR_DiagnosticPort__ConnectionMode?為 Listen,
上面兩個示例中都是使用 Listen 模式,但是 Listen 模式是 .NET 5 之后才支持的,對于 .NET Core 3.x 的應用應該使用 Connect 模式(踩了坑的==
下面是一個 Connect 模式的 deployment 示例,也是第一個示例改成的 Connect 模式
apiVersion:?apps/v1 kind:?Deployment metadata:name:?sparktodo-apilabels:app:?sparktodo-api spec:replicas:?1revisionHistoryLimit:?0selector:matchLabels:app:?sparktodo-apiminReadySeconds:?0strategy:type:?RollingUpdaterollingUpdate:maxUnavailable:?1maxSurge:?1template:metadata:annotations:prometheus.io/scrape:?"true"prometheus.io/port:?"52323"labels:app:?sparktodo-apispec:containers:-?name:?sparktodo-apiimage:?weihanli/sparktodo-api:latestimagePullPolicy:?Alwaysresources:requests:memory:?"64Mi"cpu:?"20m"limits:memory:?"128Mi"cpu:?"50m"ports:-?name:?httpcontainerPort:?80protocol:?TCPlivenessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30readinessProbe:httpGet:path:?/healthport:?80initialDelaySeconds:?60periodSeconds:?30volumeMounts:-?mountPath:?/tmpname:?tmpvol-?name:?monitorimage:?mcr.microsoft.com/dotnet/monitorargs:?[?"--no-auth"?]imagePullPolicy:?Alwaysports:-?containerPort:?52323env:-?name:?DOTNETMONITOR_DiagnosticPort__ConnectionModevalue:?Connect-?name:?DOTNETMONITOR_Urlsvalue:?"http://+:52323"volumeMounts:-?mountPath:?/tmpname:?tmpvolresources:requests:cpu:?20mmemory:?32Milimits:cpu:?50mmemory:?256Mivolumes:-?name:?tmpvolemptyDir:?{}和 Listen 模式相比,Connect 模式更為簡單一些,應用程序只需要和 dotnet-monitor 容器掛載同一個 tmp 目錄即可,但是 Listen 模式功能更為強大,Listen 模式可以支持同時監聽多個 .NET 容器,Connect 模式不支持,而且有一些高級的用法 CollectionRule 的配置僅僅支持 Listen 模式,可以參考:https://github.com/dotnet/dotnet-monitor/issues/1274,所以如果可能應當使用 Listen 模式,.NET Core 3.x 只支持 Connect 模式
Open API
dotnet-monitor 除了 metrics 之外還提供了很多的別的 API 可以參考文檔 https://github.com/dotnet/dotnet-monitor/blob/main/documentation/api/README.md
| /processes | 獲取捕獲的進程的信息 |
| /dump | 生成一個進程的托管 dump |
| /gcdump | 生成進程的 GC dump |
| /trace | 生成進程的 Trace 信息 |
| /metrics | 生成進程的 metrics 信息,并以 Prometheus 的格式返回 |
| /livemetrics | 捕獲進程的實時 metrics 信息 |
| /logs | 捕獲進程日志信息(EventLog) |
| /info | 獲取當前 dotnet-monitor 的信息(版本信息,基本配置) |
| /operations | 獲取 egress 操作狀態獲取取消操作 |
More
使用 dotnet-monitor 之后,我們就可以更好的監控我們的應用程序,之前我們使用 prometheus-net.DotNetRuntime 這個項目來監控我們的應用程序,有了 dotnet-monitor 基本完全可以取代它了,而且不需要寫一行代碼,而且擴展性也比較強,只需要修改配置文件就能收集更多自己關心的數據了,功能也很強大,metrics 數據能夠幫助我們了解應用程序的整體狀態,但是有些問題可能還需要生成進程 dump 來分析具體原因,dotnet-monitor 也可以很方便地生成進程 dump 以及 trace 數據等等,還可以配置一些動態創建 dump,trace 的配置,比如內存持續一分鐘超過 2G 創建 dump 等。
另外在部署的時候,上面為了簡單沒有啟用授權,實際使用如果需要公網訪問,授權一定要做好,現在已經默認支持授權了,可以參考文檔配置,另外一種則是不要給公網訪問,只在 k8s 集權內部可以訪問,需要的話本地做一個 port-forward 進行操作,也是我更為推薦的使用方式。
功能很強大,一篇文章很難介紹完,大家可以了解一下,有需要的時候就可以用起來了
目前使用下來,總體感覺還是很棒的,但是發現一個問題,有時候信息收集有問題,部署了幾個應用,有一個應用的 System.Runtime?相關的 metrics 數據沒有收集到,其他的數據都有的,感覺很奇怪,搞了幾天了不知道哪里的姿勢不對,提了一個 issue,感興趣的可以關注一下?https://github.com/dotnet/dotnet-monitor/issues/1241,有踩過坑的大佬可以幫忙看一下萬分感謝
另外還有一點,上面 Prometheus?只會收集 dotnet-monitor 的數據,如果要同時收集 dotnet-monitor 的 metrics 和 應用的 metrics ,你可能需要使用 Prometheus 的 Service Monitor?的 Operator,這里不多做介紹了,可以自己了解一下
References
https://github.com/WeihanLi/SparkTodo/blob/master/manifests/deployment.yml
https://github.com/OpenReservation/ReservationServer/blob/dev/k8s/dotnet-monitor-configmap.yaml
https://github.com/OpenReservation/ReservationServer/blob/dev/k8s/reservation-deployment.yaml
https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack#kube-prometheus-stack
https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack/crds
https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/troubleshooting.md
https://github.com/dotnet/dotnet-monitor/issues/1274
https://github.com/dotnet/dotnet-monitor/issues/1241
https://github.com/dotnet/dotnet-monitor/
https://github.com/dotnet/dotnet-monitor/tree/main/documentation
https://github.com/dotnet/dotnet-monitor/blob/main/documentation/kubernetes.md
總結
以上是生活随笔為你收集整理的使用 dotnet-monitor 在 Kubernetes 中收集 .NET metrics的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux下部署Kubernetes+K
- 下一篇: 天了噜!定义static字段还有顺序要求