The most common approach to configuring your Spring Boot application is to create an application.properties or applicaiton.yaml or
an application-profile.properties or application-profile.yaml file that contains key-value pairs that provide customization values to your
application or Spring Boot starters. You can override these properties by specifying system properties or environment
variables.
Kubernetes provides a resource named ConfigMap to externalize the
parameters to pass to your application in the form of key-value pairs or embedded application.properties or application.yaml files.
The Spring Cloud Kubernetes Config project makes Kubernetes ConfigMap instances available
during application bootstrapping and triggers hot reloading of beans or Spring context when changes are detected on
observed ConfigMap instances.
The default behavior is to create a ConfigMapPropertySource based on a Kubernetes ConfigMap that has a metadata.name value of either the name of
your Spring application (as defined by its spring.application.name property) or a custom name defined within the
bootstrap.properties file under the following key: spring.cloud.kubernetes.config.name.
However, more advanced configuration is possible where you can use multiple ConfigMap instances.
The spring.cloud.kubernetes.config.sources list makes this possible.
For example, you could define the following ConfigMap instances:
spring: application: name: cloud-k8s-app cloud: kubernetes: config: name: default-name namespace: default-namespace sources: # Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace - name: c1 # Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2 - namespace: n2 # Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3 - namespace: n3 name: c3
In the preceding example, if spring.cloud.kubernetes.config.namespace had not been set,
the ConfigMap named c1 would be looked up in the namespace that the application runs.
Any matching ConfigMap that is found is processed as follows:
yaml the content of any property named application.yaml.application.properties.The single exception to the aforementioned flow is when the ConfigMap contains a single key that indicates
the file is a YAML or properties file. In that case, the name of the key does NOT have to be application.yaml or
application.properties (it can be anything) and the value of the property is treated correctly.
This features facilitates the use case where the ConfigMap was created by using something like the following:
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
Assume that we have a Spring Boot application named demo that uses the following properties to read its thread pool
configuration.
pool.size.corepool.size.maximumThis can be externalized to config map in yaml format as follows:
kind: ConfigMap apiVersion: v1 metadata: name: demo data: pool.size.core: 1 pool.size.max: 16
Individual properties work fine for most cases. However, sometimes, embedded yaml is more convenient. In this case, we
use a single property named application.yaml to embed our yaml, as follows:
kind: ConfigMap apiVersion: v1 metadata: name: demo data: application.yaml: |- pool: size: core: 1 max:16
The following example also works:
kind: ConfigMap apiVersion: v1 metadata: name: demo data: custom-name.yaml: |- pool: size: core: 1 max:16
You can also configure Spring Boot applications differently depending on active profiles that are merged together
when the ConfigMap is read. You can provide different property values for different profiles by using an
application.properties or application.yaml property, specifying profile-specific values, each in their own document
(indicated by the --- sequence), as follows:
kind: ConfigMap apiVersion: v1 metadata: name: demo data: application.yml: |- greeting: message: Say Hello to the World farewell: message: Say Goodbye --- spring: profiles: development greeting: message: Say Hello to the Developers farewell: message: Say Goodbye to the Developers --- spring: profiles: production greeting: message: Say Hello to the Ops
In the preceding case, the configuration loaded into your Spring Application with the development profile is as follows:
greeting: message: Say Hello to the Developers farewell: message: Say Goodbye to the Developers
However, if the production profile is active, the configuration becomes:
greeting: message: Say Hello to the Ops farewell: message: Say Goodbye
If both profiles are active, the property that appears last within the ConfigMap overwrites any preceding values.
To tell Spring Boot which profile should be enabled at bootstrap, you can pass a system property to the Java
command. To do so, you can launch your Spring Boot application with an environment variable that you can define with the OpenShift
DeploymentConfig or Kubernetes ReplicationConfig resource file, as follows:
apiVersion: v1 kind: DeploymentConfig spec: replicas: 1 ... spec: containers: - env: - name: JAVA_APP_DIR value: /deployments - name: JAVA_OPTIONS value: -Dspring.profiles.active=developer
![]() | Note |
|---|---|
You should check the security configuration section. To access config maps from inside a pod you need to have the correct Kubernetes service accounts, roles and role bindings. |
Another option for using ConfigMap instances is to mount them into the Pod by running the Spring Cloud Kubernetes application
and having Spring Cloud Kubernetes read them from the file system.
This behavior is controlled by the spring.cloud.kubernetes.config.paths property. You can use it in
addition to or instead of the mechanism described earlier.
You can specify multiple (exact) file paths in spring.cloud.kubernetes.config.paths by using the , delimiter.
![]() | Note |
|---|---|
You have to provide the full exact path to each property file, because directories are not being recursively parsed. |
Table 5.1. Properties:
| Name | Type | Default | Description |
|---|---|---|---|
|
|
| Enable or disable consuming |
|
|
| Enable Secrets |
|
|
| Sets the name of |
|
| Client namespace | Sets the Kubernetes namespace where to lookup |
|
|
| Sets the paths where |
Kubernetes has the notion of Secrets for storing
sensitive data such as passwords, OAuth tokens, and so on. This project provides integration with Secrets to make secrets
accessible by Spring Boot applications. You can explicitly enable or disable This feature by setting the spring.cloud.kubernetes.secrets.enabled property.
When enabled, the SecretsPropertySource looks up Kubernetes for Secrets from the following sources:
spring.application.name)Note that, by default, consuming Secrets through the API (points 2 and 3 above) is not enabled for security reasons. Further, we recommend that containers share secrets through mounted volumes. If you enable consuming Secrets through the API, we recommend that you limit access to Secrets by using an [authorization policy, such as RBAC](https://kubernetes.io/docs/concepts/configuration/secret/#best-practices).
If the secrets are found, their data is made available to the application.
Assume that we have a spring boot application named demo that uses properties to read its database
configuration. We can create a Kubernetes secret by using the following command:
oc create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd
The preceding command would create the following secret (which you can see by using oc get secrets db-secret -o yaml):
apiVersion: v1 data: password: cDQ1NXcwcmQ= username: dXNlcg== kind: Secret metadata: creationTimestamp: 2017-07-04T09:15:57Z name: db-secret namespace: default resourceVersion: "357496" selfLink: /api/v1/namespaces/default/secrets/db-secret uid: 63c89263-6099-11e7-b3da-76d6186905a8 type: Opaque
Note that the data contains Base64-encoded versions of the literal provided by the create command.
Your application can then use this secret — for example, by exporting the secret’s value as environment variables:
apiVersion: v1 kind: Deployment metadata: name: ${project.artifactId} spec: template: spec: containers: - env: - name: DB_USERNAME valueFrom: secretKeyRef: name: db-secret key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: db-secret key: password
You can select the Secrets to consume in a number of ways:
By listing the directories where secrets are mapped:
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets/db-secret,etc/secrets/postgresql
If you have all the secrets mapped to a common root, you can set them like:
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
By setting a named secret:
-Dspring.cloud.kubernetes.secrets.name=db-secret
By defining a list of labels:
-Dspring.cloud.kubernetes.secrets.labels.broker=activemq -Dspring.cloud.kubernetes.secrets.labels.db=postgresql
Table 5.2. Properties:
| Name | Type | Default | Description |
|---|---|---|---|
|
|
| Enables or disables consuming secrets through APIs (examples 2 and 3) |
|
|
| Enable Secrets |
|
|
| Sets the name of the secret to look up |
|
| Client namespace | Sets the Kubernetes namespace where to look up |
|
|
| Sets the labels used to lookup secrets |
|
|
| Sets the paths where secrets are mounted (example 1) |
Notes:
* The spring.cloud.kubernetes.secrets.labels property behaves as defined by
Map-based binding.
* The spring.cloud.kubernetes.secrets.paths property behaves as defined by
Collection-based binding.
* Access to secrets through the API may be restricted for security reasons. The preferred way is to mount secrets to the Pod.
You can find an example of an application that uses secrets (though it has not been updated to use the new spring-cloud-kubernetes project) at
spring-boot-camel-config
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 a related ConfigMap or
Secret changes.
By default, this feature is disabled. You can enable it by using the spring.cloud.kubernetes.reload.enabled=true configuration property (for example, in the application.properties file).
The following levels of reload are supported (by setting the spring.cloud.kubernetes.reload.strategy property):
* refresh (default): Only configuration 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 you use 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.
Assuming that the reload feature is enabled with default settings (refresh mode), the following bean is refreshed when the config map changes:
@Configuration
@ConfigurationProperties(prefix = "bean")
public class MyConfig {
private String message = "a message that can be changed live";
// getter and setters
}To see that changes effectively happen, you can create another bean that prints the message periodically, as follows
@Component public class MyBean { @Autowired private MyConfig config; @Scheduled(fixedDelay = 5000) public void hello() { System.out.println("The message is: " + config.getMessage()); } }
You can change the message printed by the application by using a ConfigMap, as follows:
apiVersion: v1 kind: ConfigMap metadata: name: reload-example data: application.properties: |- bean.message=Hello World!
Any change to the property named bean.message in the ConfigMap associated with the pod is reflected in the
output. More generally speaking, changes associated to properties prefixed with the value defined by the prefix
field of the @ConfigurationProperties annotation are detected and reflected in the application.
Associating a ConfigMap with a pod is explained earlier in this chapter.
The full example is available in spring-cloud-kubernetes-reload-example.
The reload feature supports two operating modes:
* Event (default): Watches for changes in config maps or secrets by using the Kubernetes API (web socket).
Any event produces a re-check on the configuration and, in case of changes, a reload.
The view role on the service account is required in order to listen for config map changes. A higher level role (such as edit) is required for secrets
(by default, secrets are not monitored).
* Polling: Oeriodically re-creates the configuration from config maps and secrets to see if it has changed.
You can configure the polling period by using the spring.cloud.kubernetes.reload.period property and defaults to 15 seconds.
It requires the same role as the monitored property source.
This means, for example, that using polling on file-mounted secret sources does not require particular privileges.
Table 5.3. Properties:
| Name | Type | Default | Description |
|---|---|---|---|
|
|
| The period for verifying changes when using the |
|
|
| Enables monitoring of property sources and configuration reload |
|
|
| Allow monitoring changes in config maps |
|
|
| Allow monitoring changes in secrets |
`spring.cloud.kubernetes.reload.strategy ` |
|
| The strategy to use when firing a reload ( |
|
|
| Specifies how to listen for changes in property sources ( |
Notes:
* You should not use properties under spring.cloud.kubernetes.reload in config maps or secrets. Changing such properties at runtime may lead to unexpected results.
* Deleting a property or the whole config map does not restore the original state of the beans when you use the refresh level.