Skip to content

Commit 8224009

Browse files
authored
Merge pull request #2070 from wind57/fix-1641-make-k8s-discovery-cacheable
Fix 1641 make k8s discovery cacheable
2 parents 3eac93f + 44a995c commit 8224009

File tree

23 files changed

+801
-276
lines changed

23 files changed

+801
-276
lines changed

docs/modules/ROOT/pages/discovery-client.adoc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,30 @@ spring.cloud.kubernetes.http.discovery.catalog.watcher.enabled=true
279279
- Since http discovery has _two_ components : server and client, we strongly recommend to align versions between them, otherwise things might not work.
280280
- If you decide to disable catalog watcher, you need to disable it in both server and client.
281281

282+
Since version `5.0.0`, there is the possibility to cache the responses from a discovery client (we do it via the `@Cacheable` annotation). There are two properties to keep in mind here:
283+
284+
[source]
285+
----
286+
spring.cloud.kubernetes.discovery.cacheable.reactive.enabled
287+
----
288+
289+
and
290+
291+
[source]
292+
----
293+
spring.cloud.kubernetes.discovery.cacheable.blocking.enabled
294+
----
295+
296+
The first one enables the cacheable reactive client, and the second one, the cacheable blocking client. By default, the non-cacheable discovery clients are created; if you want the cacheable one, you need to toggle one of the above properties. For example:
297+
298+
[source]
299+
----
300+
spring.cloud.kubernetes.discovery.cacheable.reactive.enabled=true
301+
----
302+
303+
will provide you the cacheable reactive discovery client.
304+
305+
282306
By default, we use the `Endpoints`(see https://kubernetes.io/docs/concepts/services-networking/service/#endpoints) API to find out the current state of services. There is another way though, via `EndpointSlices` (https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/). Such support can be enabled via a property: `spring.cloud.kubernetes.discovery.use-endpoint-slices=true` (by default it is `false`). Of course, your cluster has to support it also. As a matter of fact, if you enable this property, but your cluster does not support it, we will fail starting the application. If you decide to enable such support, you also need proper Role/ClusterRole set-up. For example:
283307

284308
[source]

spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesClientInformerReactiveDiscoveryClientAutoConfiguration.java

Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,20 @@
2525
import io.kubernetes.client.openapi.apis.CoreV1Api;
2626
import io.kubernetes.client.openapi.models.V1Endpoints;
2727
import io.kubernetes.client.openapi.models.V1Service;
28-
import org.apache.commons.logging.LogFactory;
2928

3029
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
3130
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
32-
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
3331
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
3432
import org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration;
3533
import org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration;
36-
import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicatorProperties;
37-
import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator;
3834
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration;
39-
import org.springframework.cloud.kubernetes.commons.PodUtils;
40-
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
4135
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
4236
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
4337
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnDiscoveryCacheableReactiveDisabled;
4438
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnDiscoveryCacheableReactiveEnabled;
4539
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnSpringCloudKubernetesReactiveDiscovery;
46-
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer;
47-
import org.springframework.context.ApplicationEventPublisher;
4840
import org.springframework.context.annotation.Bean;
4941
import org.springframework.context.annotation.Configuration;
50-
import org.springframework.core.log.LogAccessor;
5142

5243
/**
5344
* @author Ryan Baxter
@@ -62,13 +53,10 @@
6253
KubernetesClientDiscoveryClientSpelAutoConfiguration.class })
6354
final class KubernetesClientInformerReactiveDiscoveryClientAutoConfiguration {
6455

65-
private static final LogAccessor LOG = new LogAccessor(
66-
LogFactory.getLog(KubernetesClientInformerReactiveDiscoveryClientAutoConfiguration.class));
67-
6856
@Bean
6957
@ConditionalOnMissingBean
7058
@ConditionalOnDiscoveryCacheableReactiveDisabled
71-
KubernetesClientInformerReactiveDiscoveryClient kubernetesClientReactiveDiscoveryClient(
59+
KubernetesClientInformerReactiveDiscoveryClient kubernetesClientInformerReactiveDiscoveryClient(
7260
List<SharedInformerFactory> sharedInformerFactories, List<Lister<V1Service>> serviceListers,
7361
List<Lister<V1Endpoints>> endpointsListers, List<SharedInformer<V1Service>> serviceInformers,
7462
List<SharedInformer<V1Endpoints>> endpointsInformers, KubernetesDiscoveryProperties properties,
@@ -82,21 +70,10 @@ KubernetesClientInformerReactiveDiscoveryClient kubernetesClientReactiveDiscover
8270
return new KubernetesClientInformerReactiveDiscoveryClient(blockingClient);
8371
}
8472

85-
@Bean
86-
@ConditionalOnBean(KubernetesClientInformerReactiveDiscoveryClient.class)
87-
@ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer
88-
ReactiveDiscoveryClientHealthIndicator kubernetesReactiveDiscoveryClientHealthIndicator(
89-
KubernetesClientInformerReactiveDiscoveryClient reactiveClient,
90-
DiscoveryClientHealthIndicatorProperties properties) {
91-
return new ReactiveDiscoveryClientHealthIndicator(reactiveClient, properties);
92-
}
93-
94-
// Above two beans are created when cacheable is disabled
95-
9673
@Bean
9774
@ConditionalOnMissingBean
9875
@ConditionalOnDiscoveryCacheableReactiveEnabled
99-
KubernetesClientCacheableInformerReactiveDiscoveryClient kubernetesClientCacheableReactiveDiscoveryClient(
76+
KubernetesClientCacheableInformerReactiveDiscoveryClient kubernetesClientCacheableInformerReactiveDiscoveryClient(
10077
List<SharedInformerFactory> sharedInformerFactories, List<Lister<V1Service>> serviceListers,
10178
List<Lister<V1Endpoints>> endpointsListers, List<SharedInformer<V1Service>> serviceInformers,
10279
List<SharedInformer<V1Endpoints>> endpointsInformers, KubernetesDiscoveryProperties properties,
@@ -110,44 +87,4 @@ KubernetesClientCacheableInformerReactiveDiscoveryClient kubernetesClientCacheab
11087
return new KubernetesClientCacheableInformerReactiveDiscoveryClient(blockingClient);
11188
}
11289

113-
@Bean
114-
@ConditionalOnMissingBean(KubernetesClientInformerReactiveDiscoveryClient.class)
115-
@ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer
116-
ReactiveDiscoveryClientHealthIndicator reactiveDiscoveryClientHealthIndicator(
117-
List<SharedInformerFactory> sharedInformerFactories, List<Lister<V1Service>> serviceListers,
118-
List<Lister<V1Endpoints>> endpointsListers, List<SharedInformer<V1Service>> serviceInformers,
119-
List<SharedInformer<V1Endpoints>> endpointsInformers,
120-
KubernetesDiscoveryProperties kubernetesDiscoveryProperties, CoreV1Api coreV1Api,
121-
Predicate<V1Service> predicate, DiscoveryClientHealthIndicatorProperties properties) {
122-
123-
KubernetesClientInformerDiscoveryClient blockingClient = new KubernetesClientInformerDiscoveryClient(
124-
sharedInformerFactories, serviceListers, endpointsListers, serviceInformers, endpointsInformers,
125-
kubernetesDiscoveryProperties, coreV1Api, predicate);
126-
blockingClient.afterPropertiesSet();
127-
128-
KubernetesClientInformerReactiveDiscoveryClient reactiveClient = new KubernetesClientInformerReactiveDiscoveryClient(
129-
blockingClient);
130-
131-
return new ReactiveDiscoveryClientHealthIndicator(reactiveClient, properties);
132-
}
133-
134-
// Above two beans are created when cacheable is enabled. In this case, we can't make
135-
// KubernetesClientInformerDiscoveryClient a @Bean, since blocking discovery might be
136-
// disabled and we do not want to allow wiring of it.
137-
// Nevertheless, we still need an instance of KubernetesClientInformerDiscoveryClient
138-
// in order to create the ReactiveDiscoveryClientHealthIndicator and
139-
// KubernetesClientCacheableInformerReactiveDiscoveryClient.
140-
// As such, we create two of such instances in each bean.
141-
142-
/**
143-
* Post an event so that health indicator is initialized.
144-
*/
145-
@Bean
146-
@ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer
147-
KubernetesDiscoveryClientHealthIndicatorInitializer reactiveIndicatorInitializer(
148-
ApplicationEventPublisher applicationEventPublisher, PodUtils<?> podUtils) {
149-
LOG.debug(() -> "Will publish InstanceRegisteredEvent from reactive implementation");
150-
return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher);
151-
}
152-
15390
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright 2019-present the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.kubernetes.client.discovery;
18+
19+
import java.util.List;
20+
import java.util.function.Predicate;
21+
22+
import io.kubernetes.client.informer.SharedInformer;
23+
import io.kubernetes.client.informer.SharedInformerFactory;
24+
import io.kubernetes.client.informer.cache.Lister;
25+
import io.kubernetes.client.openapi.apis.CoreV1Api;
26+
import io.kubernetes.client.openapi.models.V1Endpoints;
27+
import io.kubernetes.client.openapi.models.V1Service;
28+
import org.apache.commons.logging.LogFactory;
29+
30+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
31+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
32+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
33+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
34+
import org.springframework.cloud.client.ReactiveCommonsClientAutoConfiguration;
35+
import org.springframework.cloud.client.discovery.composite.reactive.ReactiveCompositeDiscoveryClientAutoConfiguration;
36+
import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicatorProperties;
37+
import org.springframework.cloud.client.discovery.health.reactive.ReactiveDiscoveryClientHealthIndicator;
38+
import org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscoveryClientAutoConfiguration;
39+
import org.springframework.cloud.kubernetes.commons.PodUtils;
40+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryClientHealthIndicatorInitializer;
41+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryProperties;
42+
import org.springframework.cloud.kubernetes.commons.discovery.KubernetesDiscoveryPropertiesAutoConfiguration;
43+
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnSpringCloudKubernetesReactiveDiscovery;
44+
import org.springframework.cloud.kubernetes.commons.discovery.conditionals.ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer;
45+
import org.springframework.context.ApplicationEventPublisher;
46+
import org.springframework.context.annotation.Bean;
47+
import org.springframework.context.annotation.Configuration;
48+
import org.springframework.core.log.LogAccessor;
49+
50+
/**
51+
* @author wind57
52+
*/
53+
@Configuration(proxyBeanMethods = false)
54+
@ConditionalOnSpringCloudKubernetesReactiveDiscovery
55+
@AutoConfigureBefore({ SimpleReactiveDiscoveryClientAutoConfiguration.class,
56+
ReactiveCommonsClientAutoConfiguration.class })
57+
@AutoConfigureAfter({ ReactiveCompositeDiscoveryClientAutoConfiguration.class,
58+
KubernetesDiscoveryPropertiesAutoConfiguration.class,
59+
KubernetesClientDiscoveryClientSpelAutoConfiguration.class,
60+
KubernetesClientInformerReactiveDiscoveryClientAutoConfiguration.class })
61+
class KubernetesClientInformerReactiveHealthAutoConfiguration {
62+
63+
private static final LogAccessor LOG = new LogAccessor(
64+
LogFactory.getLog(KubernetesClientInformerReactiveHealthAutoConfiguration.class));
65+
66+
@Bean
67+
@ConditionalOnBean(KubernetesClientInformerReactiveDiscoveryClient.class)
68+
@ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer
69+
ReactiveDiscoveryClientHealthIndicator nonCacheableReactiveDiscoveryClientHealthIndicator(
70+
KubernetesClientInformerReactiveDiscoveryClient reactiveClient,
71+
DiscoveryClientHealthIndicatorProperties properties) {
72+
return new ReactiveDiscoveryClientHealthIndicator(reactiveClient, properties);
73+
}
74+
75+
@Bean
76+
@ConditionalOnMissingBean(KubernetesClientInformerReactiveDiscoveryClient.class)
77+
@ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer
78+
ReactiveDiscoveryClientHealthIndicator cacheableReactiveDiscoveryClientHealthIndicator(
79+
List<SharedInformerFactory> sharedInformerFactories, List<Lister<V1Service>> serviceListers,
80+
List<Lister<V1Endpoints>> endpointsListers, List<SharedInformer<V1Service>> serviceInformers,
81+
List<SharedInformer<V1Endpoints>> endpointsInformers,
82+
KubernetesDiscoveryProperties kubernetesDiscoveryProperties, CoreV1Api coreV1Api,
83+
Predicate<V1Service> predicate, DiscoveryClientHealthIndicatorProperties properties) {
84+
85+
KubernetesClientInformerDiscoveryClient blockingClient = new KubernetesClientInformerDiscoveryClient(
86+
sharedInformerFactories, serviceListers, endpointsListers, serviceInformers, endpointsInformers,
87+
kubernetesDiscoveryProperties, coreV1Api, predicate);
88+
blockingClient.afterPropertiesSet();
89+
90+
KubernetesClientInformerReactiveDiscoveryClient reactiveClient = new KubernetesClientInformerReactiveDiscoveryClient(
91+
blockingClient);
92+
93+
return new ReactiveDiscoveryClientHealthIndicator(reactiveClient, properties);
94+
}
95+
96+
/**
97+
* Post an event so that health indicator is initialized.
98+
*/
99+
@Bean
100+
@ConditionalOnSpringCloudKubernetesReactiveDiscoveryHealthInitializer
101+
KubernetesDiscoveryClientHealthIndicatorInitializer reactiveIndicatorInitializer(
102+
ApplicationEventPublisher applicationEventPublisher, PodUtils<?> podUtils) {
103+
LOG.debug(() -> "Will publish InstanceRegisteredEvent from reactive implementation");
104+
return new KubernetesDiscoveryClientHealthIndicatorInitializer(podUtils, applicationEventPublisher);
105+
}
106+
107+
}

spring-cloud-kubernetes-client-discovery/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerDi
33
org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerAutoConfiguration
44
org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerReactiveDiscoveryClientAutoConfiguration
55
org.springframework.cloud.kubernetes.client.discovery.KubernetesClientDiscoveryClientSpelAutoConfiguration
6+
org.springframework.cloud.kubernetes.client.discovery.KubernetesClientInformerReactiveHealthAutoConfiguration

0 commit comments

Comments
 (0)