Asp.net core 發佈部署模式的選擇

前言

之前寫代碼的時候光顧着業務邏輯代碼的編寫,對ASP.net core的發佈和部署基本上沒去了解,對於部署模式的態度都是能跑起來就行,這段時間有空了打算認真把這個坑踩一下。
看了一下微軟自家的說明文檔,每個字都認識,但就是看不懂是什麼意思。獨立發佈、框架依賴、IIS、Kestrel、Nginx,一堆選擇實在搞得有點暈頭轉向。
這裏用到的.Net Core版本爲2.2。

選擇流程

正如微軟的文檔說到,我們部署一個ASP.net core項目確實需要根據我們的應用類型或部署環境選擇相應的部署模式。
選擇的過程分兩步走。第一,選擇部署模式。第二,選擇託管宿主。下面將展開說明。

部署模式選擇

獨立發佈 VS 框架依賴

ASP.net Core目前部署模式有三種,獨立發佈(SCD)、框架依賴(FDD)、依賴框架的可執行文件(FDE)。其中FDD和FDE差別不大,這裏不做討論,有興趣可以看看官方的文檔。
https://docs.microsoft.com/zh-cn/dotnet/core/deploying/

獨立發佈

獨立部署。 與 FDD 不同,獨立部署 (SCD) 不依賴目標系統上存在的共享組件。 所有組件(包括 .NET Core 庫和 .NET Core 運行時)都包含在應用程序中,並且獨立於其他 .NET Core 應用程序。

框架依賴

依賴框架的部署。 顧名思義,依賴框架的部署 (FDD) 依賴目標系統上存在共享系統級版本的 .NET Core。 由於已存在 .NET Core,因此應用在 .NET Core 安裝程序間也是可移植的。 應用僅包含其自己的代碼和任何位於 .NET Core 庫外的第三方依賴項。

如何選擇

簡單的說框架依賴和獨立發佈的區別就是裝不裝 .Net core運行時的區別。裝上運行時之後,很多.net core的庫都能共用,否則就需要另外打包進去,所以獨立發佈的程序體積會比框架依賴大得多。本人以ASP.net core默認樣板應用實測,獨立發佈的大小約爲100M,框架依賴的大小約爲5M。
在這裏插入圖片描述
獨立發佈的話不需要安裝.net core的運行時,而框架依賴則需要安裝.net core 運行時或者直接安裝SDK。
所以,重點來了。如果你的服務器平時都是跑其他程序,只是偶爾情況特殊需要跑幾個ASP.net core,那麼推薦你使用獨立發佈模式。如果你的服務器打算跑多個ASP.net core程序,並且將來也打算以ASP.net core作爲技術路線,框架依賴是你最好的選擇。
這裏以Windows下 .Net Core 2.2爲例,.net core 運行時僅89M。所以,如果跑兩個以上ASP.net core或者想省事的同學,請直接選擇安裝框架依賴,省地又省事。
對於Linux,和上文的Windows一樣,有個地方要注意的是,如果你選擇的是獨立發佈,沒有裝.net core 運行時的話,那麼就不能用dotnet xxx.dll 這個命令來運行程序了,就要cd 到程序目錄然後 ./ xxx ,xxx是你輸出的文件名。

託管宿主選擇

IIS VS Kestrel VS Windows服務

