265 lines
12 KiB
Plaintext
265 lines
12 KiB
Plaintext
[spring-cloud-kubernetes-configuration-watcher]
|
|
= Spring Cloud Kubernetes Configuration Watcher
|
|
|
|
Kubernetes provides the ability to https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#add-configmap-data-to-a-volume[mount a ConfigMap or Secret as a volume]
|
|
in the container of your application. When the contents of the ConfigMap or Secret changes, the https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/#mounted-configmaps-are-updated-automatically[mounted volume will be updated with those changes].
|
|
|
|
However, Spring Boot will not automatically update those changes unless you restart the application. Spring Cloud
|
|
provides the ability refresh the application context without restarting the application by either hitting the
|
|
actuator endpoint `/refresh` or via publishing a `RefreshRemoteApplicationEvent` using Spring Cloud Bus.
|
|
|
|
To achieve this configuration refresh of a Spring Cloud app running on Kubernetes, you can deploy the Spring Cloud
|
|
Kubernetes Configuration Watcher controller into your Kubernetes cluster.
|
|
|
|
The application is published as a container and is available on https://hub.docker.com/r/springcloud/spring-cloud-kubernetes-configuration-watcher[Docker Hub].
|
|
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 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
|
|
|
|
Below is a sample deployment YAML you can use to deploy the Kubernetes Configuration Watcher to Kubernetes.
|
|
|
|
[source,yaml,subs="attributes+"]
|
|
----
|
|
---
|
|
apiVersion: v1
|
|
kind: List
|
|
items:
|
|
- apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
labels:
|
|
app: spring-cloud-kubernetes-configuration-watcher
|
|
name: spring-cloud-kubernetes-configuration-watcher
|
|
spec:
|
|
ports:
|
|
- name: http
|
|
port: 8888
|
|
targetPort: 8888
|
|
selector:
|
|
app: spring-cloud-kubernetes-configuration-watcher
|
|
type: ClusterIP
|
|
- apiVersion: v1
|
|
kind: ServiceAccount
|
|
metadata:
|
|
labels:
|
|
app: spring-cloud-kubernetes-configuration-watcher
|
|
name: spring-cloud-kubernetes-configuration-watcher
|
|
- apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: RoleBinding
|
|
metadata:
|
|
labels:
|
|
app: spring-cloud-kubernetes-configuration-watcher
|
|
name: spring-cloud-kubernetes-configuration-watcher:view
|
|
roleRef:
|
|
kind: Role
|
|
apiGroup: rbac.authorization.k8s.io
|
|
name: namespace-reader
|
|
subjects:
|
|
- kind: ServiceAccount
|
|
name: spring-cloud-kubernetes-configuration-watcher
|
|
- apiVersion: rbac.authorization.k8s.io/v1
|
|
kind: Role
|
|
metadata:
|
|
namespace: default
|
|
name: namespace-reader
|
|
rules:
|
|
- apiGroups: ["", "extensions", "apps"]
|
|
resources: ["configmaps", "pods", "services", "endpoints", "secrets"]
|
|
verbs: ["get", "list", "watch"]
|
|
- apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: spring-cloud-kubernetes-configuration-watcher-deployment
|
|
spec:
|
|
selector:
|
|
matchLabels:
|
|
app: spring-cloud-kubernetes-configuration-watcher
|
|
template:
|
|
metadata:
|
|
labels:
|
|
app: spring-cloud-kubernetes-configuration-watcher
|
|
spec:
|
|
serviceAccount: spring-cloud-kubernetes-configuration-watcher
|
|
containers:
|
|
- name: spring-cloud-kubernetes-configuration-watcher
|
|
image: springcloud/spring-cloud-kubernetes-configuration-watcher:{spring-cloud-version}
|
|
imagePullPolicy: IfNotPresent
|
|
readinessProbe:
|
|
httpGet:
|
|
port: 8888
|
|
path: /actuator/health/readiness
|
|
livenessProbe:
|
|
httpGet:
|
|
port: 8888
|
|
path: /actuator/health/liveness
|
|
ports:
|
|
- containerPort: 8888
|
|
|
|
----
|
|
|
|
The Service Account and associated Role Binding is important for Spring Cloud Kubernetes Configuration to work properly.
|
|
The controller needs access to read data about ConfigMaps, Pods, Services, Endpoints and Secrets in the Kubernetes cluster.
|
|
|
|
## 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
|
|
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:
|
|
|
|
`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.
|
|
|
|
For example:
|
|
|
|
[source,yaml]
|
|
----
|
|
kind: ConfigMap
|
|
apiVersion: v1
|
|
metadata:
|
|
name: example-configmap
|
|
labels:
|
|
spring.cloud.kubernetes.config: "true"
|
|
annotations:
|
|
spring.cloud.kubernetes.configmap.apps: "app-a, app-b"
|
|
----
|
|
|
|
## HTTP Implementation
|
|
|
|
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.
|
|
|
|
You can also configure the configuration watcher to call the instances `shutdown` actuator endpoint. To do this you can set
|
|
`spring.cloud.kubernetes.configuration.watcher.refresh-strategy=shutdown`.
|
|
|
|
### Non-Default Management Port and Actuator Path
|
|
|
|
If the application is using a non-default actuator path and/or using a different port for the management endpoints, the Kubernetes service for the application
|
|
can add an annotation called `boot.spring.io/actuator` and set its value to the path and port used by the application. For example
|
|
|
|
[source,yaml]
|
|
----
|
|
apiVersion: v1
|
|
kind: Service
|
|
metadata:
|
|
labels:
|
|
app: config-map-demo
|
|
name: config-map-demo
|
|
annotations:
|
|
boot.spring.io/actuator: http://:9090/myactuator/home
|
|
spec:
|
|
ports:
|
|
- name: http
|
|
port: 8080
|
|
targetPort: 8080
|
|
selector:
|
|
app: config-map-demo
|
|
----
|
|
|
|
|
|
Another way you can choose to configure the actuator path and/or management port is by setting
|
|
`spring.cloud.kubernetes.configuration.watcher.actuatorPath` and `spring.cloud.kubernetes.configuration.watcher.actuatorPort`.
|
|
|
|
## Messaging Implementation
|
|
|
|
The messaging implementation can be enabled by setting profile to either `bus-amqp` (RabbitMQ) or `bus-kafka` (Kafka) when the Spring Cloud Kubernetes Configuration Watcher
|
|
application is deployed to Kubernetes. By default, when using the messaging implementation the configuration watcher will send a `RefreshRemoteApplicationEvent` using
|
|
Spring Cloud Bus to all application instances. This will cause the application instances to refresh the application's configuration properties without
|
|
restarting the instance.
|
|
|
|
You can also configure the configuration to shut down the application instances in order to refresh the application's configuration properties.
|
|
When the application shuts down, Kubernetes will restart the application instance and the new configuration properties will be loaded. To use
|
|
this strategy set `spring.cloud.kubernetes.configuration.watcher.refresh-strategy=shutdown`.
|
|
|
|
## Configuring RabbitMQ
|
|
|
|
When the `bus-amqp` profile is enabled you will need to configure Spring RabbitMQ to point it to the location of the RabbitMQ
|
|
instance you would like to use as well as any credentials necessary to authenticate. This can be done
|
|
by setting the standard Spring RabbitMQ properties, for example
|
|
|
|
[source,yaml]
|
|
----
|
|
spring:
|
|
rabbitmq:
|
|
username: user
|
|
password: password
|
|
host: rabbitmq
|
|
----
|
|
|
|
## Configuring Kafka
|
|
|
|
When the `bus-kafka` profile is enabled you will need to configure Spring Kafka to point it to the location of the Kafka Broker
|
|
instance you would like to use. This can be done by setting the standard Spring Kafka properties, for example
|
|
|
|
[source,yaml]
|
|
----
|
|
spring:
|
|
kafka:
|
|
producer:
|
|
bootstrap-servers: localhost:9092
|
|
----
|