399 lines
98 KiB
HTML
399 lines
98 KiB
HTML
<html><head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>Spring Cloud Kubernetes</title><link rel="stylesheet" type="text/css" href="css/manual-singlepage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.79.1"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div lang="en" class="book"><div class="titlepage"><div><div><h1 class="title"><a name="d0e3"></a>Spring Cloud Kubernetes</h1></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl class="toc"><dt><span class="preface"><a href="#d0e9"></a></span></dt><dt><span class="chapter"><a href="#_why_do_you_need_spring_cloud_kubernetes">1. Why do you need Spring Cloud Kubernetes?</a></span></dt><dt><span class="chapter"><a href="#_starters">2. Starters</a></span></dt><dt><span class="chapter"><a href="#_discoveryclient_for_kubernetes">3. DiscoveryClient for Kubernetes</a></span></dt><dt><span class="chapter"><a href="#_kubernetes_native_service_discovery">4. Kubernetes native service discovery</a></span></dt><dt><span class="chapter"><a href="#_kubernetes_propertysource_implementations">5. Kubernetes PropertySource implementations</a></span></dt><dd><dl><dt><span class="section"><a href="#configmap-propertysource">5.1. Using a <code class="literal">ConfigMap</code> <code class="literal">PropertySource</code></a></span></dt><dt><span class="section"><a href="#_secrets_propertysource">5.2. Secrets PropertySource</a></span></dt><dt><span class="section"><a href="#_propertysource_reload">5.3. <code class="literal">PropertySource</code> Reload</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_ribbon_discovery_in_kubernetes">6. Ribbon Discovery in Kubernetes</a></span></dt><dt><span class="chapter"><a href="#_kubernetes_ecosystem_awareness">7. Kubernetes Ecosystem Awareness</a></span></dt><dd><dl><dt><span class="section"><a href="#_kubernetes_profile_autoconfiguration">7.1. Kubernetes Profile Autoconfiguration</a></span></dt><dt><span class="section"><a href="#_istio_awareness">7.2. Istio Awareness</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_pod_health_indicator">8. Pod Health Indicator</a></span></dt><dt><span class="chapter"><a href="#_leader_election">9. Leader Election</a></span></dt><dt><span class="chapter"><a href="#_security_configurations_inside_kubernetes">10. Security Configurations Inside Kubernetes</a></span></dt><dd><dl><dt><span class="section"><a href="#_namespace">10.1. Namespace</a></span></dt><dt><span class="section"><a href="#_service_account">10.2. Service Account</a></span></dt></dl></dd><dt><span class="chapter"><a href="#_service_registry_implementation">11. Service Registry Implementation</a></span></dt><dt><span class="chapter"><a href="#_examples">12. Examples</a></span></dt><dt><span class="chapter"><a href="#_other_resources">13. Other Resources</a></span></dt><dt><span class="chapter"><a href="#_building">14. Building</a></span></dt><dd><dl><dt><span class="section"><a href="#_basic_compile_and_test">14.1. Basic Compile and Test</a></span></dt><dt><span class="section"><a href="#_documentation">14.2. Documentation</a></span></dt><dt><span class="section"><a href="#_working_with_the_code">14.3. Working with the code</a></span></dt><dd><dl><dt><span class="section"><a href="#_importing_into_eclipse_with_m2eclipse">14.3.1. Importing into eclipse with m2eclipse</a></span></dt><dt><span class="section"><a href="#_importing_into_eclipse_without_m2eclipse">14.3.2. Importing into eclipse without m2eclipse</a></span></dt></dl></dd></dl></dd><dt><span class="chapter"><a href="#_contributing">15. Contributing</a></span></dt><dd><dl><dt><span class="section"><a href="#_sign_the_contributor_license_agreement">15.1. Sign the Contributor License Agreement</a></span></dt><dt><span class="section"><a href="#_code_of_conduct">15.2. Code of Conduct</a></span></dt><dt><span class="section"><a href="#_code_conventions_and_housekeeping">15.3. Code Conventions and Housekeeping</a></span></dt><dt><span class="section"><a href="#_checkstyle">15.4. Checkstyle</a></span></dt><dd><dl><dt><span class="section"><a href="#_checkstyle_configuration">15.4.1. Checkstyle configuration</a></span></dt></dl></dd><dt><span class="section"><a href="#_ide_setup">15.5. IDE setup</a></span></dt><dd><dl><dt><span class="section"><a href="#_intellij_idea">15.5.1. Intellij IDEA</a></span></dt></dl></dd></dl></dd></dl></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a name="d0e9" href="#d0e9"></a></h1></div></div></div><p>This reference guide covers how to use Spring Cloud Kubernetes.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_why_do_you_need_spring_cloud_kubernetes" href="#_why_do_you_need_spring_cloud_kubernetes"></a>1. Why do you need Spring Cloud Kubernetes?</h1></div></div></div><p>Spring Cloud Kubernetes provide Spring Cloud common interface implementations that consume Kubernetes native services.
|
|
The main objective of the projects provided in this repository is to facilitate the integration of Spring Cloud and Spring Boot applications running inside Kubernetes.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_starters" href="#_starters"></a>2. Starters</h1></div></div></div><p>Starters are convenient dependency descriptors you can include in your
|
|
application. Include a starter to get the dependencies and Spring Boot
|
|
auto-configuration for a feature set.</p><div class="informaltable"><table class="informaltable" style="border-collapse: collapse;border-top: 1px solid ; border-bottom: 1px solid ; border-left: 1px solid ; border-right: 1px solid ; "><colgroup><col class="col_1"><col class="col_2"></colgroup><thead><tr><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Starter</th><th style="border-bottom: 1px solid ; " align="left" valign="top">Features</th></tr></thead><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p><a class="link" href="#_discoveryclient_for_kubernetes" title="3. DiscoveryClient for Kubernetes">Discovery Client</a> implementation that
|
|
resolves service names to Kubernetes Services.</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes-config<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Load application properties from Kubernetes
|
|
<a class="link" href="#">ConfigMaps</a> and <a class="link" href="#_secrets_propertysource" title="5.2 Secrets PropertySource">Secrets</a>.
|
|
<a class="link" href="#">Reload</a> application properties when a ConfigMap or
|
|
Secret changes.</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes-ribbon<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p><a class="link" href="#">Ribbon</a> client-side load balancer with
|
|
server list obtained from Kubernetes Endpoints.</p></td></tr><tr><td style="border-right: 1px solid ; " align="left" valign="top"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes-all<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></td><td style="" align="left" valign="top"><p>All Spring Cloud Kubernetes features.</p></td></tr></tbody></table></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_discoveryclient_for_kubernetes" href="#_discoveryclient_for_kubernetes"></a>3. DiscoveryClient for Kubernetes</h1></div></div></div><p>This project provides an implementation of <a class="link" href="https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/discovery/DiscoveryClient.java" target="_top">Discovery Client</a>
|
|
for <a class="link" href="https://kubernetes.io" target="_top">Kubernetes</a>.
|
|
This client lets you query Kubernetes endpoints (see <a class="link" href="https://kubernetes.io/docs/user-guide/services/" target="_top">services</a>) by name.
|
|
A service is typically exposed by the Kubernetes API server as a collection of endpoints that represent <code class="literal">http</code> and <code class="literal">https</code> addresses and that a client can
|
|
access from a Spring Boot application running as a pod. This discovery feature is also used by the Spring Cloud Kubernetes Ribbon project
|
|
to fetch the list of the endpoints defined for an application to be load balanced.</p><p>This is something that you get for free by adding the following dependency inside your project:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><p>To enable loading of the <code class="literal">DiscoveryClient</code>, add <code class="literal">@EnableDiscoveryClient</code> to the according configuration or application class, as the following example shows:</p><div class="informalexample"><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
|
<em><span class="hl-annotation" style="color: gray">@EnableDiscoveryClient</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
|
SpringApplication.run(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>, args);
|
|
}
|
|
}</pre></div><p>Then you can inject the client in your code simply by autowiring it, as the following example shows:</p><div class="informalexample"><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> DiscoveryClient discoveryClient;</pre></div><p>If, for any reason, you need to disable the <code class="literal">DiscoveryClient</code>, you can set the following property in <code class="literal">application.properties</code>:</p><div class="informalexample"><pre class="screen">spring.cloud.kubernetes.discovery.enabled=false</pre></div><p>Some Spring Cloud components use the <code class="literal">DiscoveryClient</code> in order to obtain information about the local service instance. For
|
|
this to work, you need to align the Kubernetes service name with the <code class="literal">spring.application.name</code> property.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_kubernetes_native_service_discovery" href="#_kubernetes_native_service_discovery"></a>4. Kubernetes native service discovery</h1></div></div></div><p>Kubernetes itself is capable of (server side) service discovery (see: <a class="link" href="https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services" target="_top">https://kubernetes.io/docs/concepts/services-networking/service/#discovering-services</a>).
|
|
Using native kubernetes service discovery ensures compatibility with additional tooling, such as Istio (<a class="link" href="https://istio.io" target="_top">https://istio.io</a>), a service mesh that is capable of load balancing, ribbon, circuit breaker, failover, and much more.</p><p>The caller service then need only refer to names resolvable in a particular Kubernetes cluster. A simple implementation might use a spring <code class="literal">RestTemplate</code> that refers to a fully qualified domain name (FQDN), such as <code class="literal"><a class="link" href="https://{service-name}.{namespace}.svc.{cluster}.local:{service-port}" target="_top">https://{service-name}.{namespace}.svc.{cluster}.local:{service-port}</a></code>.</p><p>Additionally, you can use Hystrix for:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Circuit breaker implementation on the caller side, by annotating the spring boot application class with <code class="literal">@EnableCircuitBreaker</code></li><li class="listitem">Fallback functionality, by annotating the respective method with <code class="literal">@HystrixCommand(fallbackMethod=</code></li></ul></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_kubernetes_propertysource_implementations" href="#_kubernetes_propertysource_implementations"></a>5. Kubernetes PropertySource implementations</h1></div></div></div><p>The most common approach to configuring your Spring Boot application is to create an <code class="literal">application.properties</code> or <code class="literal">applicaiton.yaml</code> or
|
|
an <code class="literal">application-profile.properties</code> or <code class="literal">application-profile.yaml</code> 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.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="configmap-propertysource" href="#configmap-propertysource"></a>5.1 Using a <code class="literal">ConfigMap</code> <code class="literal">PropertySource</code></h2></div></div></div><p>Kubernetes provides a resource named <a class="link" href="https://kubernetes.io/docs/user-guide/configmap/" target="_top"><code class="literal">ConfigMap</code></a> to externalize the
|
|
parameters to pass to your application in the form of key-value pairs or embedded <code class="literal">application.properties</code> or <code class="literal">application.yaml</code> files.
|
|
The <a class="link" href="./spring-cloud-kubernetes-config" target="_top">Spring Cloud Kubernetes Config</a> project makes Kubernetes <code class="literal">ConfigMap</code> instances available
|
|
during application bootstrapping and triggers hot reloading of beans or Spring context when changes are detected on
|
|
observed <code class="literal">ConfigMap</code> instances.</p><p>The default behavior is to create a <code class="literal">ConfigMapPropertySource</code> based on a Kubernetes <code class="literal">ConfigMap</code> that has a <code class="literal">metadata.name</code> value of either the name of
|
|
your Spring application (as defined by its <code class="literal">spring.application.name</code> property) or a custom name defined within the
|
|
<code class="literal">bootstrap.properties</code> file under the following key: <code class="literal">spring.cloud.kubernetes.config.name</code>.</p><p>However, more advanced configuration is possible where you can use multiple <code class="literal">ConfigMap</code> instances.
|
|
The <code class="literal">spring.cloud.kubernetes.config.sources</code> list makes this possible.
|
|
For example, you could define the following <code class="literal">ConfigMap</code> instances:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spring</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: cloud-k8s-app
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> cloud</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> kubernetes</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> config</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: default-name
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> namespace</span>: default-namespace
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> sources</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: c1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - namespace</span>: n2
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-comment"># Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - namespace</span>: n3
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: c3</pre></div><p>In the preceding example, if <code class="literal">spring.cloud.kubernetes.config.namespace</code> had not been set,
|
|
the <code class="literal">ConfigMap</code> named <code class="literal">c1</code> would be looked up in the namespace that the application runs.</p><p>Any matching <code class="literal">ConfigMap</code> that is found is processed as follows:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Apply individual configuration properties.</li><li class="listitem">Apply as <code class="literal">yaml</code> the content of any property named <code class="literal">application.yaml</code>.</li><li class="listitem">Apply as a properties file the content of any property named <code class="literal">application.properties</code>.</li></ul></div><p>The single exception to the aforementioned flow is when the <code class="literal">ConfigMap</code> contains a <span class="strong"><strong>single</strong></span> key that indicates
|
|
the file is a YAML or properties file. In that case, the name of the key does NOT have to be <code class="literal">application.yaml</code> or
|
|
<code class="literal">application.properties</code> (it can be anything) and the value of the property is treated correctly.
|
|
This features facilitates the use case where the <code class="literal">ConfigMap</code> was created by using something like the following:</p><div class="informalexample"><pre class="screen">kubectl create configmap game-config --from-file=/path/to/app-config.yaml</pre></div><p>Assume that we have a Spring Boot application named <code class="literal">demo</code> that uses the following properties to read its thread pool
|
|
configuration.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">pool.size.core</code></li><li class="listitem"><code class="literal">pool.size.maximum</code></li></ul></div><p>This can be externalized to config map in <code class="literal">yaml</code> format as follows:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: demo
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> pool.size.core</span>: <span class="hl-number">1</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> pool.size.max</span>: <span class="hl-number">16</span></pre></div><p>Individual properties work fine for most cases. However, sometimes, embedded <code class="literal">yaml</code> is more convenient. In this case, we
|
|
use a single property named <code class="literal">application.yaml</code> to embed our <code class="literal">yaml</code>, as follows:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: demo
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application.yaml</span>: |-
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> pool</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> size</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> core</span>: <span class="hl-number">1</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> max</span>:<span class="hl-number">16</span></pre></div><p>The following example also works:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: demo
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> custom-name.yaml</span>: |-
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> pool</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> size</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> core</span>: <span class="hl-number">1</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> max</span>:<span class="hl-number">16</span></pre></div><p>You can also configure Spring Boot applications differently depending on active profiles that are merged together
|
|
when the <code class="literal">ConfigMap</code> is read. You can provide different property values for different profiles by using an
|
|
<code class="literal">application.properties</code> or <code class="literal">application.yaml</code> property, specifying profile-specific values, each in their own document
|
|
(indicated by the <code class="literal">---</code> sequence), as follows:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: demo
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application.yml</span>: |-
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the World
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye
|
|
---
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spring</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> profiles</span>: development
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Developers
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye to the Developers
|
|
---
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spring</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> profiles</span>: production
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Ops</pre></div><p>In the preceding case, the configuration loaded into your Spring Application with the <code class="literal">development</code> profile is as follows:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Developers
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye to the Developers</pre></div><p>However, if the <code class="literal">production</code> profile is active, the configuration becomes:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> greeting</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Hello to the Ops
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> farewell</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> message</span>: Say Goodbye</pre></div><p>If both profiles are active, the property that appears last within the <code class="literal">ConfigMap</code> overwrites any preceding values.</p><p>To tell Spring Boot which <code class="literal">profile</code> 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
|
|
<code class="literal">DeploymentConfig</code> or Kubernetes <code class="literal">ReplicationConfig</code> resource file, as follows:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: DeploymentConfig
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spec</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> replicas</span>: <span class="hl-number">1</span>
|
|
...
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spec</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> containers</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - env</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: JAVA_APP_DIR
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> value</span>: /deployments
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: JAVA_OPTIONS
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> value</span>: -Dspring.profiles.active=developer</pre></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>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.</p></td></tr></table></div><p>Another option for using <code class="literal">ConfigMap</code> 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 <code class="literal">spring.cloud.kubernetes.config.paths</code> property. You can use it in
|
|
addition to or instead of the mechanism described earlier.
|
|
You can specify multiple (exact) file paths in <code class="literal">spring.cloud.kubernetes.config.paths</code> by using the <code class="literal">,</code> delimiter.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>You have to provide the full exact path to each property file, because directories are not being recursively parsed.</p></td></tr></table></div><div class="table"><a name="d0e416" href="#d0e416"></a><p class="title"><b>Table 5.1. Properties:</b></p><div class="table-contents"><table class="table" summary="Properties:" style="border-collapse: collapse;border-top: 1px solid ; border-bottom: 1px solid ; border-left: 1px solid ; border-right: 1px solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><thead><tr><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Name</th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Type</th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Default</th><th style="border-bottom: 1px solid ; " align="left" valign="top">Description</th></tr></thead><tfoot><tr><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.config.enableApi</code></p></th><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></th><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">true</code></p></th><th style="" align="left" valign="top"><p>Enable or disable consuming <code class="literal">ConfigMap</code> instances through APIs</p></th></tr></tfoot><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.config.enabled</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">true</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Enable Secrets <code class="literal">PropertySource</code></p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.config.name</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">String</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">${spring.application.name}</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Sets the name of <code class="literal">ConfigMap</code> to look up</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.config.namespace</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">String</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Client namespace</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Sets the Kubernetes namespace where to lookup</p></td></tr><tr><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.config.paths</code></p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">List</code></p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">null</code></p></td><td style="" align="left" valign="top"><p>Sets the paths where <code class="literal">ConfigMap</code> instances are mounted</p></td></tr></tbody></table></div></div><br class="table-break"></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_secrets_propertysource" href="#_secrets_propertysource"></a>5.2 Secrets PropertySource</h2></div></div></div><p>Kubernetes has the notion of <a class="link" href="https://kubernetes.io/docs/concepts/configuration/secret/" target="_top">Secrets</a> for storing
|
|
sensitive data such as passwords, OAuth tokens, and so on. This project provides integration with <code class="literal">Secrets</code> to make secrets
|
|
accessible by Spring Boot applications. You can explicitly enable or disable This feature by setting the <code class="literal">spring.cloud.kubernetes.secrets.enabled</code> property.</p><p>When enabled, the <code class="literal">SecretsPropertySource</code> looks up Kubernetes for <code class="literal">Secrets</code> from the following sources:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem">Reading recursively from secrets mounts</li><li class="listitem">Named after the application (as defined by <code class="literal">spring.application.name</code>)</li><li class="listitem">Matching some labels</li></ol></div><p>Note that, by default, consuming Secrets through the API (points 2 and 3 above) <span class="strong"><strong>is not enabled</strong></span> 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](<a class="link" href="https://kubernetes.io/docs/concepts/configuration/secret/#best-practices" target="_top">https://kubernetes.io/docs/concepts/configuration/secret/#best-practices</a>).</p><p>If the secrets are found, their data is made available to the application.</p><p>Assume that we have a spring boot application named <code class="literal">demo</code> that uses properties to read its database
|
|
configuration. We can create a Kubernetes secret by using the following command:</p><div class="informalexample"><pre class="screen">oc create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd</pre></div><p>The preceding command would create the following secret (which you can see by using <code class="literal">oc get secrets db-secret -o yaml</code>):</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> password</span>: cDQ1NXcwcmQ=
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> username</span>: dXNlcg==
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: Secret
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> creationTimestamp</span>: <span class="hl-number">2017</span>-<span class="hl-number">07</span>-<span class="hl-number">04</span>T09:<span class="hl-number">15</span>:<span class="hl-number">57</span>Z
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: db-secret
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> namespace</span>: default
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> resourceVersion</span>: <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"357496"</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> selfLink</span>: /api/v1/namespaces/default/secrets/db-secret
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> uid</span>: <span class="hl-number">63</span>c89263-<span class="hl-number">6099</span>-<span class="hl-number">11e7</span>-b3da-<span class="hl-number">76d</span>6186905a8
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">type</span>: Opaque</pre></div><p>Note that the data contains Base64-encoded versions of the literal provided by the <code class="literal">create</code> command.</p><p>Your application can then use this secret — for example, by exporting the secret’s value as environment variables:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: Deployment
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: ${project.artifactId<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">}</span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">spec</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> template</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> spec</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> containers</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - env</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: DB_USERNAME
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> valueFrom</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> secretKeyRef</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: db-secret
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> key</span>: username
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> - name</span>: DB_PASSWORD
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> valueFrom</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> secretKeyRef</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: db-secret
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> key</span>: password</pre></div><p>You can select the Secrets to consume in a number of ways:</p><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p class="simpara">By listing the directories where secrets are mapped:</p><div class="informalexample"><pre class="programlisting">-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets/db-secret,etc/secrets/postgresql</pre></div><p class="simpara">If you have all the secrets mapped to a common root, you can set them like:</p><div class="informalexample"><pre class="programlisting">-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets</pre></div></li><li class="listitem"><p class="simpara">By setting a named secret:</p><div class="informalexample"><pre class="programlisting">-Dspring.cloud.kubernetes.secrets.name=db-secret</pre></div></li><li class="listitem"><p class="simpara">By defining a list of labels:</p><div class="informalexample"><pre class="programlisting">-Dspring.cloud.kubernetes.secrets.labels.broker=activemq
|
|
-Dspring.cloud.kubernetes.secrets.labels.db=postgresql</pre></div></li></ol></div><div class="table"><a name="d0e623" href="#d0e623"></a><p class="title"><b>Table 5.2. Properties:</b></p><div class="table-contents"><table class="table" summary="Properties:" style="border-collapse: collapse;border-top: 1px solid ; border-bottom: 1px solid ; border-left: 1px solid ; border-right: 1px solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><thead><tr><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Name</th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Type</th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Default</th><th style="border-bottom: 1px solid ; " align="left" valign="top">Description</th></tr></thead><tfoot><tr><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.secrets.enableApi</code></p></th><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></th><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">false</code></p></th><th style="" align="left" valign="top"><p>Enables or disables consuming secrets through APIs (examples 2 and 3)</p></th></tr></tfoot><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.secrets.enabled</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">true</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Enable Secrets <code class="literal">PropertySource</code></p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.secrets.name</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">String</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">${spring.application.name}</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Sets the name of the secret to look up</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.secrets.namespace</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">String</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>Client namespace</p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Sets the Kubernetes namespace where to look up</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.secrets.labels</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Map</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">null</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Sets the labels used to lookup secrets</p></td></tr><tr><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.secrets.paths</code></p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">List</code></p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">null</code></p></td><td style="" align="left" valign="top"><p>Sets the paths where secrets are mounted (example 1)</p></td></tr></tbody></table></div></div><br class="table-break"><p>Notes:
|
|
* The <code class="literal">spring.cloud.kubernetes.secrets.labels</code> property behaves as defined by
|
|
<a class="link" href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#map-based-binding" target="_top">Map-based binding</a>.
|
|
* The <code class="literal">spring.cloud.kubernetes.secrets.paths</code> property behaves as defined by
|
|
<a class="link" href="https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding#collection-based-binding" target="_top">Collection-based binding</a>.
|
|
* Access to secrets through the API may be restricted for security reasons. The preferred way is to mount secrets to the Pod.</p><p>You can find an example of an application that uses secrets (though it has not been updated to use the new <code class="literal">spring-cloud-kubernetes</code> project) at
|
|
<a class="link" href="https://github.com/fabric8-quickstarts/spring-boot-camel-config" target="_top">spring-boot-camel-config</a></p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_propertysource_reload" href="#_propertysource_reload"></a>5.3 <code class="literal">PropertySource</code> Reload</h2></div></div></div><p>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 <code class="literal">ConfigMap</code> or
|
|
<code class="literal">Secret</code> changes.</p><p>By default, this feature is disabled. You can enable it by using the <code class="literal">spring.cloud.kubernetes.reload.enabled=true</code> configuration property (for example, in the <code class="literal">application.properties</code> file).</p><p>The following levels of reload are supported (by setting the <code class="literal">spring.cloud.kubernetes.reload.strategy</code> property):
|
|
* <code class="literal">refresh</code> (default): Only configuration beans annotated with <code class="literal">@ConfigurationProperties</code> or <code class="literal">@RefreshScope</code> are reloaded.
|
|
This reload level leverages the refresh feature of Spring Cloud Context.
|
|
* <code class="literal">restart_context</code>: the whole Spring <code class="literal">ApplicationContext</code> is gracefully restarted. Beans are recreated with the new configuration.
|
|
* <code class="literal">shutdown</code>: the Spring <code class="literal">ApplicationContext</code> 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 <code class="literal">ApplicationContext</code>
|
|
and that a replication controller or replica set is configured to restart the pod.</p><p>Assuming that the reload feature is enabled with default settings (<code class="literal">refresh</code> mode), the following bean is refreshed when the config map changes:</p><div class="informalexample"><pre class="screen">@Configuration
|
|
@ConfigurationProperties(prefix = "bean")
|
|
public class MyConfig {
|
|
|
|
private String message = "a message that can be changed live";
|
|
|
|
// getter and setters
|
|
|
|
}</pre></div><p>To see that changes effectively happen, you can create another bean that prints the message periodically, as follows</p><div class="informalexample"><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@Component</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> MyBean {
|
|
|
|
<em><span class="hl-annotation" style="color: gray">@Autowired</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">private</span> MyConfig config;
|
|
|
|
<em><span class="hl-annotation" style="color: gray">@Scheduled(fixedDelay = 5000)</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> hello() {
|
|
System.out.println(<span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"The message is: "</span> + config.getMessage());
|
|
}
|
|
}</pre></div><p>You can change the message printed by the application by using a <code class="literal">ConfigMap</code>, as follows:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">apiVersion</span>: v1
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">kind</span>: ConfigMap
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">metadata</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> name</span>: reload-example
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute">data</span>:
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> application.properties</span>: |-
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-attribute"> bean.message</span>=Hello World!</pre></div><p>Any change to the property named <code class="literal">bean.message</code> in the <code class="literal">ConfigMap</code> associated with the pod is reflected in the
|
|
output. More generally speaking, changes associated to properties prefixed with the value defined by the <code class="literal">prefix</code>
|
|
field of the <code class="literal">@ConfigurationProperties</code> annotation are detected and reflected in the application.
|
|
<a class="link" href="#configmap-propertysource" title="5.1 Using a ConfigMap PropertySource">Associating a <code class="literal">ConfigMap</code> with a pod</a> is explained earlier in this chapter.</p><p>The full example is available in <a class="link" href="https://github.com/fabric8io/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-examples/kubernetes-reload-example" target="_top"><code class="literal">spring-cloud-kubernetes-reload-example</code></a>.</p><p>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 <code class="literal">view</code> role on the service account is required in order to listen for config map changes. A higher level role (such as <code class="literal">edit</code>) 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 <code class="literal">spring.cloud.kubernetes.reload.period</code> 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.</p><div class="table"><a name="d0e869" href="#d0e869"></a><p class="title"><b>Table 5.3. Properties:</b></p><div class="table-contents"><table class="table" summary="Properties:" style="border-collapse: collapse;border-top: 1px solid ; border-bottom: 1px solid ; border-left: 1px solid ; border-right: 1px solid ; "><colgroup><col class="col_1"><col class="col_2"><col class="col_3"><col class="col_4"></colgroup><thead><tr><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Name</th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Type</th><th style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top">Default</th><th style="border-bottom: 1px solid ; " align="left" valign="top">Description</th></tr></thead><tfoot><tr><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.reload.period</code></p></th><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">Duration</code></p></th><th style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">15s</code></p></th><th style="" align="left" valign="top"><p>The period for verifying changes when using the <code class="literal">polling</code> strategy</p></th></tr></tfoot><tbody><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.reload.enabled</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">false</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Enables monitoring of property sources and configuration reload</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.reload.monitoring-config-maps</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">true</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Allow monitoring changes in config maps</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.reload.monitoring-secrets</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Boolean</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">false</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>Allow monitoring changes in secrets</p></td></tr><tr><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p>`spring.cloud.kubernetes.reload.strategy `</p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">Enum</code></p></td><td style="border-right: 1px solid ; border-bottom: 1px solid ; " align="left" valign="top"><p><code class="literal">refresh</code></p></td><td style="border-bottom: 1px solid ; " align="left" valign="top"><p>The strategy to use when firing a reload (<code class="literal">refresh</code>, <code class="literal">restart_context</code>, or <code class="literal">shutdown</code>)</p></td></tr><tr><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">spring.cloud.kubernetes.reload.mode</code></p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">Enum</code></p></td><td style="border-right: 1px solid ; " align="left" valign="top"><p><code class="literal">event</code></p></td><td style="" align="left" valign="top"><p>Specifies how to listen for changes in property sources (<code class="literal">event</code> or <code class="literal">polling</code>)</p></td></tr></tbody></table></div></div><br class="table-break"><p>Notes:
|
|
* You should not use properties under <code class="literal">spring.cloud.kubernetes.reload</code> 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 <code class="literal">refresh</code> level.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_ribbon_discovery_in_kubernetes" href="#_ribbon_discovery_in_kubernetes"></a>6. Ribbon Discovery in Kubernetes</h1></div></div></div><p>Spring Cloud client applications that call a microservice should be interested on relying on a client load-balancing
|
|
feature in order to automatically discover at which endpoint(s) it can reach a given service. This mechanism has been
|
|
implemented within the <a class="link" href="https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-ribbon" target="_top">spring-cloud-kubernetes-ribbon</a> project, where a
|
|
Kubernetes client populates a <a class="link" href="https://github.com/Netflix/ribbon" target="_top">Ribbon</a> <code class="literal">ServerList</code> that contains information
|
|
about such endpoints.</p><p>The implementation is part of the following starter that you can use by adding its dependency to your pom file:</p><div class="informalexample"><pre class="programlisting"><span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><dependency></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><groupId></span>org.springframework.cloud<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></groupId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><artifactId></span>spring-cloud-starter-kubernetes-ribbon<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></artifactId></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"><version></span>${latest.version}<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></version></span>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-tag"></dependency></span></pre></div><p>When the list of the endpoints is populated, the Kubernetes client searches the registered endpoints that live in
|
|
the current namespace or project by matching the service name defined in the Ribbon Client annotation, as follows:</p><div class="informalexample"><pre class="programlisting">@RibbonClient(name = <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"name-service"</span>)</pre></div><p>You can configure Ribbon’s behavior by providing properties in your <code class="literal">application.properties</code> (through your application’s
|
|
dedicated <code class="literal">ConfigMap</code>) by using the following format: <code class="literal"><name of your service>.ribbon.<Ribbon configuration key></code>, where:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal"><name of your service></code> corresponds to the service name you access over Ribbon, as configured by using the
|
|
<code class="literal">@RibbonClient</code> annotation (such as <code class="literal">name-service</code> in the preceding example).</li><li class="listitem"><code class="literal"><Ribbon configuration key></code> is one of the Ribbon configuration keys defined by
|
|
<a class="link" href="https://github.com/Netflix/ribbon/blob/master/ribbon-core/src/main/java/com/netflix/client/config/CommonClientConfigKey.java" target="_top">Ribbon’s <code class="literal">CommonClientConfigKey</code> class</a>.</li></ul></div><p>Additionally, the <code class="literal">spring-cloud-kubernetes-ribbon</code> project defines two additional configuration keys to further
|
|
control how Ribbon interacts with Kubernetes. In particular, if an endpoint defines multiple ports, the default
|
|
behavior is to use the first one found. To select more specifically which port to use in a multi-port service, you can use
|
|
the <code class="literal">PortName</code> key. If you want to specify in which Kubernetes namespace the target service should be looked up, you can use
|
|
the <code class="literal">KubernetesNamespace</code> key, remembering in both instances to prefix these keys with your service name and
|
|
<code class="literal">ribbon</code> prefix, as specified earlier.</p><p>The following examples use this module for ribbon discovery:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="./spring-cloud-kubernetes-examples/kubernetes-circuitbreaker-ribbon-example" target="_top">Spring Cloud Circuitbreaker and Ribbon</a></li><li class="listitem"><a class="link" href="https://github.com/fabric8-quickstarts/spring-boot-ribbon" target="_top">fabric8-quickstarts - Spring Boot - Ribbon</a></li><li class="listitem"><a class="link" href="https://github.com/fabric8io/kubeflix/tree/master/examples/loanbroker/bank" target="_top">Kubeflix - LoanBroker - Bank</a></li></ul></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>You can disable the Ribbon discovery client by setting the <code class="literal">spring.cloud.kubernetes.ribbon.enabled=false</code> key within the application properties file.</p></td></tr></table></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_kubernetes_ecosystem_awareness" href="#_kubernetes_ecosystem_awareness"></a>7. Kubernetes Ecosystem Awareness</h1></div></div></div><p>All of the features described earlier in this guide work equally well, regardless of whether your application is running inside
|
|
Kubernetes. This is really helpful for development and troubleshooting.
|
|
From a development point of view, this lets you start your Spring Boot application and debug one
|
|
of the modules that is part of this project. You need not deploy it in Kubernetes,
|
|
as the code of the project relies on the
|
|
<a class="link" href="https://github.com/fabric8io/kubernetes-client" target="_top">Fabric8 Kubernetes Java client</a>, which is a fluent DSL that can
|
|
communicate by using <code class="literal">http</code> protocol to the REST API of the Kubernetes Server.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_kubernetes_profile_autoconfiguration" href="#_kubernetes_profile_autoconfiguration"></a>7.1 Kubernetes Profile Autoconfiguration</h2></div></div></div><p>When the application runs as a pod inside Kubernetes, a Spring profile named <code class="literal">kubernetes</code> automatically gets activated.
|
|
This lets you customize the configuration, to define beans that are applied when the Spring Boot application is deployed
|
|
within the Kubernetes platform (for example, different development and production configuration).</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_istio_awareness" href="#_istio_awareness"></a>7.2 Istio Awareness</h2></div></div></div><p>When you include the <code class="literal">spring-cloud-kubernetes-istio</code> module in the application classpath, a new profile is added to the application,
|
|
provided the application is running inside a Kubernetes Cluster with <a class="link" href="https://istio.io" target="_top">Istio</a> installed. You can then use
|
|
spring <code class="literal">@Profile("istio")</code> annotations in your Beans and <code class="literal">@Configuration</code> classes.</p><p>The Istio awareness module uses <code class="literal">me.snowdrop:istio-client</code> to interact with Istio APIs, letting us discover traffic rules, circuit breakers, and so on,
|
|
making it easy for our Spring Boot applications to consume this data to dynamically configure themselves according to the environment.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_pod_health_indicator" href="#_pod_health_indicator"></a>8. Pod Health Indicator</h1></div></div></div><p>Spring Boot uses <a class="link" href="https://github.com/spring-projects/spring-boot/blob/master/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/health/HealthEndpoint.java" target="_top"><code class="literal">HealthIndicator</code></a> to expose info about the health of an application.
|
|
That makes it really useful for exposing health-related information to the user and makes it a good fit for use as <a class="link" href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/" target="_top">readiness probes</a>.</p><p>The Kubernetes health indicator (which is part of the core module) exposes the following info:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Pod name, IP address, namespace, service account, node name, and its IP address</li><li class="listitem">A flag that indicates whether the Spring Boot application is internal or external to Kubernetes</li></ul></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_leader_election" href="#_leader_election"></a>9. Leader Election</h1></div></div></div><p><TBD></p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_security_configurations_inside_kubernetes" href="#_security_configurations_inside_kubernetes"></a>10. Security Configurations Inside Kubernetes</h1></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_namespace" href="#_namespace"></a>10.1 Namespace</h2></div></div></div><p>Most of the components provided in this project need to know the namespace. For Kubernetes (1.3+), the namespace is made available to the pod as part of the service account secret and is automatically detected by the client.
|
|
For earlier versions, it needs to be specified as an environment variable to the pod. A quick way to do this is as follows:</p><div class="informalexample"><pre class="screen"> env:
|
|
- name: "KUBERNETES_NAMESPACE"
|
|
valueFrom:
|
|
fieldRef:
|
|
fieldPath: "metadata.namespace"</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_service_account" href="#_service_account"></a>10.2 Service Account</h2></div></div></div><p>For distributions of Kubernetes that support more fine-grained role-based access within the cluster, you need to make sure a pod that runs with <code class="literal">spring-cloud-kubernetes</code> has access to the Kubernetes API.
|
|
For any service accounts you assign to a deployment or pod, you need to make sure they have the correct roles. For example, you can add <code class="literal">cluster-reader</code> permissions to your <code class="literal">default</code> service account, depending on the project you’re in.</p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_service_registry_implementation" href="#_service_registry_implementation"></a>11. Service Registry Implementation</h1></div></div></div><p>In Kubernetes service registration is controlled by the platform, the application itself does not control
|
|
registration as it may do in other platforms. For this reason using <code class="literal">spring.cloud.service-registry.auto-registration.enabled</code>
|
|
or setting <code class="literal">@EnableDiscoveryClient(autoRegister=false)</code> will have no effect in Spring Cloud Kubernetes.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_examples" href="#_examples"></a>12. Examples</h1></div></div></div><p>Spring Cloud Kubernetes tries to make it transparent for your applications to consume Kubernetes Native Services by
|
|
following the Spring Cloud interfaces.</p><p>In your applications, you need to add the <code class="literal">spring-cloud-kubernetes-discovery</code> dependency to your classpath and remove any other dependency that contains a <code class="literal">DiscoveryClient</code> implementation (that is, a Eureka discovery client).
|
|
The same applies for <code class="literal">PropertySourceLocator</code>, where you need to add to the classpath the <code class="literal">spring-cloud-kubernetes-config</code> and remove any other dependency that contains a <code class="literal">PropertySourceLocator</code> implementation (that is, a configuration server client).</p><p>The following projects highlight the usage of these dependencies and demonstrate how you can use these libraries from any Spring Boot application:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="https://github.com/spring-cloud/spring-cloud-kubernetes/tree/master/spring-cloud-kubernetes-examples" target="_top">Spring Cloud Kubernetes Examples</a>: the ones located inside this repository.</li><li class="listitem"><p class="simpara">Spring Cloud Kubernetes Full Example: Minions and Boss</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><a class="link" href="https://github.com/salaboy/spring-cloud-k8s-minion" target="_top">Minion</a></li><li class="listitem"><a class="link" href="https://github.com/salaboy/spring-cloud-k8s-boss" target="_top">Boss</a></li></ul></div></li><li class="listitem">Spring Cloud Kubernetes Full Example: <a class="link" href="https://github.com/salaboy/s1p_docs" target="_top">SpringOne Platform Tickets Service</a></li><li class="listitem"><a class="link" href="https://github.com/salaboy/s1p_gateway" target="_top">Spring Cloud Gateway with Spring Cloud Kubernetes Discovery and Config</a></li><li class="listitem"><a class="link" href="https://github.com/salaboy/showcase-admin-tool" target="_top">Spring Boot Admin with Spring Cloud Kubernetes Discovery and Config</a></li></ul></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_other_resources" href="#_other_resources"></a>13. Other Resources</h1></div></div></div><p>This section lists other resources, such as presentations (slides) and videos about Spring Cloud Kubernetes.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><a class="link" href="https://salaboy.com/2018/09/27/the-s1p-experience/" target="_top">S1P Spring Cloud on PKS</a></li><li class="listitem"><a class="link" href="https://salaboy.com/2018/07/18/ljc-july-18-spring-cloud-docker-k8s/" target="_top">Spring Cloud, Docker, Kubernetes → London Java Community July 2018</a></li></ul></div><p>Please feel free to submit other resources through pull requests to <a class="link" href="https://github.com/spring-cloud/spring-cloud-kubernetes" target="_top">this repository</a>.</p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_building" href="#_building"></a>14. Building</h1></div></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_basic_compile_and_test" href="#_basic_compile_and_test"></a>14.1 Basic Compile and Test</h2></div></div></div><p>To build the source you will need to install JDK 1.7.</p><p>Spring Cloud uses Maven for most build-related activities, and you
|
|
should be able to get off the ground quite quickly by cloning the
|
|
project you are interested in and typing</p><pre class="screen">$ ./mvnw install</pre><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>You can also install Maven (>=3.3.3) yourself and run the <code class="literal">mvn</code> command
|
|
in place of <code class="literal">./mvnw</code> in the examples below. If you do that you also
|
|
might need to add <code class="literal">-P spring</code> if your local Maven settings do not
|
|
contain repository declarations for spring pre-release artifacts.</p></td></tr></table></div><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Be aware that you might need to increase the amount of memory
|
|
available to Maven by setting a <code class="literal">MAVEN_OPTS</code> environment variable with
|
|
a value like <code class="literal">-Xmx512m -XX:MaxPermSize=128m</code>. We try to cover this in
|
|
the <code class="literal">.mvn</code> configuration, so if you find you have to do it to make a
|
|
build succeed, please raise a ticket to get the settings added to
|
|
source control.</p></td></tr></table></div><p>For hints on how to build the project look in <code class="literal">.travis.yml</code> if there
|
|
is one. There should be a "script" and maybe "install" command. Also
|
|
look at the "services" section to see if any services need to be
|
|
running locally (e.g. mongo or rabbit). Ignore the git-related bits
|
|
that you might find in "before_install" since they’re related to setting git
|
|
credentials and you already have those.</p><p>The projects that require middleware generally include a
|
|
<code class="literal">docker-compose.yml</code>, so consider using
|
|
<a class="link" href="https://docs.docker.com/compose/" target="_top">Docker Compose</a> to run the middeware servers
|
|
in Docker containers. See the README in the
|
|
<a class="link" href="https://github.com/spring-cloud-samples/scripts" target="_top">scripts demo
|
|
repository</a> for specific instructions about the common cases of mongo,
|
|
rabbit and redis.</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>If all else fails, build with the command from <code class="literal">.travis.yml</code> (usually
|
|
<code class="literal">./mvnw install</code>).</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_documentation" href="#_documentation"></a>14.2 Documentation</h2></div></div></div><p>The spring-cloud-build module has a "docs" profile, and if you switch
|
|
that on it will try to build asciidoc sources from
|
|
<code class="literal">src/main/asciidoc</code>. As part of that process it will look for a
|
|
<code class="literal">README.adoc</code> and process it by loading all the includes, but not
|
|
parsing or rendering it, just copying it to <code class="literal">${main.basedir}</code>
|
|
(defaults to <code class="literal">${basedir}</code>, i.e. the root of the project). If there are
|
|
any changes in the README it will then show up after a Maven build as
|
|
a modified file in the correct place. Just commit it and push the change.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_working_with_the_code" href="#_working_with_the_code"></a>14.3 Working with the code</h2></div></div></div><p>If you don’t have an IDE preference we would recommend that you use
|
|
<a class="link" href="https://www.springsource.com/developer/sts" target="_top">Spring Tools Suite</a> or
|
|
<a class="link" href="https://eclipse.org" target="_top">Eclipse</a> when working with the code. We use the
|
|
<a class="link" href="https://eclipse.org/m2e/" target="_top">m2eclipse</a> eclipse plugin for maven support. Other IDEs and tools
|
|
should also work without issue as long as they use Maven 3.3.3 or better.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_importing_into_eclipse_with_m2eclipse" href="#_importing_into_eclipse_with_m2eclipse"></a>14.3.1 Importing into eclipse with m2eclipse</h3></div></div></div><p>We recommend the <a class="link" href="https://eclipse.org/m2e/" target="_top">m2eclipse</a> eclipse plugin when working with
|
|
eclipse. If you don’t already have m2eclipse installed it is available from the "eclipse
|
|
marketplace".</p><div class="note" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Note"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="images/note.png"></td><th align="left">Note</th></tr><tr><td align="left" valign="top"><p>Older versions of m2e do not support Maven 3.3, so once the
|
|
projects are imported into Eclipse you will also need to tell
|
|
m2eclipse to use the right profile for the projects. If you
|
|
see many different errors related to the POMs in the projects, check
|
|
that you have an up to date installation. If you can’t upgrade m2e,
|
|
add the "spring" profile to your <code class="literal">settings.xml</code>. Alternatively you can
|
|
copy the repository settings from the "spring" profile of the parent
|
|
pom into your <code class="literal">settings.xml</code>.</p></td></tr></table></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_importing_into_eclipse_without_m2eclipse" href="#_importing_into_eclipse_without_m2eclipse"></a>14.3.2 Importing into eclipse without m2eclipse</h3></div></div></div><p>If you prefer not to use m2eclipse you can generate eclipse project metadata using the
|
|
following command:</p><pre class="screen">$ ./mvnw eclipse:eclipse</pre><p>The generated eclipse projects can be imported by selecting <code class="literal">import existing projects</code>
|
|
from the <code class="literal">file</code> menu.</p></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a name="_contributing" href="#_contributing"></a>15. Contributing</h1></div></div></div><p>Spring Cloud is released under the non-restrictive Apache 2.0 license,
|
|
and follows a very standard Github development process, using Github
|
|
tracker for issues and merging pull requests into master. If you want
|
|
to contribute even something trivial please do not hesitate, but
|
|
follow the guidelines below.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_sign_the_contributor_license_agreement" href="#_sign_the_contributor_license_agreement"></a>15.1 Sign the Contributor License Agreement</h2></div></div></div><p>Before we accept a non-trivial patch or pull request we will need you to sign the
|
|
<a class="link" href="https://cla.pivotal.io/sign/spring" target="_top">Contributor License Agreement</a>.
|
|
Signing the contributor’s agreement does not grant anyone commit rights to the main
|
|
repository, but it does mean that we can accept your contributions, and you will get an
|
|
author credit if we do. Active contributors might be asked to join the core team, and
|
|
given the ability to merge pull requests.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_code_of_conduct" href="#_code_of_conduct"></a>15.2 Code of Conduct</h2></div></div></div><p>This project adheres to the Contributor Covenant <a class="link" href="https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc" target="_top">code of
|
|
conduct</a>. By participating, you are expected to uphold this code. Please report
|
|
unacceptable behavior to <a class="link" href="mailto:spring-code-of-conduct@pivotal.io" target="_top">spring-code-of-conduct@pivotal.io</a>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_code_conventions_and_housekeeping" href="#_code_conventions_and_housekeeping"></a>15.3 Code Conventions and Housekeeping</h2></div></div></div><p>None of these is essential for a pull request, but they will all help. They can also be
|
|
added after the original pull request but before a merge.</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem">Use the Spring Framework code format conventions. If you use Eclipse
|
|
you can import formatter settings using the
|
|
<code class="literal">eclipse-code-formatter.xml</code> file from the
|
|
<a class="link" href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml" target="_top">Spring
|
|
Cloud Build</a> project. If using IntelliJ, you can use the
|
|
<a class="link" href="https://plugins.jetbrains.com/plugin/6546" target="_top">Eclipse Code Formatter
|
|
Plugin</a> to import the same file.</li><li class="listitem">Make sure all new <code class="literal">.java</code> files to have a simple Javadoc class comment with at least an
|
|
<code class="literal">@author</code> tag identifying you, and preferably at least a paragraph on what the class is
|
|
for.</li><li class="listitem">Add the ASF license header comment to all new <code class="literal">.java</code> files (copy from existing files
|
|
in the project)</li><li class="listitem">Add yourself as an <code class="literal">@author</code> to the .java files that you modify substantially (more
|
|
than cosmetic changes).</li><li class="listitem">Add some Javadocs and, if you change the namespace, some XSD doc elements.</li><li class="listitem">A few unit tests would help a lot as well — someone has to do it.</li><li class="listitem">If no-one else is using your branch, please rebase it against the current master (or
|
|
other target branch in the main project).</li><li class="listitem">When writing a commit message please follow <a class="link" href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html" target="_top">these conventions</a>,
|
|
if you are fixing an existing issue please add <code class="literal">Fixes gh-XXXX</code> at the end of the commit
|
|
message (where XXXX is the issue number).</li></ul></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_checkstyle" href="#_checkstyle"></a>15.4 Checkstyle</h2></div></div></div><p>Spring Cloud Build comes with a set of checkstyle rules. You can find them in the <code class="literal">spring-cloud-build-tools</code> module. The most notable files under the module are:</p><p><b>spring-cloud-build-tools/. </b>
|
|
</p><pre class="screen">└── src
|
|
├── checkstyle
|
|
│ └── checkstyle-suppressions.xml <a name="CO1-1" href="#CO1-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
|
└── main
|
|
└── resources
|
|
├── checkstyle-header.txt <a name="CO1-2" href="#CO1-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
|
└── checkstyle.xml <a name="CO1-3" href="#CO1-3"></a><span><img src="images/callouts/3.png" alt="3" border="0"></span></pre><p>
|
|
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-3"><span><img src="images/callouts/3.png" alt="3" border="0"></span></a> </p></td><td valign="top" align="left"><p>Default Checkstyle rules</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>File header setup</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO1-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>Default suppression rules</p></td></tr></table></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_checkstyle_configuration" href="#_checkstyle_configuration"></a>15.4.1 Checkstyle configuration</h3></div></div></div><p>Checkstyle rules are <span class="strong"><strong>disabled by default</strong></span>. To add checkstyle to your project just define the following properties and plugins.</p><p><b>pom.xml. </b>
|
|
</p><pre class="screen"><properties>
|
|
<maven-checkstyle-plugin.failsOnError>true</maven-checkstyle-plugin.failsOnError> <a name="CO2-1" href="#CO2-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
|
<maven-checkstyle-plugin.failsOnViolation>true
|
|
</maven-checkstyle-plugin.failsOnViolation> <a name="CO2-2" href="#CO2-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
|
<maven-checkstyle-plugin.includeTestSourceDirectory>true
|
|
</maven-checkstyle-plugin.includeTestSourceDirectory> <a name="CO2-3" href="#CO2-3"></a><span><img src="images/callouts/3.png" alt="3" border="0"></span>
|
|
</properties>
|
|
|
|
<build>
|
|
<plugins>
|
|
<plugin> <a name="CO2-4" href="#CO2-4"></a><span><img src="images/callouts/4.png" alt="4" border="0"></span>
|
|
<groupId>io.spring.javaformat</groupId>
|
|
<artifactId>spring-javaformat-maven-plugin</artifactId>
|
|
</plugin>
|
|
<plugin> <a name="CO2-5" href="#CO2-5"></a><span><img src="images/callouts/5.png" alt="5" border="0"></span>
|
|
<groupId>org.apache.maven.plugins</groupId>
|
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
</plugin>
|
|
</plugins>
|
|
|
|
<reporting>
|
|
<plugins>
|
|
<plugin> <a name="CO2-6" href="#CO2-6"></a><span><img src="images/callouts/6.png" alt="6" border="0"></span>
|
|
<groupId>org.apache.maven.plugins</groupId>
|
|
<artifactId>maven-checkstyle-plugin</artifactId>
|
|
</plugin>
|
|
</plugins>
|
|
</reporting>
|
|
</build></pre><p>
|
|
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>Fails the build upon Checkstyle errors</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>Fails the build upon Checkstyle violations</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-3"><span><img src="images/callouts/3.png" alt="3" border="0"></span></a> </p></td><td valign="top" align="left"><p>Checkstyle analyzes also the test sources</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-4"><span><img src="images/callouts/4.png" alt="4" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add the Spring Java Format plugin that will reformat your code to pass most of the Checkstyle formatting rules</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO2-5"><span><img src="images/callouts/5.png" alt="5" border="0"></span></a> <a href="#CO2-6"><span><img src="images/callouts/6.png" alt="6" border="0"></span></a> </p></td><td valign="top" align="left"><p>Add checkstyle plugin to your build and reporting phases</p></td></tr></table></div><p>If you need to suppress some rules (e.g. line length needs to be longer), then it’s enough for you to define a file under <code class="literal">${project.root}/src/checkstyle/checkstyle-suppressions.xml</code> with your suppressions. Example:</p><p><b>projectRoot/src/checkstyle/checkstyle-suppresions.xml. </b>
|
|
</p><pre class="screen"><?xml version="1.0"?>
|
|
<!DOCTYPE suppressions PUBLIC
|
|
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
|
"https://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
|
|
<suppressions>
|
|
<suppress files=".*ConfigServerApplication\.java" checks="HideUtilityClassConstructor"/>
|
|
<suppress files=".*ConfigClientWatch\.java" checks="LineLengthCheck"/>
|
|
</suppressions></pre><p>
|
|
</p><p>It’s advisable to copy the <code class="literal">${spring-cloud-build.rootFolder}/.editorconfig</code> and <code class="literal">${spring-cloud-build.rootFolder}/.springformat</code> to your project. That way, some default formatting rules will be applied. You can do so by running this script:</p><pre class="programlisting">$ curl https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/.editorconfig -o .editorconfig
|
|
$ touch .springformat</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_ide_setup" href="#_ide_setup"></a>15.5 IDE setup</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_intellij_idea" href="#_intellij_idea"></a>15.5.1 Intellij IDEA</h3></div></div></div><p>In order to setup Intellij you should import our coding conventions, inspection profiles and set up the checkstyle plugin.</p><p><b>spring-cloud-build-tools/. </b>
|
|
</p><pre class="screen">└── src
|
|
├── checkstyle
|
|
│ └── checkstyle-suppressions.xml <a name="CO3-1" href="#CO3-1"></a><span><img src="images/callouts/1.png" alt="1" border="0"></span>
|
|
└── main
|
|
└── resources
|
|
├── checkstyle-header.txt <a name="CO3-2" href="#CO3-2"></a><span><img src="images/callouts/2.png" alt="2" border="0"></span>
|
|
├── checkstyle.xml <a name="CO3-3" href="#CO3-3"></a><span><img src="images/callouts/3.png" alt="3" border="0"></span>
|
|
└── intellij
|
|
├── Intellij_Project_Defaults.xml <a name="CO3-4" href="#CO3-4"></a><span><img src="images/callouts/4.png" alt="4" border="0"></span>
|
|
└── Intellij_Spring_Boot_Java_Conventions.xml <a name="CO3-5" href="#CO3-5"></a><span><img src="images/callouts/5.png" alt="5" border="0"></span></pre><p>
|
|
</p><div class="calloutlist"><table border="0" summary="Callout list"><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-3"><span><img src="images/callouts/3.png" alt="3" border="0"></span></a> </p></td><td valign="top" align="left"><p>Default Checkstyle rules</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-2"><span><img src="images/callouts/2.png" alt="2" border="0"></span></a> </p></td><td valign="top" align="left"><p>File header setup</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-1"><span><img src="images/callouts/1.png" alt="1" border="0"></span></a> </p></td><td valign="top" align="left"><p>Default suppression rules</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-4"><span><img src="images/callouts/4.png" alt="4" border="0"></span></a> </p></td><td valign="top" align="left"><p>Project defaults for Intellij that apply most of Checkstyle rules</p></td></tr><tr><td width="5%" valign="top" align="left"><p><a href="#CO3-5"><span><img src="images/callouts/5.png" alt="5" border="0"></span></a> </p></td><td valign="top" align="left"><p>Project style conventions for Intellij that apply most of Checkstyle rules</p></td></tr></table></div><div class="figure"><a name="d0e1624" href="#d0e1624"></a><p class="title"><b>Figure 15.1. Code style</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-code-style.png" alt="Code style"></div></div></div><br class="figure-break"><p>Go to <code class="literal">File</code> → <code class="literal">Settings</code> → <code class="literal">Editor</code> → <code class="literal">Code style</code>. There click on the icon next to the <code class="literal">Scheme</code> section. There, click on the <code class="literal">Import Scheme</code> value and pick the <code class="literal">Intellij IDEA code style XML</code> option. Import the <code class="literal">spring-cloud-build-tools/src/main/resources/intellij/Intellij_Spring_Boot_Java_Conventions.xml</code> file.</p><div class="figure"><a name="d0e1659" href="#d0e1659"></a><p class="title"><b>Figure 15.2. Inspection profiles</b></p><div class="figure-contents"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-inspections.png" alt="Code style"></div></div></div><br class="figure-break"><p>Go to <code class="literal">File</code> → <code class="literal">Settings</code> → <code class="literal">Editor</code> → <code class="literal">Inspections</code>. There click on the icon next to the <code class="literal">Profile</code> section. There, click on the <code class="literal">Import Profile</code> and import the <code class="literal">spring-cloud-build-tools/src/main/resources/intellij/Intellij_Project_Defaults.xml</code> file.</p><p><b>Checkstyle. </b>To have Intellij work with Checkstyle, you have to install the <code class="literal">Checkstyle</code> plugin. It’s advisable to also install the <code class="literal">Assertions2Assertj</code> to automatically convert the JUnit assertions</p><div class="informalfigure"><div class="mediaobject"><img src="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/images/intellij-checkstyle.png" alt="Checkstyle"></div></div><p>Go to <code class="literal">File</code> → <code class="literal">Settings</code> → <code class="literal">Other settings</code> → <code class="literal">Checkstyle</code>. There click on the <code class="literal">+</code> icon in the <code class="literal">Configuration file</code> section. There, you’ll have to define where the checkstyle rules should be picked from. In the image above, we’ve picked the rules from the cloned Spring Cloud Build repository. However, you can point to the Spring Cloud Build’s GitHub repository (e.g. for the <code class="literal">checkstyle.xml</code> : <code class="literal"><a class="link" href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml" target="_top">https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle.xml</a></code>). We need to provide the following variables:</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><code class="literal">checkstyle.header.file</code> - please point it to the Spring Cloud Build’s, <code class="literal">spring-cloud-build-tools/src/main/resources/checkstyle/checkstyle-header.txt</code> file either in your cloned repo or via the <code class="literal"><a class="link" href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt" target="_top">https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/main/resources/checkstyle-header.txt</a></code> URL.</li><li class="listitem"><code class="literal">checkstyle.suppressions.file</code> - default suppressions. Please point it to the Spring Cloud Build’s, <code class="literal">spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml</code> file either in your cloned repo or via the <code class="literal"><a class="link" href="https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml" target="_top">https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml</a></code> URL.</li><li class="listitem"><code class="literal">checkstyle.additional.suppressions.file</code> - this variable corresponds to suppressions in your local project. E.g. you’re working on <code class="literal">spring-cloud-contract</code>. Then point to the <code class="literal">project-root/src/checkstyle/checkstyle-suppressions.xml</code> folder. Example for <code class="literal">spring-cloud-contract</code> would be: <code class="literal">/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml</code>.</li></ul></div><div class="important" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Important"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Important]" src="images/important.png"></td><th align="left">Important</th></tr><tr><td align="left" valign="top"><p>Remember to set the <code class="literal">Scan Scope</code> to <code class="literal">All sources</code> since we apply checkstyle rules for production and test sources.</p></td></tr></table></div></div></div></div></div></body></html> |