快速搞懂.NET 5/.NET Core應用程序的發佈部署

.NET Framework時代,.NET 應用程序大多直接部署運行在Windows服務器上,固然也能夠經過Mono部署運行在Linux上。不管部署exe,仍是IIS站點、或是Windows Service,編譯後的程序直接copy、簡單配置部署上便可。linux

有了.NET Core以後,.NET應用程序完美支持跨平臺部署,.NET 5 Release後,沿襲了.NET Core應用程序發佈模式。json

支持跨平臺部署運行,.NET 5/.NET Core的應用程序面臨着多平臺,多場景的部署需求。好比說:部署在Windows、Linux、MaxOS...,OS層面是否須要部署.NET Runtime運行時,.NET Runtime運行時的版本選擇,等等。windows

所以,今天咱們研究一下.NET 5/.NET Core應用程序的部署發佈。緩存

1、兩種應用程序發佈模式安全

  1. 以自包含的方式發佈應用程序服務器

      這種模式包含.NET運行時和應用程序及其依賴項的應用程序。咱們能夠在未安裝.NET運行時的操做系統上運行它。框架

      總結一句話:把.NET Runtime運行時打包到程序運行目錄中,應用程序運行的主機不須要安裝.NET Runtime運行時。函數

  2. 以依賴於框架的方式發佈應用程序性能

      生成一個僅包含應用程序自己及其依賴項的應用程序。應用程序的運行環境必須單獨安裝.NET運行時。ui

      總結一句話:不包含.NET Runtime運行時,只有應用程序自己和依賴的應用程序。應用程序運行的主機須要單獨安裝應用程序所需的.NET Runtime運行時。

2、NET 5/.NET Core的應用程序的發佈指令:dotnet publish

  dotnet publish -將應用程序及其依賴項發佈到指定的文件夾中,以方便後續部署到目標託管系統。

  關於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 將編譯應用程序,讀取其在項目文件中指定的依賴項,而後將結果文件集發佈到目錄中。輸出包括如下內容

  • 具備dll擴展名的程序集中的中間語言(IL)代碼。
  • 一個.deps.json文件,其中包含項目的全部依賴項
  • 一個.runtimeconfig.json文件,它指定應用程序指望的共享運行時,以及該運行時的其餘配置選項(例如,垃圾收集類型)。
  • 應用程序依賴的應用程序,從NuGet緩存目錄複製到輸出文件夾中。

    從上述描述中,咱們能夠發現,經過dotnet publish指令,咱們能夠編譯應用程序,生成並輸出指定運行環境的交付物。

    咱們新建一個.NET 5的Console應用程序,同時引用Newtonsoft.Json Nuget包。

    

    Main函數的代碼:

using System;

namespace NET5PublishExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var msg = Newtonsoft.Json.JsonConvert.SerializeObject("Hello .NET 5!");
            Console.WriteLine(msg);
            Console.ReadKey();
        }
    }
}

  首先,編譯一下這個工程dotnet build,這一步很重要。而後,使用命令行執行dotnet publish指令:

   

   咱們看一下F:\GitHub\Source\Repos\NET5PublishExample\bin\Debug\net5.0\publish\目錄下生成的文件:

   

    正如上面所說,輸出包括如下內容

  • 具備dll擴展名的程序集中的中間語言(IL)代碼:NET5PublishExample.dll
  • 一個.deps.json文件,其中包含項目的全部依賴項NET5PublishExample.deps.json
  • 一個.runtimeconfig.json文件,它指定應用程序指望的共享運行時,以及該運行時的其餘配置選項(例如,垃圾收集類型)。NET5PublishExample.runtimeconfig.json
  • 應用程序依賴的應用程序,從NuGet緩存目錄複製到輸出文件夾中。Newtonsoft.Json.dll

     同時,還生成了一個Windows平臺的可執行文件:NET5PublishExample.exe,雙擊能夠執行:

     

     另外,使用dotnet NET5PublishExample.dll,也能夠直接執行:

      

     而後有幾個疑問:

     NET5PublishExample.dll是否是能夠跨平臺運行?

     在Linux、MacOS平臺下有沒有對應的可執行文件?

     帶着這2個問題,咱們繼續往下研究?

