commit 8e5b7255d973e4b2a9d8e9973092dba6c69f95b5 Author: Andreas Billmann Date: Sat May 14 11:59:01 2022 +0200 Initial commit diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..13cda3b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base +WORKDIR /app +EXPOSE 80 + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["StickySessionHelperExample/StickySessionHelperExample.csproj", "StickySessionHelperExample/"] +RUN dotnet restore "StickySessionHelperExample/StickySessionHelperExample.csproj" +COPY . . +WORKDIR "/src/StickySessionHelperExample" +RUN dotnet build "StickySessionHelperExample.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "StickySessionHelperExample.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "StickySessionHelperExample.dll"] \ No newline at end of file diff --git a/StickySessionHelperExample.sln b/StickySessionHelperExample.sln new file mode 100644 index 0000000..29256c2 --- /dev/null +++ b/StickySessionHelperExample.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StickySessionHelperExample", "StickySessionHelperExample\StickySessionHelperExample.csproj", "{52E90663-FD00-4800-94A2-04879DEA6731}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {52E90663-FD00-4800-94A2-04879DEA6731}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52E90663-FD00-4800-94A2-04879DEA6731}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52E90663-FD00-4800-94A2-04879DEA6731}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52E90663-FD00-4800-94A2-04879DEA6731}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/StickySessionHelperExample/PodWatcher.cs b/StickySessionHelperExample/PodWatcher.cs new file mode 100644 index 0000000..69664d1 --- /dev/null +++ b/StickySessionHelperExample/PodWatcher.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections; +using System.Threading; +using System.Threading.Tasks; +using k8s; +using k8s.Models; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; + +namespace StickySessionHelperExample; + +public class PodWatcher : BackgroundService +{ + // thread safe list + public static ArrayList IpAdresses = ArrayList.Synchronized(new ArrayList()); + private readonly IConfiguration _configuration; + + public PodWatcher(IConfiguration configuration) + { + _configuration = configuration; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + var inCluster = _configuration.GetValue("IN_CLUSTER", false); + + var config = inCluster + ? KubernetesClientConfiguration.InClusterConfig() + : KubernetesClientConfiguration.BuildConfigFromConfigFile(); + + IKubernetes client = new Kubernetes(config); + + var kubernetesNamespace = _configuration.GetValue("K8S_NAMESPACE_TO_WATCH", "default"); + + var podlistResp = client.CoreV1.ListNamespacedPodWithHttpMessagesAsync(kubernetesNamespace, watch: true, cancellationToken: stoppingToken); + await foreach (var (type, item) in podlistResp.WatchAsync().WithCancellation(stoppingToken)) + { + Console.Write($"Event Pod {type} : {item.Metadata.Name} - {item.Status.Phase} - {item.Status.PodIP} ["); + foreach (var (key, value) in item.Metadata.Labels) + { + Console.Write($"{key}: {value}, "); + } + + Console.WriteLine("]"); + + switch (type) + { + case WatchEventType.Added: + IpAdresses.Add(item.Status.PodIP); + break; + case WatchEventType.Deleted: + case WatchEventType.Error: + IpAdresses.Remove(item.Status.PodIP); + break; + } + } + } +} \ No newline at end of file diff --git a/StickySessionHelperExample/Program.cs b/StickySessionHelperExample/Program.cs new file mode 100644 index 0000000..43be40d --- /dev/null +++ b/StickySessionHelperExample/Program.cs @@ -0,0 +1,47 @@ +using System; +using System.Diagnostics; +using System.Net; +using System.Net.Http; +using StickySessionHelperExample; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Yarp.ReverseProxy.Forwarder; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddHttpForwarder(); +builder.Services.AddHostedService(); + +var httpClient = new HttpMessageInvoker(new SocketsHttpHandler +{ + UseProxy = false, + AllowAutoRedirect = false, + AutomaticDecompression = DecompressionMethods.None, + UseCookies = false, + ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current) +}); +var transformer = HttpTransformer.Default; +var requestConfig = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) }; +Random rnd = new Random(); + +var app = builder.Build(); +app.UseRouting(); +app.UseEndpoints(endpoints => + endpoints.Map("/{**catch-all}", handler: async (HttpContext httpContext, IHttpForwarder forwarder) => + { + var ipAddressNumber = rnd.Next(0, PodWatcher.IpAdresses.Count); + var ipAddress = PodWatcher.IpAdresses[ipAddressNumber] as string; + Console.WriteLine($"SEND CALL TO {ipAddress}"); + + var error = await forwarder.SendAsync(httpContext, $"http://{ipAddress}/", + httpClient, requestConfig, transformer); + // Check if the operation was successful + if (error != ForwarderError.None) + { + var errorFeature = httpContext.GetForwarderErrorFeature(); + var exception = errorFeature.Exception; + } + }) +); + +app.Run(); \ No newline at end of file diff --git a/StickySessionHelperExample/Properties/launchSettings.json b/StickySessionHelperExample/Properties/launchSettings.json new file mode 100644 index 0000000..028a6d9 --- /dev/null +++ b/StickySessionHelperExample/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "StickySessionHelperExample": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7018;http://localhost:5018", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/StickySessionHelperExample/StickySessionHelperExample.csproj b/StickySessionHelperExample/StickySessionHelperExample.csproj new file mode 100644 index 0000000..a4e11f7 --- /dev/null +++ b/StickySessionHelperExample/StickySessionHelperExample.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + + + + + + + + diff --git a/StickySessionHelperExample/appsettings.Development.json b/StickySessionHelperExample/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/StickySessionHelperExample/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/StickySessionHelperExample/appsettings.json b/StickySessionHelperExample/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/StickySessionHelperExample/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +}