如何创建一个带诊断工具的.NET镜像
现阶段的问题
现在是云原生和容器化时代,.NET Core对于云原生来说有非常好的兼容和亲和性,dotnet社区以及微软为.NET Core提供了非常方便的镜像容器化方案。所以现在大多数的dotnet程序都是部署在各种容器化环境中,比如我们常见的Docker。
微软官方为.NET提供的许多Docker镜像,让我们可以很方便的创建容器化的.NET应用。如下所示就是部分官方提供的不同操作系统的镜像。

其它更详细的内容大家可以点击后面的网址查看:https://hub.docker.com/_/microsoft-dotnet-runtime/
使用VS新建一个项目,微软官方给出的多段构建Dockerfile如下所示:
# 使用aspnet runtime镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS base
WORKDIR /app
EXPOSE 80
# 使用sdk镜像进行编译
FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build
# 使用build镜像发布
FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish
# 拷贝编译结果到base镜像,完成镜像打包
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]
现在看起来一切都很美好,但是假设我们遇到某一些线上CPU 100%、内存占用率很高或者程序突然停止响应等问题我们需要使用dotnet-trace、dotnet-dump等工具时就会发现使用不了。

而且在没有安装.NET SDK的情况下,我们也无法安装dotnet tool。

解决方案
1.直接使用命令安装dotnet sdk,然后再安装dotnet tool,微软在官网给出的非常方便的安装方案,但是这不是我们想要的,毕竟每次还得下载多麻烦。

2.构建最终镜像使用sdk镜像,这样的话我们就可以直接安装好这些工具,这也不是我们想要的,因为sdk镜像太大了,不利于我们分发和下载(自建机房的钞能力除外)。

3.就是我们今天提到的方案,我们可以利用Docker多段构建,使用sdk镜像安装好dotnet tool以后,直接COPY到我们runtime的镜像,然后在runtime的镜像中使用。
# 使用aspnet runtime镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/aspnet:6.0-focal AS base
WORKDIR /app
EXPOSE 80
# 使用sdk镜像进行编译
FROM mcr.microsoft.com/dotnet/sdk:6.0-focal AS build
WORKDIR /src
COPY ["WebApplication1/WebApplication1.csproj", "WebApplication1/"]
RUN dotnet restore "WebApplication1/WebApplication1.csproj"
COPY . .
WORKDIR "/src/WebApplication1"
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build
# !!! 在build镜像安装dotnet tools
RUN dotnet tool install -g dotnet-dump \
&& dotnet tool install -g dotnet-trace
# 使用build镜像发布
FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish
# 拷贝编译结果到base镜像,完成镜像打包
FROM base AS final
WORKDIR /app
# !!! 从build镜像中把dotnet工具COPY出来 并设置为PATH
COPY --from=build /root/.dotnet/tools /root/.dotnet/tools
ENV PATH="$PATH:/root/.dotnet/tools"
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]
其中关键就是这两步,在build中使用dotnet tool来安装好所需要的工具,然后复制到runtime镜像中。
...
# !!! 在build镜像安装dotnet tools
RUN dotnet tool install -g dotnet-dump \
&& dotnet tool install -g dotnet-trace
...
# !!! 从build镜像中把dotnet工具COPY出来 并设置为PATH
COPY --from=build /root/.dotnet/tools /root/.dotnet/tools
ENV PATH="$PATH:/root/.dotnet/tools"
当然我们可以打包一个包含好工具的runtime,供后面使用,就不用每次都安装tool了。我个人比较喜欢使用Ubuntu作为基础镜像,大家也可以用Alpine之类的基础镜像来进一步缩小体积。
# 使用sdk镜像进行编译
FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build
# !!! 在build镜像安装dotnet tools
RUN dotnet tool install -g dotnet-dump \
&& dotnet tool install -g dotnet-trace
# 使用aspnet runtime镜像作为基础镜像
FROM mcr.microsoft.com/dotnet/aspnet:6.0-alpine AS base
WORKDIR /app
# !!! 从build镜像中把dotnet工具COPY出来 并设置为PATH
COPY --from=build /root/.dotnet/tools /root/.dotnet/tools
ENV PATH="$PATH:/root/.dotnet/tools"
最终镜像也很小,当然我们可以使用单文件发布和Native AOT让镜像它变得更小,那就是后话了,不在本文中介绍。