3、dotnet publish生成的可執行文件和跨平臺二進制文件

     自包含的方式發佈應用程序,依賴於框架的方式發佈應用程序。這兩種發佈模式默認狀況下都會生成特定於平臺的可執行文件和跨平臺二進制文件。

     1. 可執行文件

     可執行文件不是跨平臺的。它們特定於操做系統和CPU體系結構。由於Windows和linux下的可執行文件的結構和內容是不一樣的,因此可執行文件是分操做系統的。

     建立可執行文件時,同時能夠選擇將應用程序發佈爲自包含或依賴於框架。

     以自包含的方式發佈應用程序包括該應用程序的.NET運行時,而且該應用程序的用戶沒必要擔憂在運行該應用程序以前安裝.NET。能夠直接執行!

     發佈爲與框架相關的應用程序不包括.NET運行時和庫。僅包括應用程序和第三方依賴項。須要安裝.NET 運行時。

     這裏咱們示例2個平臺的可執行文件:

     ① windows-x64平臺

     

      ② Linux-x64平臺

       使用的dotnet publish指令 dotnet publish -r linux-x64 --self-contained false

       

       生成的可執行文件:

       

     2. 跨平臺的二進制文件

     將應用程序發佈爲依賴於框架的dll文件形式時,就會建立跨平臺的二進制文件。該dll文件以項目命名。例如,若是您有一個名爲應用程序NET5PublishExample,文件名爲NET5PublishExample.dll建立。

     以這種方式發佈的應用程序dotnet <filename.dll>能夠經過命令運行,能夠在任何平臺上運行。

4、關於自包含的發佈選項和示例

    以自包含的方式發佈應用會生成特定於平臺的可執行文件

    輸出發佈文件夾包含應用程序的全部組件,包括.NET庫和目標運行時。該應用程序與其餘.NET應用程序隔離,而且不使用本地安裝的.NET運行時。所以無需下載並安裝.NET 運行時。

    可執行二進制文件針對指定的目標平臺生成。例如,若是您有一個名爲NET5PublishExample的應用程序,而且發佈了Windows的自包含可執行文件,則會建立NET5PublishExample.exe文件。對於Linux或macOS發佈,將建立一個NET5PublishExample文件。目標平臺和體系結構-r <RID>由dotnet publish命令的參數指定。有關RID的更多信息,請參見.NET RID目錄

    若是應用程序具備特定於平臺的依賴項,例如包含特定於平臺的依賴項的NuGet程序包,則這些依賴項將與應用程序一塊兒複製到publish文件夾中。

    這種模式的優點有哪些呢?

  1.     控制.NET版本:能夠控制與應用程序一塊兒部署的.NET版本。
  2.     指定運行的平臺:由於必須爲每一個平臺發佈應用程序,因此咱們須要肯定應用程序將在何處運行。若是.NET引入了新平臺,則必須先發布針對該平臺的版本,而後才能在該平臺上運行您的應用程序。

    同時也帶來了如下問題:

  1.     更大的部署內容:應用程序包括.NET運行時和全部應用程序依賴項,因此所需的下載大小和硬盤空間大於依賴於框架的版本。
  2.     難以更新.NET版本.NET Runtime:(隨應用程序分發)只能經過發佈新版本的應用程序進行升級。可是,.NET將根據應用程序運行的計算機上框架庫的須要更新關鍵的安全補丁。

    例如:

    示例1:發佈一個獨立的應用程序,建立macOS 64位可執行文件,同時包含了.NET 運行時

