Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,7 @@ spring:

Such a configuration will make the app watch changes only in the `my-namespace` namespace. Mind that this will
watch _all_ configmaps/secrets (depending on which one you enable). If you want an even more fine-grained approach,
you can enable "label-filtering". First we need to enable such support via : `enable-reload-filtering: true`

[source,yaml]
----
spring:
application:
name: event-reload
cloud:
kubernetes:
reload:
enabled: true
strategy: shutdown
mode: event
namespaces:
- my-namespaces
monitoring-config-maps: true
enable-reload-filtering: true
----

What this will do, is watch configmaps/secrets that only have the `spring.cloud.kubernetes.config.informer.enabled: true` label.
In the next major release this support will be removed and replaced with:
you can set the labels that are supposed to be watched, via:

[source,yaml]
----
Expand Down Expand Up @@ -80,7 +60,6 @@ spring:
| `spring.cloud.kubernetes.reload.mode` | `Enum` | `event` | Specifies how to listen for changes in property sources (`event` or `polling`)
| `spring.cloud.kubernetes.reload.period` | `Duration`| `15s` | The period for verifying changes when using the `polling` strategy
| `spring.cloud.kubernetes.reload.namespaces` | `String[]`| | namespaces where we should watch for changes
| `spring.cloud.kubernetes.reload.enable-reload-filtering` | `String` | | enabled labeled filtering for reload functionality
|===

Notes:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,54 +36,39 @@ env:
value: "namespace-a"
----

This one lets watcher know where to search for secrets and configmaps. You have two options here: selective namespaces (the setting above) and a namespace chosen by xref:property-source-config.adoc#namespace-resolution[Namespace Resolution] (this is the default option).
This tells the watcher where to search for Secrets and ConfigMaps. You have two options here: selective namespaces (the setting above) and a namespace chosen by xref:property-source-config.adoc#namespace-resolution[Namespace Resolution] (this is the default option).
Keep in mind that all these options require proper RBAC rules.

By default, Configuration Watcher monitors only ConfigMaps labeled:
Configuration Watcher can monitor ConfigMaps and Secrets in the configured namespace(s). If you want it to react only to particular sources, configure label filters for the watched resources:

[source]
----
spring.cloud.kubernetes.config: "true"
spring.cloud.kubernetes.reload.config-maps-labels[a]=b
spring.cloud.kubernetes.reload.secrets-labels[x]=y
----

Secrets are not monitored by default. To enable Secret monitoring, set:
or via environment variables in the watcher deployment:

[source,yaml]
----
env:
- name: SPRING_CLOUD_KUBERNETES_SECRETS_ENABLED
value: "TRUE"
----

Once enabled, only Secrets labeled: `spring.cloud.kubernetes.secret: "true"` are monitored.

You can customize these label selectors in the Configuration Watcher application itself:

[source,yaml]
----
spring:
cloud:
kubernetes:
reload:
config-maps-labels:
my-configmap-label: "my-configmap-value"
secrets-labels:
my-secret-label: "my-secret-value"
- name: SPRING_CLOUD_KUBERNETES_RELOAD_CONFIG_MAPS_LABELS_A
value: "b"
- name: SPRING_CLOUD_KUBERNETES_RELOAD_SECRETS_LABELS_X
value: "y"
----

When such filters are configured, only ConfigMaps or Secrets matching those labels will trigger a refresh event.

or via environment variables in the watcher Deployment:
Secrets are not monitored by default. To enable Secret monitoring, set:

[source,yaml]
----
env:
- name: SPRING_CLOUD_KUBERNETES_RELOAD_CONFIG_MAPS_LABELS_MY_CONFIGMAP_LABEL
value: "my-configmap-value"
- name: SPRING_CLOUD_KUBERNETES_RELOAD_SECRETS_LABELS_MY_SECRET_LABEL
value: "my-secret-value"
- name: SPRING_CLOUD_KUBERNETES_SECRETS_ENABLED
value: "TRUE"
----


One more important configuration, especially for configmaps and secrets that are mounted as volumes (via `spring.config.import`) is:

[source]
Expand All @@ -92,7 +77,7 @@ One more important configuration, especially for configmaps and secrets that are
value: "10000"
----

This tells how many milliseconds should we wait before firing the event from configuration watcher. This is important because kubernetes documentation says:
This tells the watcher how many milliseconds to wait before firing the refresh event. This is important because Kubernetes documentation says:

> When a ConfigMap currently consumed in a volume is updated, projected keys are eventually updated as well.

Expand Down Expand Up @@ -191,13 +176,13 @@ The controller needs access to read data about ConfigMaps, Pods, Services, Endpo

