天天看點

如何建立一個帶診斷工具的.NET鏡像

作者:INCerry

現階段的問題

現在是雲原生和容器化時代,.NET Core對于雲原生來說有非常好的相容和親和性,dotnet社群以及微軟為.NET Core提供了非常友善的鏡像容器化方案。是以現在大多數的dotnet程式都是部署在各種容器化環境中,比如我們常見的Docker。

微軟官方為.NET提供的許多Docker鏡像,讓我們可以很友善的建立容器化的.NET應用。如下所示就是部分官方提供的不同作業系統的鏡像。

如何建立一個帶診斷工具的.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鏡像

而且在沒有安裝.NET SDK的情況下,我們也無法安裝dotnet tool。

如何建立一個帶診斷工具的.NET鏡像

解決方案

1.直接使用指令安裝dotnet sdk,然後再安裝dotnet tool,微軟在官網給出的非常友善的安裝方案,但是這不是我們想要的,畢竟每次還得下載下傳多麻煩。

如何建立一個帶診斷工具的.NET鏡像

2.建構最終鏡像使用sdk鏡像,這樣的話我們就可以直接安裝好這些工具,這也不是我們想要的,因為sdk鏡像太大了,不利于我們分發和下載下傳(自建機房的鈔能力除外)。

如何建立一個帶診斷工具的.NET鏡像

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讓鏡像它變得更小,那就是後話了,不在本文中介紹。

如何建立一個帶診斷工具的.NET鏡像

常用的工具

因為公司是自建機房,是以對于存儲和網絡帶寬都比較寬裕,我們一般會在生産環境運作的鏡像中安裝下面這些工具。

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鏡像中沒有帶一些工具,安裝和使用起來很麻煩,是以分享一些我們公司内部一些技巧,希望能幫到大家。

繼續閱讀