DotNet 8 Minimal API with AOT (三): Ubuntu Server 生产环境部署

文章目录

    在使用 HTMX 调用 .NET 8 Minimal API 实现的接口后,这个小的练手项目就算是开发完了。现在需要部署到生产服务器上。

    编译

    > dotnet publish
    

    可执行文件的大小

    > ls bin/Release/net8.0/linux-x64/publish/ -lah
    total 32M
    4.0K  ./
    4.0K  ../
     11M  app*
     21M  app.dbg*
     127  appsettings.Development.json*
     151  appsettings.json*
    4.0K  wwwroot/
    

    app 就是生成的独立的可执行的二进制文件。只有 11M 大小。
    跟 golang gin 有得一拼了。

    静态文件无法嵌入

    唯一的问题是,wwwroot 下的静态文件,没法打包进最终的二进制文件中。

    我网上搜索了几个方案,都行不通。讨论的人也非常少。

    这点明显不如 golang 和 rust 的发布方便,可以灵活地配置是否将静态文件打包进去。

    不过,目前也能接受。毕竟目前的 DotNet 8 Minimal API with AOT 只是个半成品,我也没打算在大项目中使用。
    目前只在简单的小工具中使用。

    开发环境端口设置

    配置文件:

    Properties/launchSettings.json

    例如,我想改成 9029 端口,只需要修改下面的配置

    "applicationUrl": "http://localhost:9029",
    

    生产环境端口设置

    配置文件:

    appsettings.json

    比较有趣的是,执行 dotnet publish 之后,生成的 bin/Release/net8.0/linux-x64/publish 目录中,
    包含了两个配置文件:

    • appsettings.Development.json*
    • appsettings.json*

    这两个文件就是从项目根目录复制过来的。

    还是挺贴心的,方便内部测试和生产环境使用不同的配置文件。

    所以,要修改生产环境的端口,只需要修改配置文件 appsettings.json,增加 Kestrel 的配置:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "Kestrel": {
        "Endpoints": {
          "Http": {
            "Url": "http://localhost:9029"
          }
        }
      }
    }
    

    然后,执行 publish 目录中的可执行文件,就能看到端口号已经生效。

    > ./app
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: http://localhost:9029
    

    当然,还有好几种配置方法(例如,命令行参数,系统环境变量,代码里设置等),可以参考:

    https://stackoverflow.com/questions/70332897/how-to-change-default-port-no-of-my-net-core-6-api

    Kestrel 是什么

    Kestrel is a cross-platform web server for ASP.NET Core. Kestrel is the recommended server for ASP.NET Core, and it’s configured by default in ASP.NET Core project templates.

    Kestrel 是 ASP.NET Core 内置的 Web Server。

    但,Kestrel 是何时被引入的呢?

    var builder = WebApplication.CreateBuilder(args);
    var app = builder.Build();
    

    WebApplication.CreateBuilder 内部调用了 UseKestrel。

    而,我这里使用的 Minimal API with AOT,则使用的是:

    var builder = WebApplication.CreateSlimBuilder(args);
    

    CreateSlimBuilder 也调用了 UseKestrel,但是默认去掉了 HTTPS 和 HTTP3 支持。
    这是也是为什么,在 appsettings.json 中配置 HTTPS URL 时,在执行 dotnet publish 会报错的原因。

    Unhandled Exception: System.InvalidOperationException: Call UseKestrelHttpsConfiguration() on IWebHostBuilder to enable loading HTTPS settings from configuration.

    详细参考:

    https://andrewlock.net/exploring-the-dotnet-8-preview-comparing-createbuilder-to-the-new-createslimbuilder-method/

    Nginx 配置

    server {
        listen   80 default_server;
    
        location / {
            proxy_pass         http://127.0.0.1:9029;
            proxy_http_version 1.1;
            proxy_set_header   Upgrade $http_upgrade;
            proxy_set_header   Connection keep-alive;
            proxy_set_header   Host $host;
            proxy_cache_bypass $http_upgrade;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto $scheme;
        }
    }
    

    如何要实现 Nginx 配置文件中请求路径 /prefix/api_a,但是转发给本地的 .Net 服务,去掉 /prefix 前缀:

    location /prefix/ {
        proxy_pass http://localhost:9029/;
    	...
    }
    

    查看进程占用的内存

    使用 top 命令,然后按下大写 M,按照使用内存排序。

    VIRT    RES    SHR   S  %CPU  %MEM   COMMAND
    4872968 1.0g   20056 S   0.0  13.0   java
    2940928 805824 13696 S   1.7   9.9   mysqld
    259.5g  24064  12032 S   0.0   0.3   NetServerTool
    

    会看到这个 .NET AOT 程序,占用内存 24M。
    但是比较诡异的是虚拟内存占了 260G …
    按照 github 上的讨论,这没有什么问题。。。只是方便 GC 使用。(即便是 AOT 模式,也是有 GC 的)

    https://github.com/dotnet/runtime/issues/9199

    继续阅读 📚

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式