## Monitoring ConfigMaps and Secrets

If a change is made to a ConfigMap or Secret with valid labels (as detailed above), then Spring Cloud Kubernetes Configuration Watcher will take the name of the ConfigMap or Secret
If a change is made to a ConfigMap or Secret that matches the configured watcher labels, then Spring Cloud Kubernetes Configuration Watcher will take the name of the ConfigMap or Secret
and send a notification to the application with that name. This might not be enough for your use-case though, you could for example want to:

- bind a config-map to multiple applications, so that a change inside a single configmap triggers a refresh for many services
- have profile based sources trigger events for your application

For that reasons there is an addition annotation you could specify:
For those cases there are additional annotations you can specify:

`spring.cloud.kubernetes.configmap.apps` or `spring.cloud.kubernetes.secret.apps`. It takes a String of apps separated by comma,
that specifies the names of applications that will receive a notification when changes happen in this secret/configmap.
Expand All @@ -210,8 +195,6 @@ kind: ConfigMap
apiVersion: v1
metadata:
name: example-configmap
labels:
spring.cloud.kubernetes.config: "true"
annotations:
spring.cloud.kubernetes.configmap.apps: "app-a, app-b"
----
Expand Down Expand Up @@ -239,8 +222,6 @@ kind: ConfigMap
apiVersion: v1
metadata:
name: example-configmap
labels:
spring.cloud.kubernetes.config: "true"
annotations:
spring.cloud.kubernetes.configmap.labels: "app=demo,tier=backend"
----
Expand Down
4 changes: 1 addition & 3 deletions docs/modules/ROOT/partials/_configprops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@
|spring.cloud.kubernetes.loadbalancer.enabled | `+++true+++` | Load balancer enabled,default true.
|spring.cloud.kubernetes.loadbalancer.mode | `+++pod+++` | {@link KubernetesLoadBalancerMode} setting load balancer server list with ip of pod or service name. default value is POD.
|spring.cloud.kubernetes.loadbalancer.port-name | `+++http+++` | service port name.
|spring.cloud.kubernetes.reload.config-maps-labels | | Labels for which to watch config maps.
|spring.cloud.kubernetes.reload.enable-reload-filtering | `+++false+++` | create an informer only for sources that have 'spring.cloud.kubernetes.config.informer.enabled=true' label. This property is only relevant for event based reloading.
|spring.cloud.kubernetes.reload.enabled | `+++false+++` | Enables the Kubernetes configuration reload on change.
|spring.cloud.kubernetes.reload.max-wait-for-restart | `+++2s+++` | Restart or Shutdown strategies are used, Spring Cloud Kubernetes waits a random amount of time before restarting. This is done in order to avoid having all instances of the same application restart at the same time. This property configures the maximum of amount of wait time from the moment the signal is received that a restart is needed until the moment the restart is actually triggered
|spring.cloud.kubernetes.reload.mode | `+++EVENT+++` | Sets the detection mode for Kubernetes configuration reload.
Expand All @@ -123,4 +121,4 @@
|spring.cloud.kubernetes.secrets.sources | |
|spring.cloud.kubernetes.secrets.use-name-as-prefix | `+++false+++` |

|===
|===
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ public class KubernetesClientEventBasedConfigMapChangeDetector extends Configura

private final ConfigurableEnvironment environment;

private final boolean enableReloadFiltering;

private final boolean monitoringConfigMaps;

