.net 7.0 kestrel appsettings.json 配置用于 Unix 套接字

huangapple go评论87阅读模式
英文:

.net 7.0 kestrel appsettings.json configuration for unix sockets

问题

我有一个用C#编写的开源服务应用程序,运行在.NET 7上,部署在Linux上,它使用Kestrel暴露了一个HTTP服务,用于提供一些应用程序状态和重要监控指标的监控端点。它配置为在appsettings.json中监听TCP端点,这在需要的情况下是很好的。

我还希望Kestrel能够监听Unix套接字,用于反向代理设置等其他原因,而且要在特定路径上监听。

我可以在代码中相对容易地实现它,但我更愿意能够使用我的appsettings.json中Kestrel部分来配置它,就像对TCP套接字监听器所做的那样,这样应用程序的最终用户可以使用标准配置,而不是仅适用于此应用程序的特定设置,然后在代码中使用这些设置来使Kestrel监听所需的套接字路径。

关于如何做到这一点的文档似乎不存在,尽管我在网上搜寻了很多小时,包括Stack Overflow、Microsoft Learn和许多博客。

是否有人知道如何使用appsettings.json配置Kestrel以监听特定套接字路径上的Unix套接字?

以下是如何向Kestrel提供配置的方式:

public static Task Main(string[] args)
{
    // ...
    WebApplicationBuilder serviceBuilder = WebApplication.CreateBuilder();
    // ...
    serviceBuilder.WebHost
                  .UseKestrel(ConfigureKestrelOptions);
    // ...
}
      
private static void ConfigureKestrelOptions(WebHostBuilderContext builderContext, KestrelServerOptions kestrelOptions)
{
    kestrelOptions.Configure(_configurationRoot!.GetRequiredSection("Monitoring").GetSection("Kestrel"))
                  .Load();
}

一种尝试的配置如下:

{
  "Monitoring": {
    "Kestrel": {
      "AllowedHosts": "*",
      "Endpoints": {
        "HttpMonitoringEndpoint": {
          "Url": "http://*:60765"
        },
        "UnixSocketMonitoringEndpoint": {
          "SocketPath": "/run/myapp/monitor.sock"
        } 
      }
    }
  }
}

我还尝试将Unix套接字端点放在"UnixSocketEndpoints"或"UnixDomainSocketEndpoints"部分,而不是"Endpoints"部分。但这将导致Unix套接字被打开,但在一个随机的临时路径上,而不是指定的路径上。

英文:

I have an open-source service application written in c#, running on .net 7, on Linux, which exposes an HTTP service, using Kestrel, to provide some monitoring endpoints for application state and important metrics for monitoring the application. It is configured to listen on a TCP endpoint, in appsettings.json, and that's great for when that's the desired configuration.

I also want to have Kestrel be able to listen on unix sockets, for reverse-proxy setups, among other reasons, at a specific path.

I can do it in code, fairly easily, but I would prefer to be able to configure it using the Kestrel section of my appsettings.json, as is done for the TCP socket listener, so end-users of the application can use standard configuration, rather than settings specific to just this application, that then get consumed in code to make kestrel listen at the desired socket path.

Documentation on how to do that seems to be non-existent, after many hours of scouring the net, including SO, Microsoft Learn, and numerous blogs.

Does anybody know how to configure Kestrel to listen on unix sockets at a specific socket path using appsettings.json?

Here's how the configuration is being given to Kestrel:

public static Task Main(string[] args)
{
    // ...
    WebApplicationBuilder serviceBuilder = WebApplication.CreateBuilder( );
    // ...
    serviceBuilder.WebHost
			      .UseKestrel( ConfigureKestrelOptions );
    // ...
}
	  
private static void ConfigureKestrelOptions( WebHostBuilderContext builderContext, KestrelServerOptions kestrelOptions )
{
    kestrelOptions.Configure(_configurationRoot!.GetRequiredSection("Monitoring").GetSection("Kestrel") )
				  .Load( );
}

One attempted configuration was this:

{
  "Monitoring": {
    "Kestrel": {
      "AllowedHosts": "*",
      "Endpoints": {
        "HttpMonitoringEndpoint": {
          "Url": "http://*:60765"
        },
        "UnixSocketMonitoringEndpoint": {
          "SocketPath": "/run/myapp/monitor.sock"
        } 
      }
    }
  }
}

