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

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

.net 7.0 kestrel appsettings.json configuration for unix sockets

问题

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

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

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

在搜索了很多小时的互联网,包括SO、Microsoft Learn和许多博客之后,似乎找不到如何在appsettings.json中配置Kestrel以在特定套接字路径上监听Unix套接字的文档。

有人知道如何使用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()时给Kestrel提供的IConfigurationSection是该特定部分即可。

注意:

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.html
匿名

发表评论

匿名网友

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

确定