在 kubernetes 的 asp.net 个核心容器中登录 reset/lost
Login reset/lost in asp.net core containers in kubernetes
容器的新手并在将近十年后回到 asp.net,我认为这已经在某处得到解答,但似乎无法找到它!
我在 3 个节点上有一个简单的 asp.net 应用程序 运行,登录显然是每个节点的,并且当请求由不同的节点提供服务时会丢失。我以为会有分布式会话管理教程,但这里很短,任何 pointers/how-to ?
仅供参考 - 目前在开发中,但针对 public 面向云的解决方案 azure/linode/...
运行 3 pods
下面附上configuration/logging资料
Redis 在本地主机上工作 - 不在 docker 容器中
行为如下
- 假设用户登录到 pod1,每当请求到达 pod1 时,它显示已登录,
- 如果请求命中pod2/pod3,则显示未登录!!!
似乎还需要其他东西才能使会话使用 redis !!!
public void ConfigureServices(IServiceCollection services)
{
var cx = Configuration["RedisCache:ConnectionString"];
var redis = ConnectionMultiplexer.Connect(cx);
services.AddDataProtection().PersistKeysToStackExchangeRedis(redis, "DataProtectionKeys");
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(20);
});
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseDeveloperExceptionPage();
//app.UseExceptionHandler("/Error");
app.UseHsts();
}
if (env.IsDevelopment())
{
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// Adds session middleware to pipeline
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
APPSETTINGS.JSON
{
"ConnectionStrings": {
"DefaultConnection": "Server=host.docker.internal;Database=SAMPLE;Trusted_Connection=false;user id=XXX;password=XXX;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"RedisCache": {
"ConnectionString": "host.docker.internal:6379,ssl=True,abortConnect=False"
},
"AllowedHosts": "*"
}
我在 Index.cshtml.cs
中有以下日志记录信息
public void OnGet()
{
var str = $"({Environment.MachineName}) || {HttpContext.Session.Id} || {DateTime.UtcNow.ToString("hh:mm:ss")}: Current({User.Identity.Name})";
_logger.LogWarning(str);
string sessionKey = "testKey1";
HttpContext.Session.SetString(sessionKey, str);
}
使用当前代码,会话存储在本地,因此每次负载均衡器重定向到新 pod 时,您将丢失先前请求的任何上下文。
您必须启用分布式缓存,以便在您的服务器应用程序的多个实例之间共享会话。参见 IDistributedCache interface
您还必须确保所有应用程序实例 shared the same keys for Data Protection related workflows.
这是一个使用 Redis 作为 DistributedCache 的工作示例:
public void ConfigureServices(IServiceCollection services)
{
// ensure that several instances of the same application can share their session
services.AddDataProtection()
.SetApplicationName("myapp_session")
.PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect("redis:6379,password=cE3nNEXHmvGCwdq7jgcxxxxxxxxxx"),
"DataProtection-Keys");
services.AddControllersWithViews();
// add distributed caching based on Redis
services.AddStackExchangeRedisCache(action => {
action.InstanceName = "redis";
action.Configuration = "redis:6379,password=cE3nNEXHmvGCwdq7jgcxxxxxxxxxx";
});
services.AddSession(options => {
options.Cookie.Name = "myapp_session";
options.IdleTimeout = TimeSpan.FromMinutes(60 * 24);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseSession();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
这里是对应的csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="5.0.3" />
</ItemGroup>
</Project>
此处提供完整示例:https://github.com/Query-Interface/SO-Answers/tree/master/dotNET/AspWithSessionOnMultipleNodes
另一种选择是在您的 Kubernetes 服务中启用 SessionAffinity。它允许 LoadBalancer 将来自一个客户端的流量始终指向同一个 Pod。它可以帮助您,但不建议这样做,因为一旦 Pod 被删除(失败的 Pod 或由于缩放操作),LoadBalancer 将无法将您的请求路由到该特定的 Pod。在这个问题中有解释:
容器的新手并在将近十年后回到 asp.net,我认为这已经在某处得到解答,但似乎无法找到它! 我在 3 个节点上有一个简单的 asp.net 应用程序 运行,登录显然是每个节点的,并且当请求由不同的节点提供服务时会丢失。我以为会有分布式会话管理教程,但这里很短,任何 pointers/how-to ?
仅供参考 - 目前在开发中,但针对 public 面向云的解决方案 azure/linode/... 运行 3 pods
下面附上configuration/logging资料
Redis 在本地主机上工作 - 不在 docker 容器中
行为如下
- 假设用户登录到 pod1,每当请求到达 pod1 时,它显示已登录,
- 如果请求命中pod2/pod3,则显示未登录!!!
似乎还需要其他东西才能使会话使用 redis !!!
public void ConfigureServices(IServiceCollection services)
{
var cx = Configuration["RedisCache:ConnectionString"];
var redis = ConnectionMultiplexer.Connect(cx);
services.AddDataProtection().PersistKeysToStackExchangeRedis(redis, "DataProtectionKeys");
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(20);
});
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseMigrationsEndPoint();
}
else
{
app.UseDeveloperExceptionPage();
//app.UseExceptionHandler("/Error");
app.UseHsts();
}
if (env.IsDevelopment())
{
app.UseHttpsRedirection();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
// Adds session middleware to pipeline
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
APPSETTINGS.JSON
{
"ConnectionStrings": {
"DefaultConnection": "Server=host.docker.internal;Database=SAMPLE;Trusted_Connection=false;user id=XXX;password=XXX;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"RedisCache": {
"ConnectionString": "host.docker.internal:6379,ssl=True,abortConnect=False"
},
"AllowedHosts": "*"
}
我在 Index.cshtml.cs
中有以下日志记录信息public void OnGet()
{
var str = $"({Environment.MachineName}) || {HttpContext.Session.Id} || {DateTime.UtcNow.ToString("hh:mm:ss")}: Current({User.Identity.Name})";
_logger.LogWarning(str);
string sessionKey = "testKey1";
HttpContext.Session.SetString(sessionKey, str);
}
使用当前代码,会话存储在本地,因此每次负载均衡器重定向到新 pod 时,您将丢失先前请求的任何上下文。
您必须启用分布式缓存,以便在您的服务器应用程序的多个实例之间共享会话。参见 IDistributedCache interface
您还必须确保所有应用程序实例 shared the same keys for Data Protection related workflows.
这是一个使用 Redis 作为 DistributedCache 的工作示例:
public void ConfigureServices(IServiceCollection services)
{
// ensure that several instances of the same application can share their session
services.AddDataProtection()
.SetApplicationName("myapp_session")
.PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect("redis:6379,password=cE3nNEXHmvGCwdq7jgcxxxxxxxxxx"),
"DataProtection-Keys");
services.AddControllersWithViews();
// add distributed caching based on Redis
services.AddStackExchangeRedisCache(action => {
action.InstanceName = "redis";
action.Configuration = "redis:6379,password=cE3nNEXHmvGCwdq7jgcxxxxxxxxxx";
});
services.AddSession(options => {
options.Cookie.Name = "myapp_session";
options.IdleTimeout = TimeSpan.FromMinutes(60 * 24);
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseSession();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
这里是对应的csproj:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="5.0.1" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="5.0.3" />
</ItemGroup>
</Project>
此处提供完整示例:https://github.com/Query-Interface/SO-Answers/tree/master/dotNET/AspWithSessionOnMultipleNodes
另一种选择是在您的 Kubernetes 服务中启用 SessionAffinity。它允许 LoadBalancer 将来自一个客户端的流量始终指向同一个 Pod。它可以帮助您,但不建议这样做,因为一旦 Pod 被删除(失败的 Pod 或由于缩放操作),LoadBalancer 将无法将您的请求路由到该特定的 Pod。在这个问题中有解释: