Discovery-First Config - Cannot completely disable Eureka
See original GitHub issueDescribe the bug
A microservice deployed on Kubernetes throws an incorrect exception on startup. A check against Eureka:Client:ServiceUrl
is performed even if eureka is disabled (i.e. Eureka:Client:ShouldRegisterWithEureka
and Eureka:Client:ShouldFetchRegistry
are both false
). I’ve also set Spring:Cloud:Config:Discovery:Enabled
to false
just to avoid the eureka client being injected but the result is the same, the application keeps crashing. The only way to fix it is to overwrite the Eureka:Client:ServiceUrl
specifying a url that does not contain localhost.
This is the log from the application Pod:
System.InvalidOperationException: Eureka URL http://localhost:8761/eureka/ is not valid in containerized or cloud environments. Please configure Eureka:Client:ServiceUrl with a non-localhost address or add a service binding.
at Steeltoe.Discovery.Eureka.EurekaPostConfigurer.UpdateConfiguration(IConfiguration config, EurekaServiceInfo si, EurekaClientOptions clientOptions)
at Steeltoe.Discovery.Eureka.EurekaDiscoveryClientExtension.<>c__DisplayClass9_0.<ConfigureEurekaServices>b__0(EurekaClientOptions options)
at Microsoft.Extensions.Options.PostConfigureOptions`1.PostConfigure(String name, TOptions options)
at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
at Microsoft.Extensions.Options.OptionsMonitor`1.<>c__DisplayClass11_0.<Get>b__0()
at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
at System.Lazy`1.CreateValue()
at System.Lazy`1.get_Value()
at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd(String name, Func`1 createOptions)
at Microsoft.Extensions.Options.OptionsMonitor`1.Get(String name)
at Microsoft.Extensions.Options.OptionsMonitor`1.get_CurrentValue()
at Steeltoe.Discovery.Eureka.EurekaDiscoveryClient.EurekaHttpClientInternal.get_Config()
at Steeltoe.Discovery.Eureka.Transport.EurekaHttpClient.Initialize(IDictionary`2 headers, ILoggerFactory logFactory)
at Steeltoe.Discovery.Eureka.EurekaDiscoveryClient.EurekaHttpClientInternal..ctor(IOptionsMonitor`1 config, ILoggerFactory logFactory, IHttpClientHandlerProvider handlerProvider)
at Steeltoe.Discovery.Eureka.EurekaDiscoveryClient..ctor(IOptionsMonitor`1 clientConfig, IOptionsMonitor`1 instConfig, EurekaApplicationInfoManager appInfoManager, IEurekaHttpClient httpClient, ILoggerFactory logFactory, IHttpClientHandlerProvider handlerProvider)
--- End of stack trace from previous location where exception was thrown ---
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider provider)
at Steeltoe.Discovery.Eureka.EurekaDiscoveryClientExtension.<>c.<AddEurekaServices>b__10_0(IServiceProvider p)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Steeltoe.Discovery.Client.DiscoveryApplicationBuilderExtensions.UseDiscoveryClient(IApplicationBuilder app)
at MyService.Startup.Configure(IApplicationBuilder app, IHostEnvironment env) in /app/Startup.cs:line 177
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.<Build>b__0(IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass13_0.<UseStartup>b__2(IApplicationBuilder app)
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.<Configure>g__MiddlewareFilterBuilder|0(IApplicationBuilder builder)
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.<Configure>b__0(IApplicationBuilder app)
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
Steps to reproduce
Steps to reproduce the behavior:
- deploy a config-server instance on a Kubernetes cluster (it should be accesible from a service named “config-server” at port 8888)
- create an aspnetcore 3.1 application with the following specs:
Project dependencies:
<PackageReference Include="Steeltoe.Discovery.ClientCore" Version="3.0.2" />
<PackageReference Include="Steeltoe.Discovery.Eureka" Version="3.0.2" />
<PackageReference Include="Steeltoe.Discovery.Kubernetes" Version="3.0.2" />
<PackageReference Include="Steeltoe.Extensions.Configuration.ConfigServerCore" Version="3.0.2" />
<PackageReference Include="Steeltoe.Extensions.Configuration.KubernetesCore" Version="3.0.2" />
<PackageReference Include="Steeltoe.Management.EndpointBase" Version="3.0.2" />
<PackageReference Include="Steeltoe.Management.EndpointCore" Version="3.0.2" />
<PackageReference Include="Steeltoe.Management.KubernetesCore" Version="3.0.2" />
Application code:
namespace Test
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var startupLoggerFactory = new LoggerFactory().AddConsole();
return Host.CreateDefaultBuilder(args)
.AddKubernetesConfiguration(null, startupLoggerFactory)
.AddConfigServer(startupLoggerFactory)
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>());
}
}
public class Startup
{
private IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddDiscoveryClient(Configuration);
}
public void Configure(IApplicationBuilder app)
{
app.UseDiscoveryClient();
}
}
}
Application configuration:
//appsettings.json
{
"Spring": {
"Cloud": {
"Config": {
"Discovery": {
"Enabled": true,
"ServiceId": "config-server"
},
"FailFast": true
},
"Kubernetes": {
"Enabled": false
}
}
},
"Eureka": {
"Client": {
"ServiceUrl": "http://localhost:8761/eureka/"
}
}
}
//appsettings.Kubernetes.json
{
"Spring": {
"Cloud": {
"Config": {
"Uri": "http://config-server:8888",
"Discovery": {
"Enabled": false
}
},
"Kubernetes": {
"Enabled": true
}
}
},
"Eureka": {
"Client": {
"ShouldRegisterWithEureka": false,
"ShouldFetchRegistry": false
}
}
}
- deploy the aspnetcore microservice on kubernetes and set
ASPNETCORE_ENVIRONMENT=Kubernetes
Expected behavior
I would like to be able to disable the eureka client completely to avoid application startup crashes if eureka-server is not deployed in Kubernetes (and it probably won’t be due to native service discovery capabilities). Spring allows to disable eureka completely using the following property in the application.yml:
eureka:
client:
enabled: false
To disable the Eureka Discovery Client, you can set eureka.client.enabled to false. Eureka Discovery Client will also be disabled when spring.cloud.discovery.enabled is set to false.
I would like to have the same option to disable any Eureka integration (discovery, health check, etc…) through configuration thus skipping any check for incorrect eureka client configurations or errors due to missing eureka-server.
Note: I have multiple configuration to support multiple deployments so I cannot simply remove the eureka dependency from the project.
Environment:
- Steeltoe Version: 3.0.2
- Platform: Kubernetes (Client Version: v1.18.1, Server Version: v1.19.7)
- OS: Windows (Minikube)
- .NET Version: .NET Core 3.1
Additional context or links
Issue Analytics
- State:
- Created 2 years ago
- Comments:6 (6 by maintainers)
Top GitHub Comments
@DaviGia if the original complaint (Eureka appears active when it shouldn’t be) is still present then we need to get to the bottom of that to determine if there’s a bug to fix (I think you’ve provided enough info, somebody just needs to find the time to look into it). The additional settings would technically be an enhancement, but I don’t feel strongly about needing to separate the two items at this time.
edit: the labels aren’t exclusive, why not both?
@DaviGia sorry for the delay and bummer of an answer here, but I missed the key to the problem:
"Spring:Cloud:Config:Discovery:Enabled": true
. Which is valid, I was just looking at the Discovery code and not thinking about discovery-first Config Server…The reason this is the key is twofold:
Note that currently we only support Netflix Eureka
So… it looks like we already needed to completely re-implement ConfigServerDiscoveryService anyway, and what you’re seeing is just symptoms of a larger problem