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.core
pool.size.maximum
This 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.