Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] Different behaviour kubernetes-client-config / kubernetes-client-all #1654

Closed
UnleashSpirit opened this issue May 15, 2024 · 11 comments · Fixed by #1655
Closed

[QUESTION] Different behaviour kubernetes-client-config / kubernetes-client-all #1654

UnleashSpirit opened this issue May 15, 2024 · 11 comments · Fixed by #1655
Labels
Milestone

Comments

@UnleashSpirit
Copy link

Hi, i know this is more for issue or feature than help wanted

We recenlty try to migrate from spring boot 2.6.6 to 3.2.5 (yeah big jump)
Our apps running on kubernetes and are package without any application.[yml|yaml|properties]
At startup it picks up the configMap base on the SPRING_APPLICATION_NAME, it's the bootstrap way which is now deprecated (at least legacy and no more the default).

To keep this behaviour we use (with bootstrap false)
SPRING_CONFIG_IMPORT = kubernetes:

We are using the

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-kubernetes-client-all</artifactId>
</dependency>

Keeping this deps giving us this error

17:16:49.226 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
java.lang.NullPointerException: Cannot invoke "org.springframework.cloud.kubernetes.commons.KubernetesClientProperties.withNamespace(String)" because the return value of "org.springframework.boot.ConfigurableBootstrapContext.get(java.lang.Class)" is null
	at org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver$PropertyHolder.clientProperties(KubernetesConfigDataLocationResolver.java:180)
	at org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver$PropertyHolder.of(KubernetesConfigDataLocationResolver.java:167)
	at org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver.resolveProfileSpecific(KubernetesConfigDataLocationResolver.java:89)
	at org.springframework.boot.context.config.ConfigDataLocationResolvers.lambda$resolve$2(ConfigDataLocationResolvers.java:107)
	at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:113)
	at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:106)
	at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:94)
	at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:106)
	at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:98)
	at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
	at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:115)
	at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:313)
	at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:234)
	at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96)
	at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89)
	at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:109)
	at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:94)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
	at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
	at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
	at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81)
	at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64)
	at java.base/java.lang.Iterable.forEach(Unknown Source)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
	at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
	at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63)
	at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:369)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:329)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
	at foo.bar.Application.main(Application.java:19)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91)
	at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53)
	at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:58)

Switching to

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-kubernetes-client-config</artifactId>
</dependency>

Works as expected

And we can't figure out why
Any ideas ? :(

@ryanjbaxter
Copy link
Contributor

Can you provide a complete, minimal, verifiable sample that reproduces the problem? It should be available as a GitHub (or similar) project or attached to this issue as a zip file.

@UnleashSpirit
Copy link
Author

Hello,

Here the zip. It includes the Dockerfile I use to build the app
demo.zip

Here the kube deployment used :

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
        - name: demo
          image: "harbor.local/demo:latest" 
          imagePullPolicy: Always
          resources:
            limits:
              cpu: 250m
              memory: 512Mi
            requests:
              cpu: 50m
              memory: 512Mi
          env:
            - name: SPRING_APPLICATION_NAME
              value: demo
          ports:
          - name: webservice
            containerPort: 9090
            protocol: TCP

No matter the configMap as it's never read, NPE before

@wind57
Copy link
Contributor

wind57 commented May 16, 2024

The problem is indeed there, I can re-produce it. Thank you for the sample.

Indeed the dependencies are to be blamed here. I am going to dig a little bit more, so that my conclusions are not vague and will update this post once I am done.

@wind57
Copy link
Contributor

wind57 commented May 16, 2024

To me : this is a bug.

@ryanjbaxter I'll try to explain what is going on, so please advise with your input.

Since OP is having this dependency:

spring-cloud-starter-kubernetes-client-all

this will bring spring-cloud-kubernetes-client-discovery and spring-cloud-kubernetes-client-config.

Because of the first one, we will trigger KubernetesClientConfigServerBootstrapper, that in its initialize method has such code:

		registry.registerIfAbsent(KubernetesClientProperties.class, context -> {
			if (!getDiscoveryEnabled(context)) {
				return null;
			}
			return createKubernetesClientProperties(context);
		});

since discovery is not enabled, we will return null here.

After that, we will trigger KubernetesConfigDataLocationResolver that in the clientProperties has such code:

			if (context.getBootstrapContext().isRegistered(KubernetesClientProperties.class)) {
				kubernetesClientProperties = context.getBootstrapContext().get(KubernetesClientProperties.class)
						.withNamespace(namespace);
			}

Now because KubernetesClientProperties is registered, we will call context.getBootstrapContext().get(KubernetesClientProperties.class) that will return a null, thus the error that OP sees.


We are returning null there in the sense that "I don't care about these properties, since I am not going to use them anyway, because discovery is not enabled". At least this is how I understood the code.

If that is indeed the case, we can still bind (create) them, with defaults and other properties that are present for them. Much like we do in KubernetesConfigDataLocationResolver when such a class is not regsitered:

if (context.getBootstrapContext().isRegistered(KubernetesClientProperties.class)) {
				kubernetesClientProperties = context.getBootstrapContext().get(KubernetesClientProperties.class)
						.withNamespace(namespace);
			}
			else {
				kubernetesClientProperties = context.getBinder()
						.bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(KubernetesClientProperties.class))
						.withNamespace(namespace);
			}

