From 3d766effa603e08e86f8d282da48abdcd5ef3f12 Mon Sep 17 00:00:00 2001 From: Nicola Ferraro Date: Tue, 11 Oct 2016 16:02:18 +0200 Subject: [PATCH] Adjusting configuration and adding documentation --- example/src/main/java/io/app/MyBean.java | 29 ------- .../src/main/resources/application.properties | 9 --- pom.xml | 4 +- readme.md | 77 ++++++++++++++++++- .../kubernetes-reload-example/config-map.yml | 8 ++ .../kubernetes-reload-example}/pom.xml | 43 ++++++++--- .../kubernetes-reload-example/readme.md | 54 +++++++++++++ .../cloud/kubernetes/examples}/App.java | 4 +- .../cloud/kubernetes/examples/MyBean.java | 19 +++++ .../cloud/kubernetes/examples/MyConfig.java | 20 +++++ .../src/main/resources/application.properties | 9 +++ spring-cloud-kubernetes-examples/pom.xml | 23 ++++++ 12 files changed, 246 insertions(+), 53 deletions(-) delete mode 100644 example/src/main/java/io/app/MyBean.java delete mode 100644 example/src/main/resources/application.properties create mode 100644 spring-cloud-kubernetes-examples/kubernetes-reload-example/config-map.yml rename {example => spring-cloud-kubernetes-examples/kubernetes-reload-example}/pom.xml (51%) create mode 100644 spring-cloud-kubernetes-examples/kubernetes-reload-example/readme.md rename {example/src/main/java/io/app => spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples}/App.java (66%) create mode 100644 spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyBean.java create mode 100644 spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyConfig.java create mode 100644 spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/resources/application.properties create mode 100644 spring-cloud-kubernetes-examples/pom.xml diff --git a/example/src/main/java/io/app/MyBean.java b/example/src/main/java/io/app/MyBean.java deleted file mode 100644 index 76569e3d..00000000 --- a/example/src/main/java/io/app/MyBean.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.app; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -/** - * - */ -@Component -@ConfigurationProperties(prefix = "bean") -public class MyBean { - - private String message; - - @Scheduled(fixedDelay = 5000) - public void hello() { - System.out.println("The message is: " + message); - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - -} diff --git a/example/src/main/resources/application.properties b/example/src/main/resources/application.properties deleted file mode 100644 index 358fdac4..00000000 --- a/example/src/main/resources/application.properties +++ /dev/null @@ -1,9 +0,0 @@ -spring.application.name=example - - -#spring.cloud.kubernetes.reload.strategy=refresh -#spring.cloud.kubernetes.reload.mode=polling -#spring.cloud.kubernetes.reload.period=2000 -#spring.cloud.kubernetes.reload.monitoring-config-maps=false -#spring.cloud.kubernetes.reload.monitoring-secrets=true -#spring.cloud.kubernetes.reload.enabled=true diff --git a/pom.xml b/pom.xml index 14e1fdf3..70b5d9a2 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,7 @@ 1.4.14 0.0.4 1.16.8 + 5.2.4.Final 2.5 1.0-groovy-2.3 1.4.1.RELEASE @@ -90,6 +91,7 @@ 3.5 2.19.1 + 3.1.69 1.2 0.3.4 @@ -106,7 +108,7 @@ spring-cloud-starter-kubernetes-netflix spring-cloud-starter-kubernetes-zipkin spring-cloud-starter-kubernetes-all - example + spring-cloud-kubernetes-examples diff --git a/readme.md b/readme.md index 58f20cda..88d340fb 100644 --- a/readme.md +++ b/readme.md @@ -11,6 +11,7 @@ - [PropertySource](#kubernetes-propertysource) - [ConfigMap PropertySource](#configmap-propertysource) - [Secrets PropertySource](#secrets-propertysource) + - [PropertySource Reload](#propertysource-reload) - [Pod Health Indicator](#pod-health-indicator) - [Transparency](#transparency) *(its transparent wether the code runs in or outside of Kubernetes)* - [Kubernetes Profile Autoconfiguration](#kubernetes-profile-autoconfiguration) @@ -199,13 +200,13 @@ You can select the Secrets to consume in a number of ways: #### PropertySource Reload 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 its related ConfigMap or Secret change. +The reload feature of Spring Cloud Kubernetes is able to trigger an application reload when a related ConfigMap or Secret change. This feature is disabled by default and can be enabled using the configuration property `spring.cloud.kubernetes.reload.enabled=true` (eg. in the *application.properties* file). The following levels of reload are supported (property `spring.cloud.kubernetes.reload.strategy`): -- **refresh (default)**: only spring beans annotated with `@ConfigurationProperties` or `@RefreshScope` are reloaded. +- **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. @@ -214,8 +215,78 @@ This reload level leverages the refresh feature of Spring Cloud Context. Example: -Assuming that the reload feature is enabled with default settings, the following bean will be refreshed +Assuming that the reload feature is enabled with default settings (*refresh* mode), the following bean will be refreshed when the config map changes: +```java +@Configuration +@ConfigurationProperties(prefix = "bean") +public class MyConfig { + + private String message = "a message that can be changed live"; + + // getter and setters + +} +``` + +A way to see that changes effectively happen is creating another bean that prints the message periodically. + +```java +@Component +public class MyBean { + + @Autowired + private MyConfig config; + + @Scheduled(fixedDelay = 5000) + public void hello() { + System.out.println("The message is: " + config.getMessage()); + } +} +``` + +The message printed by the application can be changed using a config map like the following one: + +```yml +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 Config Map associated to the pod will be reflected in the output of the program +(more details [here](#configmap-propertysource) about how to associate a Config Map to a pod). + +The full example is available in [spring-cloud-kubernetes-reload-example](spring-cloud-kubernetes-examples/spring-cloud-kubernetes-reload-example). + +The reload feature supports two operating modes: +- **event (default)**: watches for changes in config maps or secrets using the Kubernetes API (web socket). +Any event will produce a re-check on the configuration and a reload in case of changes. +The `view` role on the service account is required in order to listen for config map changes. A higher level role (eg. `edit`) is required for secrets +(secrets are not monitored by default). +- **polling**: re-creates the configuration periodically from config maps and secrets to see if it has changed. +The polling period can be configured using the property `spring.cloud.kubernetes.reload.period` 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. + +Properties: + +| Name | Type | Default | Description +| --- | --- | --- | --- +| spring.cloud.kubernetes.reload.enabled | Boolean | false | Enables monitoring of property sources and configuration reload +| spring.cloud.kubernetes.reload.monitoring-config-maps | Boolean | true | Allow monitoring changes in config maps +| spring.cloud.kubernetes.reload.monitoring-secrets | Boolean | false | Allow monitoring changes in secrets +| spring.cloud.kubernetes.reload.strategy | Enum | refresh | The strategy to use when firing a reload (*refresh*, *restart_context*, *shutdown*) +| spring.cloud.kubernetes.reload.mode | Enum | event | Specifies how to listen for changes in property sources (*event*, *polling*) +| spring.cloud.kubernetes.reload.period | Long | 15000 | The period in milliseconds for verifying changes when using the *polling* strategy + +Notes: +- Properties under *spring.cloud.kubernetes.reload.** should not be used 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 using the *refresh* level. + ### Pod Health Indicator diff --git a/spring-cloud-kubernetes-examples/kubernetes-reload-example/config-map.yml b/spring-cloud-kubernetes-examples/kubernetes-reload-example/config-map.yml new file mode 100644 index 00000000..29be9bbe --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/config-map.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: reload-example +data: + application.properties: |- + bean.message=Hello World! + another.property=value \ No newline at end of file diff --git a/example/pom.xml b/spring-cloud-kubernetes-examples/kubernetes-reload-example/pom.xml similarity index 51% rename from example/pom.xml rename to spring-cloud-kubernetes-examples/kubernetes-reload-example/pom.xml index b782b635..71d3314d 100644 --- a/example/pom.xml +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/pom.xml @@ -3,14 +3,28 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - spring-cloud-kubernetes-project + spring-cloud-kubernetes-examples io.fabric8 0.1-SNAPSHOT 4.0.0 - example + kubernetes-reload-example + Fabric8 :: Spring Cloud Kubernetes :: Examples :: Reload + Example demostrating how to use the configuration reload feature. + + + + + org.springframework.boot + spring-boot-dependencies + pom + import + ${spring-boot.version} + + + @@ -19,20 +33,29 @@ ${project.version} - - - - - org.springframework.boot spring-boot-starter - 1.4.1.RELEASE + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-undertow + + org.hibernate hibernate-validator - 5.2.4.Final + ${hibernate-validator.version} @@ -42,7 +65,7 @@ io.fabric8 fabric8-maven-plugin - 3.1.69 + ${fabric8.maven.plugin.version} diff --git a/spring-cloud-kubernetes-examples/kubernetes-reload-example/readme.md b/spring-cloud-kubernetes-examples/kubernetes-reload-example/readme.md new file mode 100644 index 00000000..6c65369b --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/readme.md @@ -0,0 +1,54 @@ +## Kubernetes Reload Example + +This example demonstrate how to use the reload feature to change the configuration of a spring-boot application at runtime. + +The application consists of a timed bean that periodically prints a message to the console. +The message can be changed using a config map. + +### Running the example + +When using Openshift, you must assign the `view` role to the *default* service account in the current project: + +``` +oc policy add-role-to-user view --serviceaccount=default +``` + +You can deploy the application using the fabric8 maven plugin: + +``` +mvn clean install fabric8:deploy +``` + +### Changing the configuration + +Create a yaml file with the following contents: + +```yml +apiVersion: v1 +kind: ConfigMap +metadata: + name: reload-example +data: + application.properties: |- + bean.message=Hello World! + another.property=value +``` + +A sample config map is provided with this example in the *config-map.yml* file. + +To deploy the config map, just run the following command: + +``` +oc create -f config-map.yml +``` + +As soon as the config map is deployed, the output of the application changes accordingly. +The config map can be now edited with the following command: + +``` +oc edit configmap reload-example +``` + +Changes are applied immediately when using the *event* reload mode. + +The name of the config map (*"reload-example"*) matches the name of the application as declared in the *application.properties* file. diff --git a/example/src/main/java/io/app/App.java b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/App.java similarity index 66% rename from example/src/main/java/io/app/App.java rename to spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/App.java index 306d88aa..480ab822 100644 --- a/example/src/main/java/io/app/App.java +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/App.java @@ -1,12 +1,14 @@ -package io.app; +package io.fabric8.spring.cloud.kubernetes.examples; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.scheduling.annotation.EnableScheduling; /** * */ @SpringBootApplication +@EnableScheduling public class App { public static void main(String[] args) { diff --git a/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyBean.java b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyBean.java new file mode 100644 index 00000000..b735f7df --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyBean.java @@ -0,0 +1,19 @@ +package io.fabric8.spring.cloud.kubernetes.examples; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +public class MyBean { + + @Autowired + private MyConfig config; + + @Scheduled(fixedDelay = 5000) + public void hello() { + System.out.println("The message is: " + config.getMessage()); + } + + +} diff --git a/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyConfig.java b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyConfig.java new file mode 100644 index 00000000..19fe9e82 --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/java/io/fabric8/spring/cloud/kubernetes/examples/MyConfig.java @@ -0,0 +1,20 @@ +package io.fabric8.spring.cloud.kubernetes.examples; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "bean") +public class MyConfig { + + private String message = "a message that can be changed live"; + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + +} diff --git a/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/resources/application.properties b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/resources/application.properties new file mode 100644 index 00000000..ca0bfe4a --- /dev/null +++ b/spring-cloud-kubernetes-examples/kubernetes-reload-example/src/main/resources/application.properties @@ -0,0 +1,9 @@ +spring.application.name=reload-example + +spring.cloud.kubernetes.reload.enabled=true + +#spring.cloud.kubernetes.reload.strategy=restart_context +#spring.cloud.kubernetes.reload.mode=polling +#spring.cloud.kubernetes.reload.period=5000 +#spring.cloud.kubernetes.reload.monitoring-config-maps=false +#spring.cloud.kubernetes.reload.monitoring-secrets=true diff --git a/spring-cloud-kubernetes-examples/pom.xml b/spring-cloud-kubernetes-examples/pom.xml new file mode 100644 index 00000000..5c2d0304 --- /dev/null +++ b/spring-cloud-kubernetes-examples/pom.xml @@ -0,0 +1,23 @@ + + + + spring-cloud-kubernetes-project + io.fabric8 + 0.1-SNAPSHOT + + 4.0.0 + + spring-cloud-kubernetes-examples + pom + + Fabric8 :: Spring Cloud Kubernetes :: Examples + Examples showing how to use features of Spring Cloud Kubernetes. + + + kubernetes-reload-example + + + + \ No newline at end of file