This reference guide covers how to use Spring Cloud Kubernetes.
1. Why do you need Spring Cloud Kubernetes?
Spring Cloud Kubernetes provides implementations of well known Spring Cloud interfaces allowing developers to build and run Spring Cloud applications on Kubernetes. While this project may be useful to you when building a cloud native application, it is also not a requirement in order to deploy a Spring Boot app on Kubernetes. If you are just getting started in your journey to running your Spring Boot app on Kubernetes you can accomplish a lot with nothing more than a basic Spring Boot app and Kubernetes itself. To learn more, you can get started by reading the Spring Boot reference documentation for deploying to Kubernetes and also working through the workshop material Spring and Kubernetes.
2. Starters
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. Starters that begin with spring-cloud-starter-kubernetes-fabric8
provide implementations using the Fabric8 Kubernetes Java Client.
Starters that begin with
spring-cloud-starter-kubernetes-client provide implementations using the Kubernetes Java Client.
This project provides an implementation of Discovery Client
for Kubernetes.
This client lets you query Kubernetes endpoints (see services) by name.
A service is typically exposed by the Kubernetes API server as a collection of endpoints that represent http and https addresses and that a client can
access from a Spring Boot application running as a pod.
This is something that you get for free by adding the following dependency inside your project:
To enable loading of the DiscoveryClient, add @EnableDiscoveryClient to the according configuration or application class, as the following example shows:
To discover service endpoint addresses that are not marked as "ready" by the kubernetes api server, you can set the following property in application.properties (default: false):
This might be useful when discovering services for monitoring purposes, and would enable inspecting the /health endpoint of not-ready service instances.
If your service exposes multiple ports, you will need to specify which port the DiscoveryClient should use.
The DiscoveryClient will choose the port using the following logic.
If the service has a label primary-port-name it will use the port with the name specified in the label’s value.
If no label is present, then the port name specified in spring.cloud.kubernetes.discovery.primary-port-name will be used.
If neither of the above are specified it will use the port named https.
If none of the above conditions are met it will use the port named http.
As a last resort it wil pick the first port in the list of ports.
Warning
The last option may result in non-deterministic behaviour.
Please make sure to configure your service and/or application accordingly.
By default all of the ports and their names will be added to the metadata of the ServiceInstance.
If, for any reason, you need to disable the DiscoveryClient, you can set the following property in application.properties:
spring.cloud.kubernetes.discovery.enabled=false
Some Spring Cloud components use the DiscoveryClient in order to obtain information about the local service instance. For
this to work, you need to align the Kubernetes service name with the spring.application.name property.
Note
spring.application.name has no effect as far as the name registered for the application within Kubernetes
Spring Cloud Kubernetes can also watch the Kubernetes service catalog for changes and update the
DiscoveryClient implementation accordingly. In order to enable this functionality you need to add
@EnableScheduling on a configuration class in your application.
4. Kubernetes native service discovery
Kubernetes itself is capable of (server side) service discovery (see: kubernetes.io/docs/concepts/services-networking/service/#discovering-services).
Using native kubernetes service discovery ensures compatibility with additional tooling, such as Istio (istio.io), a service mesh that is capable of load balancing, circuit breaker, failover, and much more.
The caller service then need only refer to names resolvable in a particular Kubernetes cluster. A simple implementation might use a spring RestTemplate that refers to a fully qualified domain name (FQDN), such as {service-name}.{namespace}.svc.{cluster}.local:{service-port}.
Additionally, you can use Hystrix for:
Circuit breaker implementation on the caller side, by annotating the spring boot application class with @EnableCircuitBreaker
Fallback functionality, by annotating the respective method with @HystrixCommand(fallbackMethod=
5. Kubernetes PropertySource implementations
The most common approach to configuring your Spring Boot application is to create an application.properties or application.yaml or
an application-profile.properties or application-profile.yaml file that contains key-value pairs that provide customization values to your
application or Spring Boot starters. You can override these properties by specifying system properties or environment
variables.
To enable this functionality you need to set spring.config.import=kubernetes: in your application’s configuration properties.
Currently you can not specify a ConfigMap or Secret to load using spring.config.import, by default Spring Cloud Kubernetes
will load a ConfigMap and/or Secret based on the spring.application.name property. If spring.application.name is not set it will
load a ConfigMap and/or Secret with the name application.
If you would like to load Kubernetes PropertySource`s during the bootstrap phase like it worked prior to the 3.0.x release
you can either add `spring-cloud-starter-bootstrap to your application’s classpath or set spring.cloud.bootstrap.enabled=true
as an environment variable.
5.1. Using a ConfigMapPropertySource
Kubernetes provides a resource named ConfigMap to externalize the
parameters to pass to your application in the form of key-value pairs or embedded application.properties or application.yaml files.
The Spring Cloud Kubernetes Config project makes Kubernetes ConfigMap instances available
during application startup and triggers hot reloading of beans or Spring context when changes are detected on
observed ConfigMap instances.
Everything that follows is explained mainly referring to examples using ConfigMaps, but the same stands for
Secrets, i.e.: every feature is supported for both.
The default behavior is to create a Fabric8ConfigMapPropertySource (or a KubernetesClientConfigMapPropertySource) based on a Kubernetes ConfigMap that has a metadata.name value of either the name of
your Spring application (as defined by its spring.application.name property) or a custom name defined within the
application.properties file under the following key: spring.cloud.kubernetes.config.name.
However, more advanced configuration is possible where you can use multiple ConfigMap instances.
The spring.cloud.kubernetes.config.sources list makes this possible.
For example, you could define the following ConfigMap instances:
spring:
application:
name: cloud-k8s-appcloud:
kubernetes:
config:
name: default-namenamespace: default-namespacesources:
# Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
- name: c1# Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
- namespace: n2# Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
- namespace: n3name: c3
In the preceding example, if spring.cloud.kubernetes.config.namespace had not been set,
the ConfigMap named c1 would be looked up in the namespace that the application runs.
See Namespace resolution to get a better understanding of how the namespace
of the application is resolved.
Any matching ConfigMap that is found is processed as follows:
Apply individual configuration properties.
Apply as yaml (or properties) the content of any property that is named by the value of spring.application.name
(if it’s not present, by application.yaml/properties)
Apply as a properties file the content of the above name + each active profile.
An example should make a lot more sense. Let’s suppose that spring.application.name=my-app and that
we have a single active profile called k8s. For a configuration as below:
my-app-dev.yamlignored, since dev is not an active profile
someProp: someValue plain property
The single exception to the aforementioned flow is when the ConfigMap contains a single key that indicates
the file is a YAML or properties file. In that case, the name of the key does NOT have to be application.yaml or
application.properties (it can be anything) and the value of the property is treated correctly.
This features facilitates the use case where the ConfigMap was created by using something like the following:
Individual properties work fine for most cases. However, sometimes, embedded yaml is more convenient. In this case, we
use a single property named application.yaml to embed our yaml, as follows:
This will search for every configmap in namespace spring-k8s that has labels {letter : a}. The important
thing to notice here is that unlike reading a configmap by name, this can result in multiple config maps read.
As usual, the same feature is supported for secrets.
You can also configure Spring Boot applications differently depending on active profiles that are merged together
when the ConfigMap is read. You can provide different property values for different profiles by using an
application.properties or application.yaml property, specifying profile-specific values, each in their own document
(indicated by the --- sequence), as follows:
kind: ConfigMapapiVersion: v1metadata:
name: demodata:
application.yml: |- greeting: message: Say Hello to the World farewell: message: Say Goodbye --- spring: profiles: development greeting: message: Say Hello to the Developers farewell: message: Say Goodbye to the Developers --- spring: profiles: production greeting: message: Say Hello to the Ops
In the preceding case, the configuration loaded into your Spring Application with the development profile is as follows:
greeting:
message: Say Hello to the Developersfarewell:
message: Say Goodbye to the Developers
However, if the production profile is active, the configuration becomes:
greeting:
message: Say Hello to the Opsfarewell:
message: Say Goodbye
If both profiles are active, the property that appears last within the ConfigMap overwrites any preceding values.
Another option is to create a different config map per profile and spring boot will automatically fetch it based
on active profiles
kind: ConfigMapapiVersion: v1metadata:
name: demodata:
application.yml: |- greeting: message: Say Hello to the World farewell: message: Say Goodbye
kind: ConfigMapapiVersion: v1metadata:
name: demo-developmentdata:
application.yml: |- spring: profiles: development greeting: message: Say Hello to the Developers farewell: message: Say Goodbye to the Developers
kind: ConfigMapapiVersion: v1metadata:
name: demo-productiondata:
application.yml: |- spring: profiles: production greeting: message: Say Hello to the Ops farewell: message: Say Goodbye
To tell Spring Boot which profile should be enabled see the Spring Boot documentation.
One option for activating a specific profile when deploying to Kubernetes is to launch your Spring Boot application with an environment variable that you can define in the PodSpec at the container specification.
Deployment resource file, as follows:
You could run into a situation where there are multiple configs maps that have the same property names. For example:
kind: ConfigMapapiVersion: v1metadata:
name: config-map-onedata:
application.yml: |- greeting: message: Say Hello from one
and
kind: ConfigMapapiVersion: v1metadata:
name: config-map-twodata:
application.yml: |- greeting: message: Say Hello from two
Depending on the order in which you place these in bootstrap.yaml|properties, you might end up with an un-expected result (the last config map wins). For example:
Such a configuration will result in two properties being generated:
greetings.message equal to Say Hello from one.
config-map-two.greetings.message equal to Say Hello from two
Notice that spring.cloud.kubernetes.config.useNameAsPrefix has a lower priority than spring.cloud.kubernetes.config.sources.useNameAsPrefix.
This allows you to set a "default" strategy for all sources, at the same time allowing to override only a few.
If using the config map name is not an option, you can specify a different strategy, called : explicitPrefix. Since this is an explicit prefix that
you select, it can only be supplied to the sources level. At the same time it has a higher priority than useNameAsPrefix. Let’s suppose we have a third config map with these entries:
kind: ConfigMapapiVersion: v1metadata:
name: config-map-threedata:
application.yml: |- greeting: message: Say Hello from three
two.greetings.message equal to Say Hello from two.
config-map-three.greetings.message equal to Say Hello from three.
The same way you configure a prefix for configmaps, you can do it for secrets also; both for secrets that are based on name
and the ones based on labels. For example:
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
letter: a
useNameAsPrefix: false
- labels:
letter: b
explicitPrefix: two
- labels:
letter: c
- labels:
letter: d
useNameAsPrefix: true
- name: my-secret
The same processing rules apply when generating property source as for config maps. The only difference is that
potentially, looking up secrets by labels can mean that we find more than one source. In such a case, prefix (if specified via useNameAsPrefix)
will be the names of all secrets found for those particular labels.
One more thing to bear in mind is that we support prefix per source, not per secret. The easiest way to explain this is via an example:
请发表评论