private final Map<String, String> configMapsLabels;
Expand Down Expand Up @@ -115,7 +113,6 @@ public KubernetesClientEventBasedConfigMapChangeDetector(CoreV1Api coreV1Api, Co
this.propertySourceLocator = propertySourceLocator;
this.coreV1Api = coreV1Api;
this.apiClient = createApiClientForInformerClient();
this.enableReloadFiltering = properties.enableReloadFiltering();
this.monitoringConfigMaps = properties.monitoringConfigMaps();
this.configMapsLabels = properties.configMapsLabels();
namespaces = namespaces(kubernetesNamespaceProvider, properties, "configmap");
Expand All @@ -126,21 +123,6 @@ void inform() {
if (monitoringConfigMaps) {
LOG.info(() -> "Kubernetes event-based configMap change detector activated");

Map<String, String> labelSelector;

if (enableReloadFiltering) {
LOG.warn(() -> "enable reload filtering is deprecated and will be removed in the next major release");
LOG.warn(() -> "use spring.cloud.kubernetes.reload.config-maps-labels instead");
if (!configMapsLabels.isEmpty()) {
LOG.warn(() -> "spring.cloud.kubernetes.reload.config-maps-labels is not empty, but "
+ "spring.cloud.kubernetes.reload.enable-reload-filtering is enabled and will override the former");
}
labelSelector = Map.of(ConfigReloadProperties.RELOAD_LABEL_FILTER, "true");
}
else {
labelSelector = configMapsLabels;
}

namespaces.forEach(namespace -> {
SharedIndexInformer<V1ConfigMap> informer;

Expand All @@ -151,11 +133,11 @@ void inform() {
.timeoutSeconds(params.timeoutSeconds)
.resourceVersion(params.resourceVersion)
.watch(params.watch)
.labelSelector(labelSelector(labelSelector))
.labelSelector(labelSelector(configMapsLabels))
.buildCall(null), V1ConfigMap.class, V1ConfigMapList.class);

LOG.debug(() -> "added configmap informer for namespace : " + namespace + " with labels : "
+ labelSelector);
LOG.debug(
() -> "configmap informer for namespace : " + namespace + " with labels : " + configMapsLabels);

informer.addEventHandler(handler);
informers.add(informer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,6 @@ public class KubernetesClientEventBasedSecretsChangeDetector extends Configurati

private final ConfigurableEnvironment environment;

private final boolean enableReloadFiltering;

private final boolean monitoringSecrets;

private final Map<String, String> secretsLabels;
Expand Down Expand Up @@ -117,7 +115,6 @@ public KubernetesClientEventBasedSecretsChangeDetector(CoreV1Api coreV1Api, Conf
this.propertySourceLocator = propertySourceLocator;
this.coreV1Api = coreV1Api;
this.apiClient = createApiClientForInformerClient();
this.enableReloadFiltering = properties.enableReloadFiltering();
this.monitoringSecrets = properties.monitoringSecrets();
this.secretsLabels = properties.secretsLabels();
namespaces = namespaces(kubernetesNamespaceProvider, properties, "secret");
Expand All @@ -127,21 +124,6 @@ public KubernetesClientEventBasedSecretsChangeDetector(CoreV1Api coreV1Api, Conf
void inform() {
LOG.info(() -> "Kubernetes event-based secrets change detector activated");

Map<String, String> labelSelector;

if (enableReloadFiltering) {
LOG.warn(() -> "enable reload filtering is deprecated and will be removed in the next major release");
LOG.warn(() -> "use spring.cloud.kubernetes.reload.secrets-labels instead");
if (!secretsLabels.isEmpty()) {
LOG.warn(() -> "spring.cloud.kubernetes.reload.secrets-labels is not empty, but "
+ "spring.cloud.kubernetes.reload.enable-reload-filtering is enabled and will override the former");
}
labelSelector = Map.of(ConfigReloadProperties.RELOAD_LABEL_FILTER, "true");
}
else {
labelSelector = secretsLabels;
}

if (monitoringSecrets) {
namespaces.forEach(namespace -> {
SharedIndexInformer<V1Secret> informer;
Expand All @@ -153,10 +135,10 @@ void inform() {
.timeoutSeconds(params.timeoutSeconds)
.resourceVersion(params.resourceVersion)
.watch(params.watch)
.labelSelector(labelSelector(labelSelector))
.labelSelector(labelSelector(secretsLabels))
.buildCall(null), V1Secret.class, V1SecretList.class);

LOG.debug(() -> "secret informer for namespace : " + namespace + " with filter : " + secretsLabels);
LOG.debug(() -> "secret informer for namespace : " + namespace + " with labels : " + secretsLabels);

informer.addEventHandler(handler);
informers.add(informer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.springframework.cloud.kubernetes.client.config;

import java.time.Duration;
import java.util.Map;
import java.util.Set;

import org.assertj.core.api.Assertions;
Expand All @@ -33,9 +34,9 @@ class KubernetesClientConfigUtilsTests {

@Test
void testNamespacesFromProperties() {
ConfigReloadProperties properties = new ConfigReloadProperties(false, false, false,
ConfigReloadProperties properties = new ConfigReloadProperties(false, false, Map.of(), false, Map.of(),
ConfigReloadProperties.ReloadStrategy.REFRESH, ConfigReloadProperties.ReloadDetectionMode.EVENT,
Duration.ofMillis(15000), Set.of("non-default"), false, Duration.ofSeconds(2));
Duration.ofMillis(15000), Set.of("non-default"), Duration.ofSeconds(2));
Set<String> namespaces = KubernetesClientConfigUtils
.namespaces(new KubernetesNamespaceProvider(new MockEnvironment()), properties, "configmap");
Assertions.assertThat(1).isEqualTo(namespaces.size());
Expand Down
Loading
Loading