常用的工具
因为公司是自建机房,所以对于存储和网络带宽都比较宽裕,我们一般会在生产环境运行的镜像中安装下面这些工具。
RUN dotnet tool install -g dotnet-dump \
&& dotnet tool install -g dotnet-trace \
&& dotnet tool install -g dotnet-counters \
&& dotnet tool install -g dotnet-sos \
&& dotnet tool install -g dotnet-gcdump \
&& dotnet tool install -g dotnet-monitor \
&& dotnet tool install -g dotnet-symbol \
&& dotnet tool install -g JetBrains.dotTrace.GlobalTools
在遇到线上问题的时候,排查起来非常方便,对于一些内存泄漏和CPU满的问题,配合dotTrace很容易就能定位到问题所在。
总结
本文编写的初衷是因为在群里有很多小伙伴遇到生产环境性能问题的时候,.NET的runtime镜像中没有带一些工具,安装和使用起来很麻烦,所以分享一些我们公司内部一些技巧,希望能帮到大家。
如何创建一个带诊断工具的.NET镜像的更多相关文章
- 「六」创建一个带 weblogic 服务的基础镜像
Weblogic Weblogic 简单介绍以及其在 Docker 环境下的特殊应用 WebLogic是美国Oracle公司出品的一个application server确切的说是一个基于JAVAEE ...
- 「五」创建一个带 tomcat 服务的基础镜像(修订版)
Tomcat Tomcat 简单介绍 Tomcat server是一个免费的开放源码的Web 应用server,属于轻量级应用server.在中小型系统和并发訪问用户不是非常多的场合下被普遍使用,是开 ...
- 创建一个带模版的用户控件 V.3
再重构此篇<创建一个带模版的用户控件 V.2>http://www.cnblogs.com/insus/p/4164149.html 让其它动态实现header,Item和Footer. ...
- 创建一个带模版的用户控件 V.2
前面有做练习<创建一个带模版的用户控件>http://www.cnblogs.com/insus/p/4161544.html .过于简化.通常使用数据控件Repeater会有网页写好He ...
- 十分钟通过 NPM 创建一个命令行工具
大过年的,要不要写点代码压压惊?来花十分钟学一下怎么通过 NPM 构建一个命令行工具. 写了一个小 demo,用于代替 touch 的创建文件命令 touchme ,可以创建自带“佛祖保佑”注释的文件 ...
- 「两」创建一个带 ssh 镜座服务(修订版)--采用 Dockerfile 创
创建目录 首先,创建一个叫做 sshd_ubuntu 的目录,用于存放我们的 Dockerfile .脚本文件.以及其它文件. $ mkdir sshd_ubuntu $ ls sshd_ubuntu ...
- dom4j 创建一个带命名空间的pom.xml 文件
http://xml.apache.org/xalan-j/index.html 需要的jar包 <dependencies> <dependency> <groupId ...
- AngularJs创建一个带参数的自定义方法
学习这篇之前,先要从这篇<AngularJs创建自定义Service>http://www.cnblogs.com/insus/p/6773894.html 开始. 看看: app.con ...
- 【分分钟内搭建一个带用户系统的博客程序(一)用户系统】asp.net core的Identity真香,EF真香!
不用不知道,一用香到爆. 老哥是个屌丝前端,但也想写点web应用耍一耍.之前弄过了NodeJs,也弄过JAVA,最近由于写游戏的原因用C#,索性上手一波asp.net core. 这篇博客记录的是,如 ...
随机推荐
- 容器内的Linux诊断工具0x.tools
原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,转载请保留出处. 简介 Linux上有大量的问题诊断工具,如perf.bcc等,但这些诊断工具,虽然功能强大,但却需要很高的权限才可以使用 ...
- C# 随机给一个全部信息都未知的类类型,如何获取该类的类名、属性个数、属性名、属性的数据类型、属性值?
一.场景假设 假设现在有一个泛型类T的实例对象t,该T类的全部信息都未知. 要求:打印输出实例对象t的类名.属性个数.属性名.属性的数据类型.属性值. 二.解决问题 1.我们根据输出的内容要求定义一个 ...
- ELF文件结构
ELF文件结构 ELF文件的全称是Executable and Linkable Format,直译为"可执行可链接格式",包括目标文件(.o).可执行文件(可以直接运行).静态链 ...
- 满满干货!手把手教你实现基于eTS的分布式计算器
最近收到很多小伙伴反馈,想基于扩展的TS语言(eTS)进行HarmonyOS应用开发,但是不知道代码该从何处写起,从0到1的过程让新手们抓狂. 本期我们将带来"分布式计算器"的开发 ...
- VS Code - Vim 插件自动切换输入法
前言: 在使用 Linux 的过程中,vim 是一个不错的编辑器,以至于多数人将其用成了习惯,在没有 vim 的环境下还是习惯用 vim 的快捷键来编辑文本.所以便有开发者们为众多的 IDE 和文本编 ...
- 在CabloyJS中将Webpack生成的文件自动上传到阿里云OSS
背景 阿里云OSS提供了一个Webpack插件,可在Webpack打包结束后将webpack生成的文件自动上传到阿里云OSS中 下面看看在CabloyJS中如何使用该插件 新建项目,并配置MySQL连 ...
- client offset scroll 之间的区别
一.client 属性 值 clientWidth 元素被设置的宽度 + padding左右内间距 clientHeight 元素被设置的高度 + padding上下内间距 clientLeft 左 ...
- php三行代码解决输入地址给出经纬度
//获取地址经纬度坐标 public function getAddress() { $ak = 'GPIrsdfZ-UNLRP-VBBDB-V3AGK-XL5KO-5DBNY'; $address ...
- Windows系统重置用户登录密码
更新记录 2022年4月16日:本文迁移自Panda666原博客,原发布时间:2021年8月23日. 方法一.使用带有密码恢复功能的PE盘 买一张 PE光盘 或 自制PE启动盘,这里推荐微PE. 准备 ...
- php判断客户端浏览器类型
/** * 判断浏览器名称和版本 */ function get_user_browser() { if (empty($_SERVER['HTTP_USER_AGENT'])) { return ' ...