sin*_*yil 1 environment-variables docker kubernetes asp.net-core
我目前正在开发一个在 Kubernetes 上使用 .NET Core 2.1 运行的项目。我的应用程序从文件和环境变量中读取配置值appsettings.json。
问题是当我尝试从接口读取配置时IConfiguration,“大多数时候”值返回 null,但仅限于 Kubernetes。它在我的开发机器和带有 Windows VM 和 IIS 的测试机器上完美运行。这些环境之间的区别在于开发和测试机器是 Windows,但生产是在 Linux 容器上运行的 Kubernetes(基于microsoft/dotnet:2.1-aspnetcore-runtime映像)以及我如何实现环境变量。在我的开发机器中没有定义环境变量。web.config在 Windows VM 中,我确实通过如下条目使用环境变量:
<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout">
<environmentVariables>
<environmentVariable name="Site:SiteId" value="1" />
<environmentVariable name="Site:Theme" value="MyTheme" />
</environmentVariables>
</aspNetCore>
Run Code Online (Sandbox Code Playgroud)
我用于WebHost.CreateDefaultBuilder()配置和文档说方法实现了appsettings.json配置appsettings.{EnvironmentName}.json源的环境变量和命令行参数。
我的appsettings.json文件:
{
"Site": {
"SiteId": 1,
"Theme": "Limitless"
},
"RemoteClient": {
"HostUrl": "http://localhost:59554/management/",
"AppKey": "test",
"AppSecret": "1"
}
}
Run Code Online (Sandbox Code Playgroud)
最后是我的 Kubernetes 部署文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 1
selector:
matchLabels:
component: myapp
strategy: {}
template:
metadata:
labels:
component: myapp
spec:
nodeSelector:
beta.kubernetes.io/os: linux
containers:
- image: 'myregistry/myapp:latest'
imagePullPolicy: IfNotPresent
name: myapp
env:
- name: "Site__SiteId"
value: "1"
- name: "Site__Theme"
value: "Limitless"
- name: "RemoteClient__HostUrl"
value: "http://apphost/management"
- name: "RemoteClient__AppKey"
value: e824b2670e644824bdd5cdee1db9bd4b
- name: "RemoteClient__AppSecret"
value: 12d4deadf948
- name: "ASPNETCORE_ENVIRONMENT"
value: Production
ports:
- containerPort: 80
restartPolicy: Always
Run Code Online (Sandbox Code Playgroud)
我说的是“大多数时候”,因为每次 Pod 重新启动时它的行为都会有所不同。有时它读取一个变量而不读取其他变量,有时它读取其余变量,最终它可以读取所有变量并且应用程序正常运行。你可以在kubectl describe pod输出中看到
但是当我从服务读取值IConfiguration并将其输出到控制台时,输出如下所示:
以及其他重启
在这两次运行之间我没有改变任何东西,它只是重新启动。它没有读取值,甚至没有读取 appsettings.json 中定义的默认值。
那么您认为为什么会发生这种情况?
编辑:
我正在使用此代码块进行初始配置,CreateDefaultBuilder()负责配置。
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.AddPreConfigureServices();
Run Code Online (Sandbox Code Playgroud)
和注释CreateDefaultBinder():
//
// Summary:
// Initializes a new instance of the Microsoft.AspNetCore.Hosting.WebHostBuilder
// class with pre-configured defaults.
//
// Parameters:
// args:
// The command line args.
//
// Returns:
// The initialized Microsoft.AspNetCore.Hosting.IWebHostBuilder.
//
// Remarks:
// The following defaults are applied to the returned Microsoft.AspNetCore.Hosting.WebHostBuilder:
// use Kestrel as the web server and configure it using the application's configuration
// providers, set the Microsoft.AspNetCore.Hosting.IHostingEnvironment.ContentRootPath
// to the result of System.IO.Directory.GetCurrentDirectory, load Microsoft.Extensions.Configuration.IConfiguration
// from 'appsettings.json' and 'appsettings.[Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName].json',
// load Microsoft.Extensions.Configuration.IConfiguration from User Secrets when
// Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName is 'Development'
// using the entry assembly, load Microsoft.Extensions.Configuration.IConfiguration
// from environment variables, load Microsoft.Extensions.Configuration.IConfiguration
// from supplied command line args, configures the Microsoft.Extensions.Logging.ILoggerFactory
// to log to the console and debug output, enables IIS integration, and enables
// the ability for frameworks to bind their options to their default configuration
// sections.
public static IWebHostBuilder CreateDefaultBuilder(string[] args);
Run Code Online (Sandbox Code Playgroud)
编辑2:
像这样读取我的值Startup.cs:
services.AddMvc(options => { })
.AddEntityBinders()
.AddRazorOptions(options =>
{
string theme = Configuration["Site:Theme"];
options.ViewLocationFormats.Clear();
options.ViewLocationFormats.Add($"~/Views/{theme}Theme/{{1}}/{{0}}.cshtml");
options.ViewLocationFormats.Add($"~/Views/{theme}Theme/Shared/{{0}}.cshtml");
})
.SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_1);
Run Code Online (Sandbox Code Playgroud)
经过漫长而困难的调试过程。我终于可以找出问题所在了。
.Net Core 使用:配置键分隔符,但 Kubernetes 配置文件在命名环境变量时不支持此类字符。EnvironmentVariablesConfigurationProvider通过接受作为分隔符并在读取值时__替换为来解决此问题。:
因此,我在 Kubernetes 部署文件中使用 __ 分隔符声明环境变量(如上所示)。但 Dockerfile 没有这个问题,我用:分隔符编写 ENV 定义(如下),这会创建重复的变量,.Net Core 会读取所有这些变量并产生不稳定的结果。
ENV RemoteClient:HostUrl ${HOST_URL}
ENV RemoteClient:AppKey ${APP_KEY}
ENV RemoteClient:AppSecret ${APP_SECRET}
ENV ASPNETCORE_ENVIRONMENT ${ENVIRONMENT_NAME}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1780 次 |
| 最近记录: |