背景.NET Framework時(shí)代,.NET 應(yīng)用程序大多直接部署運(yùn)行在Windows服務(wù)器上。無論部署exe,還是IIS站點(diǎn)、或是Windows Service,編譯后的程序直接copy、簡單配置部署上即可。 有了.NET Core之后,.NET應(yīng)用程序完美支持跨平臺部署。 支持跨平臺部署運(yùn)行,.NET 5/.NET Core的應(yīng)用程序面臨著多平臺,多場景的部署需求。比如說:部署在Windows、Linux、MaxOS...,OS層面是否需要部署.NET Runtime運(yùn)行時(shí),.NET Runtime運(yùn)行時(shí)的版本選擇,等等。 因此,今天我們研究一下.NET 5/.NET Core應(yīng)用程序的部署發(fā)布。 兩種應(yīng)用程序發(fā)布模式1. 以自包含的方式發(fā)布應(yīng)用程序 這種模式包含.NET運(yùn)行時(shí)和應(yīng)用程序及其依賴項(xiàng)的應(yīng)用程序。我們可以在未安裝.NET運(yùn)行時(shí)的操作系統(tǒng)上運(yùn)行它。 總結(jié)一句話:把.NET Runtime運(yùn)行時(shí)打包到程序運(yùn)行目錄中,應(yīng)用程序運(yùn)行的主機(jī)不需要安裝.NET Runtime運(yùn)行時(shí)。 2. 以依賴于框架的方式發(fā)布應(yīng)用程序 生成一個(gè)僅包含應(yīng)用程序本身及其依賴項(xiàng)的應(yīng)用程序。應(yīng)用程序的運(yùn)行環(huán)境必須單獨(dú)安裝.NET運(yùn)行時(shí)。 總結(jié)一句話:不包含.NET Runtime運(yùn)行時(shí),只有應(yīng)用程序本身和依賴的應(yīng)用程序。應(yīng)用程序運(yùn)行的主機(jī)需要單獨(dú)安裝應(yīng)用程序所需的.NET Runtime運(yùn)行時(shí)。 NET 5/.NET Core的應(yīng)用程序的發(fā)布指令:dotnet publishdotnet publish -將應(yīng)用程序及其依賴項(xiàng)發(fā)布到指定的文件夾中,以方便后續(xù)部署到目標(biāo)托管系統(tǒng)。 關(guān)于dotnet publish的使用說明,可以參考以下鏈接:https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-publish?WT.mc_id=DT-MVP-5003918 dotnet publish [<PROJECT>|<SOLUTION>] [-c|--configuration <CONFIGURATION>] [-f|--framework <FRAMEWORK>] [--force] [--interactive] [--manifest <PATH_TO_MANIFEST_FILE>] [--no-build] [--no-dependencies] [--no-restore] [--nologo] [-o|--output <OUTPUT_DIRECTORY>] [-p:PublishReadyToRun=true] [-p:PublishSingleFile=true] [-p:PublishTrimmed=true] [-r|--runtime <RUNTIME_IDENTIFIER>] [--self-contained [true|false]] [--no-self-contained] [-v|--verbosity <LEVEL>] [--version-suffix <VERSION_SUFFIX>]dotnet publish -h|--help dotnet publish 將編譯應(yīng)用程序,讀取其在項(xiàng)目文件中指定的依賴項(xiàng),然后將結(jié)果文件集發(fā)布到目錄中。輸出包括以下內(nèi)容:
從上述描述中,我們可以發(fā)現(xiàn),通過dotnet publish指令,我們可以編譯應(yīng)用程序,生成并輸出指定運(yùn)行環(huán)境的交付物。 我們新建一個(gè).NET 5的Console應(yīng)用程序,同時(shí)引用Newtonsoft.Json Nuget包。 Main函數(shù)的代碼: using System;
首先,編譯一下這個(gè)工程dotnet build,這一步很重要。然后,使用命令行執(zhí)行dotnet publish指令: 我們看一下F:\GitHub\Source\Repos\NET5PublishExample\bin\Debug\net5.0\publish\目錄下生成的文件: 正如上面所說,輸出包括以下內(nèi)容:
同時(shí),還生成了一個(gè)Windows平臺的可執(zhí)行文件:NET5PublishExample.exe,雙擊可以執(zhí)行: 另外,使用dotnet NET5PublishExample.dll,也可以直接執(zhí)行: 然后有幾個(gè)疑問:
帶著這2個(gè)問題,我們繼續(xù)往下研究? dotnet publish生成的可執(zhí)行文件和跨平臺二進(jìn)制文件自包含的方式發(fā)布應(yīng)用程序,依賴于框架的方式發(fā)布應(yīng)用程序。這兩種發(fā)布模式默認(rèn)情況下都會(huì)生成特定于平臺的可執(zhí)行文件和跨平臺二進(jìn)制文件。 1. 可執(zhí)行文件 可執(zhí)行文件不是跨平臺的。它們特定于操作系統(tǒng)和CPU體系結(jié)構(gòu)。因?yàn)閃indows和linux下的可執(zhí)行文件的結(jié)構(gòu)和內(nèi)容是不同的,所以可執(zhí)行文件是分操作系統(tǒng)的。 這里我們示例2個(gè)平臺的可執(zhí)行文件: ① windows-x64平臺 ② Linux-x64平臺 使用的dotnet publish指令 dotnet publish -r linux-x64 --self-contained false 生成的可執(zhí)行文件: 2. 跨平臺的二進(jìn)制文件 將應(yīng)用程序發(fā)布為依賴于框架的dll文件形式時(shí),就會(huì)創(chuàng)建跨平臺的二進(jìn)制文件。該dll文件以項(xiàng)目命名。例如,如果您有一個(gè)名為應(yīng)用程序NET5PublishExample,文件名為NET5PublishExample.dll創(chuàng)建。 以這種方式發(fā)布的應(yīng)用程序dotnet <filename.dll>可以通過命令運(yùn)行,可以在任何平臺上運(yùn)行。 關(guān)于自包含的發(fā)布選項(xiàng)和示例以自包含的方式發(fā)布應(yīng)用會(huì)生成特定于平臺的可執(zhí)行文件。 輸出發(fā)布文件夾包含應(yīng)用程序的所有組件,包括.NET庫和目標(biāo)運(yùn)行時(shí)。該應(yīng)用程序與其他.NET應(yīng)用程序隔離,并且不使用本地安裝的.NET運(yùn)行時(shí)。因此無需下載并安裝.NET 運(yùn)行時(shí)。 可執(zhí)行二進(jìn)制文件針對指定的目標(biāo)平臺生成。例如,如果您有一個(gè)名為NET5PublishExample的應(yīng)用程序,并且發(fā)布了Windows的自包含可執(zhí)行文件,則會(huì)創(chuàng)建NET5PublishExample.exe文件。對于Linux或macOS發(fā)布,將創(chuàng)建一個(gè)NET5PublishExample文件。目標(biāo)平臺和體系結(jié)構(gòu)-r <RID>由dotnet publish命令的參數(shù)指定。有關(guān)RID的更多信息,請參見.NET RID目錄。 如果應(yīng)用程序具有特定于平臺的依賴項(xiàng),例如包含特定于平臺的依賴項(xiàng)的NuGet程序包,則這些依賴項(xiàng)將與應(yīng)用程序一起復(fù)制到publish文件夾中。 這種模式的優(yōu)勢有哪些呢?
同時(shí)也帶來了以下問題:
例如: 示例1:發(fā)布一個(gè)獨(dú)立的應(yīng)用程序,創(chuàng)建macOS 64位可執(zhí)行文件,同時(shí)包含了.NET 運(yùn)行時(shí) dotnet publish -r osx-x64 生成的文件列表如下:包含macOS 64可執(zhí)行文件NET5PublishExample,以及包含了對應(yīng)macOS 64平臺下的.NET 運(yùn)行時(shí) 示例2:發(fā)布一個(gè)獨(dú)立的應(yīng)用程序,創(chuàng)建Windows 64位可執(zhí)行文件,同時(shí)包含了.NET 運(yùn)行時(shí)
生成的文件列表如下:包含Windows 64可執(zhí)行文件NET5PublishExample.exe,以及包含了對應(yīng)Windows 64平臺下的.NET 運(yùn)行時(shí) 關(guān)于依賴框架的發(fā)布選項(xiàng)和示例發(fā)布為依賴框架的應(yīng)用程序是跨平臺的,并且不包含.NET運(yùn)行時(shí)。應(yīng)用程序的運(yùn)行需要單獨(dú)安裝指定版本的.NET運(yùn)行時(shí)。 應(yīng)用程序的跨平臺二進(jìn)制文件可以使用dotnet <filename.dll>命令運(yùn)行,并且可以在任何平臺上運(yùn)行。如果應(yīng)用程序使用具有特定于平臺的實(shí)現(xiàn)的NuGet包,則所有平臺的依賴項(xiàng)都將與應(yīng)用程序一起復(fù)制到publish文件夾中。 可以通過將-r <RID> --self-contained false參數(shù)傳遞給dotnet publish命令來為特定平臺創(chuàng)建可執(zhí)行文件。當(dāng)-r參數(shù)被省略,為當(dāng)前平臺創(chuàng)建一個(gè)可執(zhí)行文件。具有目標(biāo)平臺特定于平臺的依賴關(guān)系的任何NuGet軟件包都將復(fù)制到publish文件夾中。 這種模式帶來的優(yōu)勢有:
同時(shí)也帶來了以下問題:
例如: 示例1:發(fā)布一個(gè)當(dāng)前平臺的依賴框架的跨平臺應(yīng)用程序,不包含.NET 運(yùn)行時(shí),將與dll文件一起創(chuàng)建一個(gè)針對當(dāng)前平臺的可執(zhí)行文件。 dotnet publish 使用dotnet NET5PublishExample.dll,可以直接運(yùn)行(本機(jī)已經(jīng)安裝.NET運(yùn)行時(shí),NET5PublishExample.dll是跨平臺的二進(jìn)制文件) 示例2:發(fā)布一個(gè)依賴框架的跨平臺應(yīng)用程序(Linux 64位),不包含.NET 運(yùn)行時(shí),將創(chuàng)建一個(gè)Linux 64位可執(zhí)行文件以及dll文件。
![]() 使用dotnet NET5PublishExample.dll,可以直接運(yùn)行(本機(jī)已經(jīng)安裝.NET運(yùn)行時(shí),NET5PublishExample.dll是跨平臺的二進(jìn)制文件) ![]() ReadyToRun編譯選項(xiàng)通過將應(yīng)用程序程序集編譯為ReadyToRun(R2R)格式,可以改善.NET應(yīng)用程序的啟動(dòng)時(shí)間和延遲。R2R是一種提前(AOT)編譯的形式。 R2R二進(jìn)制文件通過減少應(yīng)用程序加載時(shí)即時(shí)(JIT)編譯器需要完成的工作量來提高啟動(dòng)性能。與JIT產(chǎn)生的代碼相比,二進(jìn)制文件包含相似的本機(jī)代碼。 但是,R2R二進(jìn)制文件較大,因?yàn)樗鼈兗劝虚g語言(IL)代碼(某些情況下仍然需要此代碼)和同一代碼的本機(jī)版本。僅當(dāng)發(fā)布針對特定運(yùn)行時(shí)環(huán)境(RID)(例如Linux x64或Windows x64)的應(yīng)用程序時(shí),R2R才可用。 總結(jié)一下:通過R2R方式,可以直接將代碼編譯為Native Code,減少.NET 程序第一次加載時(shí)JIT編譯帶來的性能消耗,以提升.NET應(yīng)用的首次加載性能。類似于ngen的程序集預(yù)加載。關(guān)于Ngen可以參考這個(gè)鏈接:ngen 對應(yīng)的dotnet publish指令選項(xiàng): dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true 以上是.NET 5/.NET Core應(yīng)用程序的發(fā)布部署的一些研究和分享。 推薦一個(gè)不錯(cuò)的知識鏈接:https://docs.microsoft.com/en-us/dotnet/core/deploying/#publish-framework-dependent?WT.mc_id=DT-MVP-5003918 |
|