Spring Cloud Kubernetes Reload

This commit is contained in:
Nicola Ferraro
2016-10-11 10:31:33 +02:00
committed by Ioannis Canellos
parent 7e521f5c23
commit 41bb31fd4c
16 changed files with 729 additions and 4 deletions

58
example/pom.xml Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-kubernetes-project</artifactId>
<groupId>io.fabric8</groupId>
<version>0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>example</artifactId>
<dependencies>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>spring-cloud-kubernetes-core</artifactId>
<version>${project.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework.cloud</groupId>-->
<!--<artifactId>spring-cloud-config-client</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.2.4.Final</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>fabric8-maven-plugin</artifactId>
<version>3.1.69</version>
<executions>
<execution>
<goals>
<goal>resource</goal>
<goal>build</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,16 @@
package io.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
*
*/
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@@ -0,0 +1,29 @@
package io.app;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
*
*/
@Component
@ConfigurationProperties(prefix = "bean")
public class MyBean {
private String message;
@Scheduled(fixedDelay = 5000)
public void hello() {
System.out.println("The message is: " + message);
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,9 @@
spring.application.name=example
#spring.cloud.kubernetes.reload.strategy=refresh
#spring.cloud.kubernetes.reload.mode=polling
#spring.cloud.kubernetes.reload.period=2000
#spring.cloud.kubernetes.reload.monitoring-config-maps=false
#spring.cloud.kubernetes.reload.monitoring-secrets=true
#spring.cloud.kubernetes.reload.enabled=true

View File

@@ -106,6 +106,7 @@
<module>spring-cloud-starter-kubernetes-netflix</module>
<module>spring-cloud-starter-kubernetes-zipkin</module>
<module>spring-cloud-starter-kubernetes-all</module>
<module>example</module>
</modules>
<dependencyManagement>

View File

@@ -64,7 +64,7 @@ The `ConfigMap` `PropertySource` when enabled will lookup Kubernetes for a `Conf
- apply individual configuration properties.
- apply as yaml the content of any property named `application.yaml`
- apple as properties file the content of any property named `application.properties`
- apply as properties file the content of any property named `application.properties`
Example:
@@ -196,6 +196,27 @@ You can select the Secrets to consume in a number of ways:
- The property spring.cloud.kubernetes.secrets.paths behave as defined by [Collection-based binding](https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#collection-based-binding).
- Access to secrets via API may be restricted for security reasons, the preferred way is to mount secret to the POD.
#### PropertySource Reload
Some applications may need to detect changes on external property sources and update their internal status to reflect the new configuration.
The reload feature of Spring Cloud Kubernetes is able to trigger an application reload when its related ConfigMap or Secret change.
This feature is disabled by default and can be enabled using the configuration property `spring.cloud.kubernetes.reload.enabled=true`
(eg. in the *application.properties* file).
The following levels of reload are supported (property `spring.cloud.kubernetes.reload.strategy`):
- **refresh (default)**: only spring beans annotated with `@ConfigurationProperties` or `@RefreshScope` are reloaded.
This reload level leverages the refresh feature of Spring Cloud Context.
- **restart_context**: the whole Spring _ApplicationContext_ is gracefully restarted. Beans are recreated with the new configuration.
- **shutdown**: the Spring _ApplicationContext_ is shut down to activate a restart of the container.
When using this level, make sure that the lifecycle of all non-daemon threads is bound to the ApplicationContext
and that a replication controller or replica set is configured to restart the pod.
Example:
Assuming that the reload feature is enabled with default settings, the following bean will be refreshed
### Pod Health Indicator
Spring Boot uses [HealthIndicator](https://github.com/spring-projects/spring-boot/blob/master/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthIndicator.java) to expose info about the health of an application.

View File

@@ -22,6 +22,7 @@ import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@Order(0)
@@ -35,7 +36,7 @@ public class ConfigMapPropertySourceLocator implements PropertySourceLocator {
}
@Override
public PropertySource<?> locate(Environment environment) {
public MapPropertySource locate(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
String appName = env.getProperty(Constants.SPRING_APPLICATION_NAME, Constants.FALLBACK_APPLICATION_NAME);

View File

@@ -22,6 +22,7 @@ import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@Order(1)
@@ -35,7 +36,7 @@ public class SecretsPropertySourceLocator implements PropertySourceLocator {
}
@Override
public PropertySource<?> locate(Environment environment) {
public MapPropertySource locate(Environment environment) {
return environment instanceof ConfigurableEnvironment
? new SecretsPropertySource(client, environment, properties)
: null;

View File

@@ -0,0 +1,137 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import javax.annotation.PreDestroy;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.spring.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import io.fabric8.spring.cloud.kubernetes.config.SecretsPropertySourceLocator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.cloud.context.restart.RestartEndpoint;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
/**
* Definition of beans needed for the automatic reload of configuration.
*/
@Configuration
@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true)
@EnableConfigurationProperties(ConfigReloadProperties.class)
public class ConfigReloadAutoConfiguration {
/**
* Configuration reload must be enabled explicitly.
*/
@ConditionalOnProperty(value = "spring.cloud.kubernetes.reload.enabled")
@ConditionalOnClass({RestartEndpoint.class, ContextRefresher.class})
@EnableScheduling
@EnableAsync
protected static class ConfigReloadAutoConfigurationBeans {
@Autowired
private AbstractEnvironment environment;
@Autowired
private KubernetesClient kubernetesClient;
@Autowired
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
@Autowired
private SecretsPropertySourceLocator secretsPropertySourceLocator;
/**
* Provides a bean that listen to configuration changes and fire a reload.
*/
@Bean
@ConditionalOnMissingBean
public ConfigurationChangeDetector propertyChangeWatcher(ConfigReloadProperties properties, ConfigurationUpdateStrategy strategy, EventWatcher eventWatcher) {
switch (properties.getMode()) {
case POLLING:
return new PollingConfigurationChangeDetector(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator, secretsPropertySourceLocator);
case EVENT:
return new EventBasedConfigurationChangeDetector(environment, properties, kubernetesClient, strategy, configMapPropertySourceLocator, secretsPropertySourceLocator, eventWatcher);
}
throw new IllegalStateException("Unsupported configuration reload mode: " + properties.getMode());
}
/**
* Provides the action to execute when the configuration changes.
*/
@Bean
@ConditionalOnMissingBean
public ConfigurationUpdateStrategy configurationUpdateStrategy(ConfigReloadProperties properties, ConfigurableApplicationContext ctx, RestartEndpoint restarter, ContextRefresher refresher) {
switch (properties.getStrategy()) {
case RESTART_CONTEXT:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), restarter::restart);
case REFRESH:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), refresher::refresh);
case SHUTDOWN:
return new ConfigurationUpdateStrategy(properties.getStrategy().name(), ctx::close);
}
throw new IllegalStateException("Unsupported configuration update strategy: " + properties.getStrategy());
}
/**
* Manages watches asynchronously and clean them up on context close.
*/
@Component
public static class DefaultEventWatcher implements EventWatcher {
private Logger log = LoggerFactory.getLogger(getClass());
private KubernetesClient kubernetesClient;
private Map<String, Watch> watches;
@Autowired
public DefaultEventWatcher(KubernetesClient kubernetesClient) {
this.kubernetesClient = kubernetesClient;
this.watches = new ConcurrentHashMap<>();
}
@Async
public void addWatch(String name, Function<KubernetesClient, Watch> watch) {
if (watches.containsKey(name)) {
throw new IllegalArgumentException("Watch already present: " + name);
}
watches.put(name, watch.apply(kubernetesClient));
log.info("Added new Kubernetes watch: {}", name);
}
@PreDestroy
public void unwatch() {
if (this.watches != null) {
for (Watch watch : this.watches.values()) {
try {
watch.close();
} catch (Exception e) {
log.error("Error while closing the watch connection", e);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,124 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* General configuration for the configuration reload.
*/
@ConfigurationProperties(prefix = "spring.cloud.kubernetes.reload")
public class ConfigReloadProperties {
/**
* Enables the Kubernetes configuration reload on change.
*/
private boolean enabled = false;
/**
* Enables monitoring on config maps to detect changes.
*/
private boolean monitoringConfigMaps = true;
/**
* Enables monitoring on secrets to detect changes.
*/
private boolean monitoringSecrets = false;
/**
* Sets the reload strategy for Kubernetes configuration reload on change.
*/
private ReloadStrategy strategy = ReloadStrategy.REFRESH;
/**
* Sets the detection mode for Kubernetes configuration reload.
*/
private ReloadDetectionMode mode = ReloadDetectionMode.EVENT;
/**
* Sets the polling period in milliseconds to use when the detection mode is POLLING.
*/
private Long period = 15000L;
public ConfigReloadProperties() {
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isMonitoringConfigMaps() {
return monitoringConfigMaps;
}
public void setMonitoringConfigMaps(boolean monitoringConfigMaps) {
this.monitoringConfigMaps = monitoringConfigMaps;
}
public boolean isMonitoringSecrets() {
return monitoringSecrets;
}
public void setMonitoringSecrets(boolean monitoringSecrets) {
this.monitoringSecrets = monitoringSecrets;
}
public ReloadStrategy getStrategy() {
return strategy;
}
public void setStrategy(ReloadStrategy strategy) {
this.strategy = strategy;
}
public ReloadDetectionMode getMode() {
return mode;
}
public Long getPeriod() {
return period;
}
public void setPeriod(Long period) {
this.period = period;
}
public void setMode(ReloadDetectionMode mode) {
this.mode = mode;
}
public enum ReloadStrategy {
/**
* Fire a refresh of beans annotated with @ConfigurationProperties or @RefreshScope.
*/
REFRESH,
/**
* Restarts the Spring ApplicationContext to apply the new configuration.
*/
RESTART_CONTEXT,
/**
* Shuts down the Spring ApplicationContext to activate a restart of the container.
* Make sure that the lifecycle of all non-daemon threads is bound to the ApplicationContext and that
* a replication controller or replica set is configured to restart the pod.
*/
SHUTDOWN
}
public enum ReloadDetectionMode {
/**
* Enables a polling task that retrieves periodically all external properties and
* fire a reload when they change.
*/
POLLING,
/**
* Listens to Kubernetes events and checks if a reload is needed when configmaps or secrets change.
*/
EVENT
}
}

View File

@@ -0,0 +1,109 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.annotation.PreDestroy;
import io.fabric8.kubernetes.client.Client;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
/**
* This is the superclass of all beans that can listen to changes in the configuration and fire a reload.
*/
public abstract class ConfigurationChangeDetector {
protected Logger log = LoggerFactory.getLogger(getClass());
protected ConfigurableEnvironment environment;
protected ConfigReloadProperties properties;
protected KubernetesClient kubernetesClient;
protected ConfigurationUpdateStrategy strategy;
public ConfigurationChangeDetector(ConfigurableEnvironment environment, ConfigReloadProperties properties, KubernetesClient kubernetesClient, ConfigurationUpdateStrategy strategy) {
this.environment = environment;
this.properties = properties;
this.kubernetesClient = kubernetesClient;
this.strategy = strategy;
}
@PreDestroy
public void shutdown() {
// Ensure the kubernetes client is cleaned up from spare threads when shutting down
if (kubernetesClient instanceof Client) {
((Client) kubernetesClient).close();
}
}
public void reloadProperties() {
log.info("Reloading using strategy: " + strategy.getName());
strategy.reload();
}
/**
* Determines if two property sources are different.
*/
protected boolean changed(MapPropertySource mp1, MapPropertySource mp2) {
if (mp1 == mp2) return false;
if (mp1 == null && mp2 != null || mp1 != null && mp2 == null) return true;
Map<String, Object> s1 = mp1.getSource();
Map<String, Object> s2 = mp2.getSource();
return s1 == null ? s2 != null : !s1.equals(s2);
}
/**
* Finds one registered property source of the given type, logging a warning if
* multiple property sources of that type are available.
*/
protected <S extends PropertySource<?>> S findPropertySource(Class<S> sourceClass) {
List<S> sources = findPropertySources(sourceClass);
if (sources.size() == 0) {
return null;
}
if (sources.size() > 1) {
log.warn("Found more than one property source of type " + sourceClass);
}
return sources.get(0);
}
/**
* Finds all registered property sources of the given type.
*/
protected <S extends PropertySource<?>> List<S> findPropertySources(Class<S> sourceClass) {
List<S> managedSources = new LinkedList<>();
LinkedList<PropertySource<?>> sources = toLinkedList(environment.getPropertySources());
while (!sources.isEmpty()) {
PropertySource<?> source = sources.pop();
if (source instanceof CompositePropertySource) {
CompositePropertySource comp = (CompositePropertySource) source;
sources.addAll(comp.getPropertySources());
} else if (sourceClass.isInstance(source)) {
managedSources.add(sourceClass.cast(source));
}
}
return managedSources;
}
private <E> LinkedList<E> toLinkedList(Iterable<E> it) {
LinkedList<E> list = new LinkedList<E>();
for (E e : it) {
list.add(e);
}
return list;
}
}

View File

@@ -0,0 +1,36 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import java.util.Objects;
/**
* This is the superclass of all named strategies that can be fired when the configuration changes.
*/
public class ConfigurationUpdateStrategy {
private String name;
private Runnable reloadProcedure;
public ConfigurationUpdateStrategy(String name, Runnable reloadProcedure) {
Objects.requireNonNull(name, "name cannot be null");
Objects.requireNonNull(reloadProcedure, "reloadProcedure cannot be null");
this.name = name;
this.reloadProcedure = reloadProcedure;
}
public String getName() {
return name;
}
public void reload() {
this.reloadProcedure.run();
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ConfigurationUpdateStrategy{");
sb.append("name='").append(name).append('\'');
sb.append('}');
return sb.toString();
}
}

View File

@@ -0,0 +1,100 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import javax.annotation.PostConstruct;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.Secret;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.spring.cloud.kubernetes.config.ConfigMapPropertySource;
import io.fabric8.spring.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import io.fabric8.spring.cloud.kubernetes.config.SecretsPropertySource;
import io.fabric8.spring.cloud.kubernetes.config.SecretsPropertySourceLocator;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.MapPropertySource;
/**
* A change detector that subscribes to changes in secrets and configmaps and fire a reload when something changes.
*/
public class EventBasedConfigurationChangeDetector extends ConfigurationChangeDetector {
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
private EventWatcher eventWatcher;
public EventBasedConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties,
KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator,
EventWatcher eventWatcher) {
super(environment, properties, kubernetesClient, strategy);
this.eventWatcher = eventWatcher;
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
}
@PostConstruct
public void watch() {
if (properties.isMonitoringConfigMaps()) {
eventWatcher.addWatch("config-maps-watch", k -> k.configMaps()
.watch(new Watcher<ConfigMap>() {
@Override
public void eventReceived(Action action, ConfigMap configMap) {
onEvent(configMap);
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
}
if (properties.isMonitoringSecrets()) {
eventWatcher.addWatch("secrets-watch", k -> k.secrets()
.watch(new Watcher<Secret>() {
@Override
public void eventReceived(Action action, Secret secret) {
onEvent(secret);
}
@Override
public void onClose(KubernetesClientException e) {
}
}));
}
log.info("Kubernetes polling configuration change detector activated");
}
private void onEvent(ConfigMap configMap) {
MapPropertySource currentConfigMapSource = findPropertySource(ConfigMapPropertySource.class);
if (currentConfigMapSource != null) {
MapPropertySource newConfigMapSource = configMapPropertySourceLocator.locate(environment);
if (changed(currentConfigMapSource, newConfigMapSource)) {
log.info("Detected change in config maps");
reloadProperties();
}
}
}
private void onEvent(Secret secret) {
MapPropertySource currentSecretSource = findPropertySource(SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = secretsPropertySourceLocator.locate(environment);
if (changed(currentSecretSource, newSecretSource)) {
log.info("Detected change in secrets");
reloadProperties();
}
}
}
}

View File

@@ -0,0 +1,15 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import java.util.function.Function;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.kubernetes.client.Watch;
/**
* Provides a way to start Kubernetes watches and bind their lifecycle to the application context.
*/
public interface EventWatcher {
void addWatch(String name, Function<KubernetesClient, Watch> watch);
}

View File

@@ -0,0 +1,67 @@
package io.fabric8.spring.cloud.kubernetes.reload;
import javax.annotation.PostConstruct;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.fabric8.spring.cloud.kubernetes.config.ConfigMapPropertySource;
import io.fabric8.spring.cloud.kubernetes.config.ConfigMapPropertySourceLocator;
import io.fabric8.spring.cloud.kubernetes.config.SecretsPropertySource;
import io.fabric8.spring.cloud.kubernetes.config.SecretsPropertySourceLocator;
import org.springframework.core.env.AbstractEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.scheduling.annotation.Scheduled;
/**
* A change detector that periodically retrieves secrets and configmaps and fire a reload when something changes.
*/
public class PollingConfigurationChangeDetector extends ConfigurationChangeDetector {
private ConfigMapPropertySourceLocator configMapPropertySourceLocator;
private SecretsPropertySourceLocator secretsPropertySourceLocator;
public PollingConfigurationChangeDetector(AbstractEnvironment environment,
ConfigReloadProperties properties,
KubernetesClient kubernetesClient,
ConfigurationUpdateStrategy strategy,
ConfigMapPropertySourceLocator configMapPropertySourceLocator,
SecretsPropertySourceLocator secretsPropertySourceLocator) {
super(environment, properties, kubernetesClient, strategy);
this.configMapPropertySourceLocator = configMapPropertySourceLocator;
this.secretsPropertySourceLocator = secretsPropertySourceLocator;
}
@PostConstruct
public void init() {
log.info("Kubernetes polling configuration change detector activated");
}
@Scheduled(initialDelayString = "${spring.cloud.kubernetes.reload.period:15000}", fixedDelayString = "${spring.cloud.kubernetes.reload.period:15000}")
public void executeCycle() {
boolean changedConfigMap = false;
if (properties.isMonitoringConfigMaps()) {
MapPropertySource currentConfigMapSource = findPropertySource(ConfigMapPropertySource.class);
if (currentConfigMapSource != null) {
MapPropertySource newConfigMapSource = configMapPropertySourceLocator.locate(environment);
changedConfigMap = changed(currentConfigMapSource, newConfigMapSource);
}
}
boolean changedSecrets = false;
if (properties.isMonitoringSecrets()) {
MapPropertySource currentSecretSource = findPropertySource(SecretsPropertySource.class);
if (currentSecretSource != null) {
MapPropertySource newSecretSource = secretsPropertySourceLocator.locate(environment);
changedSecrets = changed(currentSecretSource, newSecretSource);
}
}
if (changedConfigMap || changedSecrets) {
reloadProperties();
}
}
}

View File

@@ -1,5 +1,6 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.fabric8.spring.cloud.kubernetes.KubernetesAutoConfiguration
io.fabric8.spring.cloud.kubernetes.KubernetesAutoConfiguration,\
io.fabric8.spring.cloud.kubernetes.reload.ConfigReloadAutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
io.fabric8.spring.cloud.kubernetes.config.BootstrapConfiguration