specifically in the else part:

.bindOrCreate(KubernetesClientProperties.PREFIX, Bindable.of(KubernetesClientProperties.class))

@wind57
Copy link
Contributor

wind57 commented May 16, 2024

I have a proposal for a fix here and I tested it against the OPs sample.

@ryanjbaxter
Copy link
Contributor

I guess I am wondering why we are even registering KubernetesClientProperties in KubernetesClientConfigServerBootstrapper. We don't even seem to use it when we register ConfigServerInstanceProvider.Function.

@wind57
Copy link
Contributor

wind57 commented May 17, 2024

ha! you're right, I've updated the PR to remove it.

@ryanjbaxter ryanjbaxter linked a pull request May 17, 2024 that will close this issue
@ryanjbaxter ryanjbaxter added this to the 3.1.2 milestone May 17, 2024
@github-project-automation github-project-automation bot moved this to Done in 2023.0.2 May 17, 2024
@UnleashSpirit
Copy link
Author

Hello guys, thanks for the reactivity :)

I see 3.1.2 and spring-cloud-dependencies 2023.0.2
How can I know/estimate the release date please ?

@ryanjbaxter
Copy link
Contributor

No problem!

You can always view tentative release dates here https://github.com/spring-cloud/spring-cloud-release/milestones

@davgia
Copy link

davgia commented Jan 10, 2025

Hi everyone,

I have the same error:

16:59:39.496 [main] ERROR org.springframework.boot.SpringApplication -- Application run failed
java.lang.NullPointerException: Cannot invoke "org.springframework.cloud.kubernetes.commons.KubernetesClientProperties.withNamespace(String)" because the return value of "org.springframework.boot.ConfigurableBootstrapContext.get(java.lang.Class)" is null
    at org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver$PropertyHolder.clientProperties(KubernetesConfigDataLocationResolver.java:181)
    at org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver$PropertyHolder.of(KubernetesConfigDataLocationResolver.java:167)
    at org.springframework.cloud.kubernetes.commons.config.KubernetesConfigDataLocationResolver.resolveProfileSpecific(KubernetesConfigDataLocationResolver.java:89)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.lambda$resolve$2(ConfigDataLocationResolvers.java:107)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:113)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:106)
    at org.springframework.boot.context.config.ConfigDataLocationResolvers.resolve(ConfigDataLocationResolvers.java:94)
    at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:106)
    at org.springframework.boot.context.config.ConfigDataImporter.resolve(ConfigDataImporter.java:98)
    at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
    at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:121)
    at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:316)
    at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:237)
    at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:96)
    at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:89)
    at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:132)
    at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:115)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:185)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:178)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:156)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:138)
    at org.springframework.boot.context.event.EventPublishingRunListener.multicastInitialEvent(EventPublishingRunListener.java:136)
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:81)
    at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:64)
    at java.base/java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:118)
    at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:112)
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:63)
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:353)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:313)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)
    at it.eresult.gateway.GatewayApplication.main(GatewayApplication.java:10)
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102)
    at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
    at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)

using the following dependencies:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-kubernetes-fabric8-loadbalancer</artifactId>
</dependency>

with spring boot 3.4.1 and spring cloud 2024.0.0.

I am using fabric8, but I guess it doesn't matter. There are no newer spring cloud releases. It is supposed to be fixed?

@wind57
Copy link
Contributor

wind57 commented Jan 12, 2025

@davgia can you open a new bug and provide a sample, just like the initial one in this thread? then I can take a look at it. thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
Status: Done
Development

Successfully merging a pull request may close this issue.

5 participants