選擇好部署模式之後就該考慮選擇託管宿主,託管宿主的選擇體現在ASP.net core應用中的Program.cs,在 CreateWebHostBuilder 方法中可以選擇UseIIS或者UseKestrel。
根據微軟的文檔,我們在Windows系統下有3種託管選擇:IIS、Kestrel、Windows服務。首先,Windows服務實質上也是用Kerstrel,但是跑在服務裏可以做到開機自啓;同樣的功能IIS也能做到。選擇託管宿主在代碼上怎麼體現?下面會上代碼說明。這裏我們現在討論一下不同情況下該怎麼選宿主。
因爲Windows服務實質上也是Kerstrel(親測UseIIS根本跑不起來)。所以這裏先討論IIS和Kerstrel的區別。這裏先借鑑一下這位大佬的文章,裏面詳細地對比了IIS和Kestrel的性能區別。
https://www.cnblogs.com/savorboard/p/dotnet-benchmarks.html#asp.net-core-vs-asp.net-corekestrel-vs-iis
首先,Kestrel的性能比IIS好這個是鐵打的事實,但是Kestrel它沒有反向代理的功能,簡單的說,就是它做不到一個端口映射多個應用,假如它綁了443端口做https,其它應用就不能用443端口,而在IIS中,一個443端口綁多個應用可以說是基本操作。
所以,一般部署在外網的應用不會只使用Kestrel,而是會添加一個IIS、Nginx或者Apache作爲反向代理,首先Kestrel部署在其他端口(假設爲8081)上,Nginx監聽443端口,收到請求後根據請求的域名區分它是請求哪個應用,再轉發到對應的端口(8081)上處理。
在這裏插入圖片描述
這樣就會產生一個很尷尬的現象,性能就變成了由反向代理或者Kestrel中最慢的一個來決定。假如我使用IIS作爲反向代理,不管你Kestrel性能有多強悍,還不是要被IIS卡住?那爲什麼我不直接用IIS呢?還省了一步轉發。
另外,Kestrel本質上是一個控制檯應用,要是遇到特殊情況掛掉了那就真的掛掉了,不會開機自啓,也不會自行重啓,當然也可以把它部署在Windows服務裏用看門狗監控它重啓,而在IIS中就不需要理這些東西。
所以,我們選擇宿主不能迷信性能,還要結合使用場景進行選擇。
那麼現在重點來了,如果你的應用部署內網,用IP+端口進行訪問,那麼選Kestrel就對了,爲了讓它運行得更穩定,可以把它部署在Windows服務裏。如果你的應用是部署在外網,靠域名來訪問,而且服務器上不止跑一個應用,那麼就推薦使用Kestrel + 反向代理的操作。但是如果你的反向代理是用IIS的話,還是推薦你使用IIS作爲宿主,另外在程序裏配上InProcess模式,InProcess模式僅在使用IIS時纔有用,可以提升一定的性能。所以,如果你的服務器上已經用IIS跑了一些應用,爲了降低維護的複雜度就不要再搞那麼多花裏胡哨的東西,老老實實用回IIS,講道理IIS性能也不差。
另外,這裏選擇反向代理,推薦使用Nginx。
宿主選擇代碼實現。

    public class Program
    {
        public static void Main(string[] args)
        {
            string runMode = "Kestrel"; //"IIS" "Kestrel" "Service"
            if (runMode == "Service")
            {
                var isService = !(Debugger.IsAttached || args.Contains("--console"));
                
                if (isService)
                {
                    var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
                    var pathToContentRoot = Path.GetDirectoryName(pathToExe);
                    Directory.SetCurrentDirectory(pathToContentRoot);
                }
                
                var builder = CreateWebHostBuilder(args.Where(arg => arg != "--console").ToArray());
                var host = builder.Build();
                
                if (isService)
                {
                    host.RunAsService();
                }
                else
                {
                    host.Run();
                }
            }
            else
            {
                CreateWebHostBuilder(args).Build().Run();
            }
        }
        
        public static IWebHostBuilder CreateWebHostBuilder(string[] args)
        {
            IWebHostBuilder builder = null;
            string runMode = "Kestrel"; //"IIS" "Kestrel" "Service"

            if (runMode == "IIS")
            {
                builder = WebHost.CreateDefaultBuilder(args)
                    .UseIIS()
                    .UseIISIntegration()
                    .UseStartup<Startup>();
            }
            else if (runMode == "Kestrel")
            {
                builder = WebHost.CreateDefaultBuilder(args)
                    .ConfigureKestrel((context, option) =>
                    {
                        option.Listen(System.Net.IPAddress.Any, 80, (cfg) =>
                        {
                            // 根據需要使用https
                            // cfg.UseHttps(caPath,caPsd);
                        });
                    })
                    .UseKestrel()
                    .UseStartup<Startup>();
            }
            else if (runMode == "Service")
            {
                builder = WebHost.CreateDefaultBuilder(args)
                    .ConfigureLogging((hostingContext, logging) =>
                    {
                        logging.AddEventLog();
                    })
                    .ConfigureAppConfiguration((context, config) =>
                    {
                        // Configure the app here.
                    })
                    .ConfigureKestrel((context, option) =>
                    {
                        option.Listen(System.Net.IPAddress.Any, 80, (cfg) =>
                        {
                            // 根據需要使用https
                            // cfg.UseHttps(caPath,caPsd);
                        });
                    })
                    .UseKestrel()
                    .UseStartup<Startup>();
            }

            return builder;
        }
    }

這裏如果選擇了Kestrel+反向代理,而且反向代理已經設置了https,那麼代碼裏千萬不要再UseHttps,這樣相當於進行了兩次https加解密操作,親測會損耗比較可觀的性能。

操作系統相關

Windows VS Linux

衆所周知,Linux上是沒有IIS這種東西的,以上關於託管宿主的討論僅針對Windows系統。對於Linux系統下,首先根據需求選擇部署模式(獨立 or 框架依賴),然後宿主的話只能選Kestrel。如果是內網應用就沒必要裝反向代理了,如果是外網應用就需要用反向代理 + Kestrel + Linux服務的操作了,Linux Service和Windows Service的作用一樣,都是爲了使應用開機自啓。
這裏放上Asp.net core在Linux上的安裝教程(可選裝SDK或者只裝運行時)。
安裝 .net core SDK
https://dotnet.microsoft.com/learn/dotnet/hello-world-tutorial/install
僅安裝 .net core 運行時
https://dotnet.microsoft.com/download/linux-package-manager/centos7/runtime-current
Nginx反向代理 + Kestrel + Linux Service教程
https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.2

如果這篇文章有幸能幫助到你,請不要吝嗇你的贊。

參考文獻
https://docs.microsoft.com/zh-cn/dotnet/core/deploying/
https://www.cnblogs.com/savorboard/p/dotnet-benchmarks.html#asp.net-core-vs-asp.net-corekestrel-vs-iis
https://dotnet.microsoft.com/learn/dotnet/hello-world-tutorial/install
https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.2

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章