I have also tried putting the unix socket endpoint in a "UnixSocketEndpoints" and "UnixDomainSocketEndpoints" section, instead of "Endpoints." Those result in a unix socket being opened, but at a random temporary path, rather than the path specified.

答案1

得分: 1

在查看了GitHub上.NET 7.0.9的当前源代码并跟踪配置加载过程中的每个函数调用后,我弄清楚了需要做什么。

Kestrel配置的相关源文件如下:

首先,有KestrelServerOptions类,Kestrel使用它来进行代码配置以及可以提供IConfigurationSection给Kestrel的ConfigurationProviders。

随着代码的深入,您会意识到JSON中的“Endpoints”集合由EndpointConfiguration类的实例组成,它既表示可以在“Endpoints”部分的配置中定义的内容,也表示可以在代码中为抽象的“Endpoint”执行的内容。

所有Endpoint都有一个ListenOptions属性,定义了每个EndPoint条目可以具有的特定设置,如熟悉的选项UrlProtocols等。该属性的类型与同名的类型位于ListenOptions.cs中。

如果将所有这些结合起来并将这些类的结构应用于配置,您最终会得到类似以下内容的内容(也包括TCP端点以显示相似性):

{
  "Endpoints": {
    "HttpMonitoringEndpoint": {
      "Url": "http://*:60763"
    },
    "UnixSocketMonitoringEndpoint": {
      "Url": "http://unix:/path/to/my.sock"
    }
  }
}

这个配置可以工作,并在指定的Url上创建一个Unix套接字。

当然,这可以放在您的appsettings.json(或您加载的其他json文件)的任何部分,只要您在调用Configure()时将特定的IConfigurationSection提供给Kestrel即可。

注意:

KestrelConfigurationLoader的.NET代码将忽略unix:和第一个斜杠之间的任何内容。如果套接字路径没有根路径,您将收到异常。

您还必须确保套接字“文件”要放置的目录已经存在,否则您将收到此异常:

Unhandled exception. System.Net.Sockets.SocketException (99): Cannot assign requested address

关键是要注意,99是在libc中定义的errno值,即EADDRNOTAVAIL。

.NET不会为此为您创建任何目录,所以请确保您要放置套接字文件的目录已经存在,并且您的进程正在以适当的权限执行该目录的帐户/组。

英文:

After going over the current source code for .net 7.0.9, in github, following every function call during the loading of configuration, I figured out what needed to be done.

The relevant source files for kestrel configuration are these:

First, there's the KestrelServerOptions class, which Kestrel uses, both for configuration in code and from ConfigurationProviders that can provide IConfigurationSections to Kestrel.

Following the code around eventually leads you to realizing that the "Endpoints" collection in the JSON is made up of instances of the EndpointConfiguration class, which both represents what can be defined in configuration for items in the "Endpoints" section, as well as what can be done in code, for an abstract "Endpoint."

All Endpoints have a ListenOptions property, which defines the specific settings each EndPoint entry can have, such as the familiar options Url and Protocols, among others. That property is of a type with the same name, located in ListenOptions.cs.

If you combine all of that and apply how those classes are structured to the configuration, you end up with something like this (TCP endpoint also included to show similarity):

{
  "Endpoints": {
    "HttpMonitoringEndpoint": {
      "Url": "http://*:60763"
    },
    "UnixSocketMonitoringEndpoint": {
      "Url": "http://unix:/path/to/my.sock"
    }
  }
}

This works, and creates a unix socket at the specified Url.

This can, of course, be placed in any part of your appsettings.json (or other json file you load), so long as the IConfigurationSection you give to Kestrel, in the call to Configure() is that specific section.

Notes:

The .net code for the KestrelConfigurationLoader will ignore anything between the unix: and the first slash. If the socket path is not rooted, you'll get an exception.

You must also make sure the directory the socket file is going to be placed in already exists, or you'll get this exception:

Unhandled exception. System.Net.Sockets.SocketException (99): Cannot assign requested address

Key is to note that 99 is an errno value as defined in libc, which is EADDRNOTAVAIL.

.net will not create any directories for you, for this, so just be sure the directory you're placing the socket file in already exists and that the account/group your process is executing as has appropriate permissions to the directory.

huangapple
  • 本文由 发表于 2023年8月9日 09:29:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76864020-2.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定