dotnet publish -r osx-x64

    生成的文件列表以下:包含macOS 64可執行文件NET5PublishExample,以及包含了對應macOS 64平臺下的.NET 運行時

    

      示例2:發佈一個獨立的應用程序,建立Windows 64位可執行文件,同時包含了.NET 運行時

 dotnet publish -r win-x64

    生成的文件列表以下:包含Windows 64可執行文件NET5PublishExample.exe,以及包含了對應Windows 64平臺下的.NET 運行時

       

5、關於依賴框架的發佈選項和示例

  發佈爲依賴框架的應用程序是跨平臺的,而且不包含.NET運行時。應用程序的運行須要單獨安裝指定版本的.NET運行時

  應用程序的跨平臺二進制文件可使用dotnet <filename.dll>命令運行,而且能夠在任何平臺上運行。若是應用程序使用具備特定於平臺的實現的NuGet包,則全部平臺的依賴項都將與應用程序一塊兒複製到publish文件夾中。

  能夠經過將-r <RID> --self-contained false參數傳遞給dotnet publish命令來爲特定平臺建立可執行文件。當-r參數被省略,爲當前平臺建立一個可執行文件。具備目標平臺特定於平臺的依賴關係的任何NuGet軟件包都將複製到publish文件夾中。

  這種模式帶來的優點有:

  1.   小型部署:僅分發應用程序及其依賴項。.NET運行時和庫由用戶安裝,全部應用共享運行時。
  2.   跨平臺:應用程序和任何基於.NET的庫均可以在其餘操做系統上運行
  3.   使用最新的.NET運行時:該應用程序使用目標系統上安裝的最新運行時(在.NET的目標主要,次要家族中)。這意味着應用程序會自動使用最新的.NET運行時修補版本。

   同時也帶來了如下問題:

  1.    須要預安裝.NET 運行時僅在主機系統上已安裝應用目標的.NET運行時版本時,應用才能運行。
  2.    .NET可能會更改:.NET運行時和庫可能會在運行該應用程序的計算機上更新。

   例如:

   示例1:發佈一個當前平臺的依賴框架的跨平臺應用程序,不包含.NET 運行時,將與dll文件一塊兒建立一個針對當前平臺的可執行文件。   

dotnet publish

   

   使用dotnet NET5PublishExample.dll,能夠直接運行(本機已經安裝.NET運行時,NET5PublishExample.dll是跨平臺的二進制文件

   示例2:發佈一個依賴框架的跨平臺應用程序(Linux 64位),不包含.NET 運行時,將建立一個Linux 64位可執行文件以及dll文件。    

dotnet publish -r linux-x64 --self-contained false

      使用dotnet NET5PublishExample.dll,能夠直接運行(本機已經安裝.NET運行時,NET5PublishExample.dll是跨平臺的二進制文件

      

  6、ReadyToRun編譯選項

   經過將應用程序程序集編譯爲ReadyToRun(R2R)格式,能夠改善.NET應用程序的啓動時間和延遲。R2R是一種提早(AOT)編譯的形式。

   R2R二進制文件經過減小應用程序加載時即時(JIT)編譯器須要完成的工做量來提升啓動性能。與JIT產生的代碼相比,二進制文件包含類似的本機代碼

   可是,R2R二進制文件較大,由於它們既包含中間語言(IL)代碼(某些狀況下仍然須要此代碼)和同一代碼的本機版本。僅當發佈針對特定運行時環境(RID)(例如Linux x64或Windows x64)的應用程序時,R2R纔可用。

   總結一下:經過R2R方式,能夠直接將代碼編譯爲Native Code,減小.NET 程序第一次加載是JIT編譯帶來的性能消耗,以提高.NET應用的首次加載性能。相似於ngen的程序集預加載。關於Ngen能夠參考這個連接:ngen

   對應的dotnet publish指令選項:   dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true

 

   以上是.NET 5/.NET Core應用程序的發佈部署的一些研究和分享。

   推薦一個不錯的知識連接:https://docs.microsoft.com/en-us/dotnet/core/deploying/#publish-framework-dependent?WT.mc_id=DT-MVP-5003918

 

周國慶

2020/2/15

相關文章
相關標籤/搜索