Skip to content

Commit

Permalink
Merge branch 'main' into major-changes-in-k8s-discovery-implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
wind57 committed Dec 27, 2023
2 parents 0ecadd3 + 9930c7d commit b3c3edb
Show file tree
Hide file tree
Showing 75 changed files with 2,859 additions and 79 deletions.
2 changes: 1 addition & 1 deletion docs/modules/ROOT/pages/property-source-config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ an `application-profile.properties` or `application-profile.yaml` file that cont
application or Spring Boot starters. You can override these properties by specifying system properties or environment
variables.

To enable this functionality you need to set `spring.config.import=kubernetes:` in your application's configuration properties.
To enable this functionality you need to set the `spring.config.import` application configuration property to `kubernetes:` (escape with quotes when using yaml eg. `"kubernetes:"`).
Currently you can not specify a ConfigMap or Secret to load using `spring.config.import`, by default Spring Cloud Kubernetes
will load a ConfigMap and/or Secret based on the `spring.application.name` property. If `spring.application.name` is not set it will
load a ConfigMap and/or Secret with the name `application`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ NOTE: If you already have `spring-retry` and `spring-boot-starter-aop` on the cl
and want to enable fail-fast, but do not want retry to be enabled; you can disable retry for `Secrets` `PropertySources`
by setting `spring.cloud.kubernetes.secrets.retry.enabled=false`.

Since data coming from Secrets is usually treated as sensitive, endpoints of the actuator `/env` and `/configprops` can be made to sanitize data, so that it is not displayed in plain text. In order to do that, you need to set:

[source]
----
spring.cloud.kubernetes.sanitize.secrets=true
----

This setting is supported since `3.0.6` and upwards.

.Properties:
[options="header,footer"]
|===
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,62 @@ The application is published as a container and is available on https://hub.dock
However, if you need to customize the config watcher behavior or prefer to build the image yourself you can easily build your own
image from the https://github.com/spring-cloud/spring-cloud-kubernetes/tree/main/spring-cloud-kubernetes-controllers/spring-cloud-kubernetes-configuration-watcher[source code on GitHub] and use that.

Another option to configure it is to provide some environment variables in the deployment.yaml used to deploy configuration watcher. Here are some important ones:

[source]
----
env:
- name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CONFIGURATION_WATCHER
value: DEBUG
- name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_CLIENT_CONFIG_RELOAD
value: DEBUG
- name: LOGGING_LEVEL_ORG_SPRINGFRAMEWORK_CLOUD_KUBERNETES_COMMONS_CONFIG_RELOAD
value: DEBUG
----

These enable debug logging on the configuration watcher and are particular useful on the initial set-up, to be able to diagnose potential miss-configurations.

[source]
----
env:
- name: SPRING_CLOUD_KUBERNETES_RELOAD_NAMESPACES_0
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).
Keep in mind that all these options require proper RBAC rules.

Changes from configmaps/secrets will only trigger an event being fired from configuration watcher if that particular change came from a source that has a label: `spring.cloud.kubernetes.config=true` or `spring.cloud.kubernetes.secret=true`.

To put it simpler, if you change a configmap (or secret), that does _not_ have the label above, configuration watcher will skip firing an event for it (if you enabled debug logging, this will be visible in logs).

By default, configuration watcher will monitor all configmaps/secrets in the configured namespace(s). If you want to filter to watch only particular sources, you can do that by setting:

[source]
----
SPRING_CLOUD_KUBERNETES_CONFIG_INFORMER_ENABLED=TRUE
----

This will tell watcher to only monitor sources that have a label: `spring.cloud.kubernetes.config.informer.enabled=true`.

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

[source]
----
- name: SPRING_CLOUD_KUBERNETES_CONFIGURATION_WATCHER_REFRESHDELAY
value: "10000"
----

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

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

You need to "match" this _eventually_ part to that value in milliseconds on your cluster.

Spring Cloud Kubernetes Configuration Watcher can send refresh notifications to applications in two ways.

1. Over HTTP in which case the application being notified must of the `/refresh` actuator endpoint exposed and accessible from within the cluster
1. Over HTTP, in which case the application being notified, must have the `/refresh` actuator endpoint exposed and accessible from within the cluster
2. Using Spring Cloud Bus, in which case you will need a message broker deployed to your custer for the application to use.

## Deployment YAML
Expand Down Expand Up @@ -108,12 +161,8 @@ The controller needs access to read data about ConfigMaps, Pods, Services, Endpo

## Monitoring ConfigMaps and Secrets

