docker - 在 kubernetes 中的 asp.net 核心容器中登录重置/丢失

标签 docker kubernetes asp.net-core-5.0

容器的新手,近十年后又回到了 asp.net,我认为这已经在某个地方得到了回答,但似乎无法找到它! 我有一个在 3 个节点上运行的简单 asp.net 应用程序,登录显然是每个节点,当请求由不同的节点提供服务时会丢失。我假设会有分布式 session 管理教程,但这里没有任何指示/操作方法?

仅供引用 - 目前处于开发阶段,但面向公众的云解决方案 azure/linode/... 运行 3 个 pod

配置/日志信息附在下面

Redis 在本地主机上工作 - 而不是在 docker 容器中

行为如下

  • 假设用户登录到 pod1,每当请求到达 pod1 时,它显示已登录,
  • 如果请求命中 pod2/pod3,则显示未登录!!!

看起来需要其他东西才能使 session 使用 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);
}

最佳答案

使用当前代码, session 存储在本地,因此每次负载均衡器重定向到新的 pod 时,您都将丢失先前请求的任何上下文。

您必须启用分布式缓存,以允许在您的服务器应用程序的多个实例之间共享 session 。参见 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。在这个问题中有解释:https://stackoverflow.com/questions/56323438

关于docker - 在 kubernetes 中的 asp.net 核心容器中登录重置/丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66091085/

相关文章:

python-3.x - Alpine Docker image FROM python :3. x-alpine3.x 使用与声明不同的 Python 包版本

windows - Windows 上的 kubectl diff 返回错误 : executable file not found in PATH

kubernetes - 如何为示例Istio应用程序公开外部IP地址

asp.net-core - 包 Microsoft.AspNetCore.Authentication.JwtBearer 5.0.0 与 netcoreapp3.1 不兼容,但它的目标是 net 5.0

c# - 从 .Net Core 3.1 升级到 .Net 5 后序列化和 MD5 哈希失败

docker - 在新的 Docker 镜像上自动重建 Openshift pod

azure - 使用azure应用程序网关的认证链中的问题

docker - 在 Gitlab 运行器中的 Docker 容器内运行测试命令时出现问题

c++ - curl_slist_free_all() 在带有 Debian 8.7 的 GKE 上导致段错误

c# - 如何使用我自己的自定义设计来自定义 swagger UI