Spring Cloud Kubernetes Configuration Watcher will react to changes in ConfigMaps with a label of `spring.cloud.kubernetes.config` with the value `true`
or any Secret with a label of `spring.cloud.kubernetes.secret` with the value `true`. If the ConfigMap or Secret does not have either of those labels
or the values of those labels is not `true` then any changes will be ignored.

If a change is made to a ConfigMap or Secret with valid 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 what to:
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
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
Expand All @@ -139,10 +188,10 @@ metadata:

## HTTP Implementation

The HTTP implementation is what is used by default. When this implementation is used Spring Cloud Kubernetes Configuration Watcher and a
The HTTP implementation is what is used by default. When this implementation is used, Spring Cloud Kubernetes Configuration Watcher and a
change to a ConfigMap or Secret occurs then the HTTP implementation will use the Spring Cloud Kubernetes Discovery Client to fetch all
instances of the application which match the name of the ConfigMap or Secret and send an HTTP POST request to the application's actuator
`/refresh` endpoint. By default it will send the post request to `/actuator/refresh` using the port registered in the discovery client.
`/refresh` endpoint. By default, it will send the post request to `/actuator/refresh` using the port registered in the discovery client.

### Non-Default Management Port and Actuator Path

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ public static ApiClient kubernetesApiClient() {
catch (Exception e) {
if (e instanceof IllegalStateException illegalStateException
&& illegalStateException.getCause() instanceof NumberFormatException) {
LOG.info("Could not create the Kubernetes ApiClient in a cluster environment, because connection port " +
"was not provided.");
LOG.info("Could not create the Kubernetes ApiClient in a cluster environment, because connection port "
+ "was not provided.");
}
else {
LOG.info("Could not create the Kubernetes ApiClient in a cluster environment, because : ", e);
}
LOG.info("""
Trying to use a "standard" configuration to create the Kubernetes ApiClient""");
Trying to use a "standard" configuration to create the Kubernetes ApiClient""");
try {
ApiClient apiClient = ClientBuilder.defaultClient();
LOG.info("Created standard API client. Unless $KUBECONFIG or $HOME/.kube/config is defined, "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithPrefixConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledConfigMapWithPrefixConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import org.springframework.test.web.reactive.server.WebTestClient;

/**
* Stud data is in
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithPrefixConfigurationStub}
* Stub data is in
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledConfigMapWithPrefixConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithProfileConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledConfigMapWithProfileConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
import org.springframework.test.web.reactive.server.WebTestClient;

/**
* Stud data is in
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledConfigMapWithProfileConfigurationStub}
* Stub data is in
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledConfigMapWithProfileConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithPrefixConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledSecretWithPrefixConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithPrefixConfigurationStub;
import org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledSecretWithPrefixConfigurationStub;
import org.springframework.test.web.reactive.server.WebTestClient;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithProfileConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledSecretWithProfileConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@

/**
* Stubs for this test are in
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.LabeledSecretWithProfileConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.LabeledSecretWithProfileConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedConfigMapWithPrefixConfigurationStub.stubData;

/**
* @author Ryan Baxter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithPrefixConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedConfigMapWithPrefixConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedConfigMapWithProfileConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedConfigMapWithProfileConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedConfigMapWithProfileConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedConfigMapWithProfileConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedSecretWithPrefixConfigurationStub.stubData;

/**
* @author Ryan Baxter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithPrefixConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedSecretWithPrefixConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithProfileConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedSecretWithProfileConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.NamedSecretWithProfileConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.NamedSecretWithProfileConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub.stubData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SingleSourceMultipleFilesConfigurationStub.stubData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
* @author wind57
*
* Stub for this test is here :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SingleSourceMultipleFilesConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SingleSourceMultipleFilesConfigurationStub}
*
* issue: https://github.com/spring-cloud/spring-cloud-kubernetes/issues/640
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubConfigMapData;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubSecretsData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SourcesOrderConfigurationStub.stubConfigMapData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SourcesOrderConfigurationStub.stubSecretsData;

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SourcesOrderConfigurationStub}
*
* @author wind57
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
import static org.mockito.Mockito.mockStatic;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubConfigMapData;
import static org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub.stubSecretsData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SourcesOrderConfigurationStub.stubConfigMapData;
import static org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SourcesOrderConfigurationStub.stubSecretsData;

/**
* @author wind57
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

/**
* The stub data for this test is in :
* {@link org.springframework.cloud.kubernetes.client.config.boostrap.stubs.SourcesOrderConfigurationStub}
* {@link org.springframework.cloud.kubernetes.client.config.bootstrap.stubs.SourcesOrderConfigurationStub}
*
* @author wind57
*/
Expand Down
Loading

0 comments on commit b3c3edb

Please sign in to comment.