Using a ConfigMap
PropertySource
Kubernetes 提供的名为 ConfigMap
的资源可以将以键值对或嵌入式 application.properties
或 application.yaml
文件形式传递给应用程序的参数对外化。 Spring Cloud Kubernetes Config 项目使 Kubernetes ConfigMap
实例在应用程序启动时可用,并在观察到的 ConfigMap
实例发生更改时触发 Bean 或 Spring 上下文的热重新加载。
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.
以下所有内容主要参考使用 ConfigMap 的示例来解释,但秘密的情况也是一样的,即:每个功能都同时支持两者。
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.
默认行为是基于 Kubernetes ConfigMap
创建一个 Fabric8ConfigMapPropertySource
(或 KubernetesClientConfigMapPropertySource
),其中 metadata.name
为:
The default behavior is to create a Fabric8ConfigMapPropertySource
(or a KubernetesClientConfigMapPropertySource
) based on a Kubernetes ConfigMap
that has metadata.name
of either:
-
value of
spring.cloud.kubernetes.config.name
-
value of your Spring application (as defined by
spring.application.name
property) -
the String literal
"application"
然而,可以使用多个 ConfigMap
实例进行更高级的配置。spring.cloud.kubernetes.config.sources
列表使这成为可能。例如,你可以定义以下 ConfigMap
实例:
However, more advanced configuration is possible where you can use multiple ConfigMap
instances.
The spring.cloud.kubernetes.config.sources
list makes this possible.
For example, you could define the following ConfigMap
instances:
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
name: default-name
namespace: default-namespace
sources:
# Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
- name: c1
# Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
- namespace: n2
# Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
- namespace: n3
name: c3
在前面的示例中,如果未设置 spring.cloud.kubernetes.config.namespace
,将在应用程序运行的命名空间中查找名为 c1
的 ConfigMap
。请参阅 Namespace resolution 更好地了解如何解析应用程序的命名空间。
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.
找到的任何匹配的 ConfigMap
都将按如下方式处理:
Any matching ConfigMap
that is found is processed as follows:
-
Apply individual configuration properties.
-
Apply as
yaml
(orproperties
) the content of any property that is named by the value ofspring.application.name
(if it’s not present, byapplication.yaml/properties
) -
Apply as a properties file the content of the above name + each active profile.
一个示例应该会更有意义。让我们假设 spring.application.name=my-app
,并且我们有一个名为 k8s
的活动配置文件。对于如下配置:
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:
kind: ConfigMap
apiVersion: v1
metadata:
name: my-app
data:
my-app.yaml: |-
...
my-app-k8s.yaml: |-
..
my-app-dev.yaml: |-
..
not-my-app.yaml: |-
..
someProp: someValue
这是我们最终加载的内容:
This is what we will end-up loading:
-
my-app.yaml
treated as a file -
my-app-k8s.yaml
treated as a file -
my-app-dev.yaml
ignored, sincedev
is not an active profile -
not-my-app.yaml
ignored, since it does not matchspring.application.name
-
someProp: someValue
plain property
加载属性的顺序如下:
The order of loading properties is a as follows:
-
first load all properties from
my-app.yaml
-
then all from profile-based sources:
my-app-k8s.yaml
-
then all plain properties
someProp: someValue
这意味着基于配置文件的资源优先于非基于配置文件的资源(就像在纯粹的 Spring 应用程序中一样);且普通属性优先于基于配置文件的资源和非基于配置文件的资源。以下是一个示例:
This means that profile based sources take precedence over non-profile based sources (just like in a vanilla Spring app); and plain properties take precedence over both profile and non-profile based sources. Here is an example:
kind: ConfigMap
apiVersion: v1
metadata:
name: my-app
data:
my-app-k8s.yaml: |-
key1=valueA
key2=valueB
my-app.yaml: |-
key1=valueC
key2=valueA
key1: valueD
处理这样的 ConfigMap 之后,您将在属性中获得以下内容:key1=valueD
、key2=valueB
。
After processing such a ConfigMap, this is what you will get in the properties: key1=valueD
, key2=valueB
.
上述流程的唯一例外是当 ConfigMap
包含表示文件是 YAML 或属性文件的*单个*键时。在这种情况下,键的名称不必是 application.yaml
或 application.properties
(可以是任何名称),并且正确处理属性的值。此功能促进了使用以下内容创建 ConfigMap
的用例:
The single exception to the aforementioned flow is when the ConfigMap
contains a single key that indicates
the file is a YAML or properties file. In that case, the name of the key does NOT have to be application.yaml
or
application.properties
(it can be anything) and the value of the property is treated correctly.
This features facilitates the use case where the ConfigMap
was created by using something like the following:
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
假设我们有一个名为 demo
的 Spring Boot 应用程序,该应用程序使用以下属性来读取其线程池配置。
Assume that we have a Spring Boot application named demo
that uses the following properties to read its thread pool
configuration.
-
pool.size.core
-
pool.size.maximum
可以将其外置到 yaml
格式的配置文件映射中,如下所示:
This can be externalized to config map in yaml
format as follows:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
pool.size.core: 1
pool.size.max: 16
对于大多数情况,单独的属性都能正常运行。但是,有时,嵌入式 yaml
更方便。在这种情况下,我们使用名为 application.yaml
的单个属性来嵌入我们的 yaml
,如下所示:
Individual properties work fine for most cases. However, sometimes, embedded yaml
is more convenient. In this case, we
use a single property named application.yaml
to embed our yaml
, as follows:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yaml: |-
pool:
size:
core: 1
max:16
以下示例也适用:
The following example also works:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
custom-name.yaml: |-
pool:
size:
core: 1
max:16
您还可以定义基于标签进行搜索,例如:
You can also define the search to happen based on labels, for example:
spring:
application:
name: labeled-configmap-with-prefix
cloud:
kubernetes:
config:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
letter: a
这将在具有标签 {letter : a}
的名称空间 spring-k8s
中搜索每个配置文件映射。此处需要注意的重要事项是,与按名称读取配置文件映射不同,这可能导致读取多个配置文件映射。与往常一样,秘密也支持相同的功能。
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.
您还可以根据在读取 ConfigMap
时合并在一起的活动简档来配置 Spring Boot 应用程序。您可以为不同的简档提供不同的属性值,方法是使用指定特定于简档的值的 application.properties
或 application.yaml
属性,每个属性位于其自己的文档中(由 ---
序列表示),如下所示:
You can also configure Spring Boot applications differently depending on active profiles that are merged together
when the ConfigMap
is read. You can provide different property values for different profiles by using an
application.properties
or application.yaml
property, specifying profile-specific values, each in their own document
(indicated by the ---
sequence), as follows:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yml: |-
greeting:
message: Say Hello to the World
farewell:
message: Say Goodbye
---
spring:
profiles: development
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
---
spring:
profiles: production
greeting:
message: Say Hello to the Ops
在上述情况下,加载到具有 development
简档的 Spring 应用程序中的配置如下:
In the preceding case, the configuration loaded into your Spring Application with the development
profile is as follows:
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
但是,如果 production
简档处于活动状态,则配置将变为:
However, if the production
profile is active, the configuration becomes:
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
如果两个简档都处于活动状态,则 ConfigMap
中最后出现的属性将覆盖任何前置值。
If both profiles are active, the property that appears last within the ConfigMap
overwrites any preceding values.
另一种选择是针对每个简档创建一个不同的配置文件映射,Spring Boot 将基于活动简档自动获取该映射。
Another option is to create a different config map per profile and spring boot will automatically fetch it based on active profiles
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yml: |-
greeting:
message: Say Hello to the World
farewell:
message: Say Goodbye
kind: ConfigMap
apiVersion: v1
metadata:
name: demo-development
data:
application.yml: |-
spring:
profiles: development
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
kind: ConfigMap
apiVersion: v1
metadata:
name: demo-production
data:
application.yml: |-
spring:
profiles: production
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
要告诉 Spring Boot 应该启用哪个 profile
,请参见 Spring Boot documentation。在部署至 Kubernetes 时激活特定的配置文件的一个选项是使用您可以在容器规范中的 PodSpec 中定义的环境变量来启动您的 Spring Boot 应用程序。部署资源文件,如下所示:
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:
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-name
labels:
app: deployment-name
spec:
replicas: 1
selector:
matchLabels:
app: deployment-name
template:
metadata:
labels:
app: deployment-name
spec:
containers:
- name: container-name
image: your-image
env:
- name: SPRING_PROFILES_ACTIVE
value: "development"
您可能会遇到具有相同属性名称的多个配置文件映射的情况。例如:
You could run into a situation where there are multiple configs maps that have the same property names. For example:
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-one
data:
application.yml: |-
greeting:
message: Say Hello from one
和
and
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-two
data:
application.yml: |-
greeting:
message: Say Hello from two
根据您在 bootstrap.yaml|properties
中放置这些映射的顺序,您可能会得到一个意外的结果(最后一个配置文件映射获胜)。例如:
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:
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
namespace: default-namespace
sources:
- name: config-map-two
- name: config-map-one
将导致属性 greetings.message
为 Say Hello from one
。
will result in property greetings.message
being Say Hello from one
.
有一种方法可以通过指定 useNameAsPrefix
来更改此默认配置。例如:
There is a way to change this default configuration by specifying useNameAsPrefix
. For example:
spring:
application:
name: with-prefix
cloud:
kubernetes:
config:
useNameAsPrefix: true
namespace: default-namespace
sources:
- name: config-map-one
useNameAsPrefix: false
- name: config-map-two
此类配置将生成两个属性:
Such a configuration will result in two properties being generated:
-
greetings.message
equal toSay Hello from one
. -
config-map-two.greetings.message
equal toSay Hello from two
请注意,spring.cloud.kubernetes.config.useNameAsPrefix
的优先级_低于_ spring.cloud.kubernetes.config.sources.useNameAsPrefix
。这允许您为所有源设置“默认”策略,同时允许仅覆盖少数源。
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.
如果不使用 ConfigMap 名称作为选项,您可以指定称为 : explicitPrefix
的不同策略。因为这是一个您选择的_显式_前缀,所以只能将其提供给 sources
级别。同时其优先级高于 useNameAsPrefix
。让我们假设我们有包含以下条目的第三个 ConfigMap:
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: ConfigMap
apiVersion: v1
metadata:
name: config-map-three
data:
application.yml: |-
greeting:
message: Say Hello from three
如下配置:
A configuration like the one below:
spring:
application:
name: with-prefix
cloud:
kubernetes:
config:
useNameAsPrefix: true
namespace: default-namespace
sources:
- name: config-map-one
useNameAsPrefix: false
- name: config-map-two
explicitPrefix: two
- name: config-map-three
将生成三个属性:
will result in three properties being generated:
-
greetings.message
equal toSay Hello from one
. -
two.greetings.message
equal toSay Hello from two
. -
config-map-three.greetings.message
equal toSay Hello from three
.
您可以针对 ConfigMap 配置前缀的方式与针对 Secret 的相同,针对基于名称和基于标签的 Secret 均可。例如:
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
在生成属性源时应用相同的处理规则,如同 ConfigMap 所用。唯一的区别是,通过标签查找 Secret 可能意味着会找到多个源。在这种情况下,前缀(如果通过 useNameAsPrefix
指定)将是要查找的特定标签的所有 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.
还要记住的一点是,我们支持的是每个_源_的 prefix
,而不是每个 Secret 的 prefix
。最简单的解释方法是通过示例:
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:
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
color: blue
useNameAsPrefix: true
假设匹配此类标签的查询将提供两个 Secret 作为结果:secret-a
和 secret-b
。这两个 Secret 具有相同的属性名称:color=sea-blue
和 color=ocean-blue
。未定义哪个`color` 将最终成为属性源的一部分,但前缀将是 secret-a.secret-b
(按 Secret 名称自然排序后连接)。
Suppose that a query matching such a label will provide two secrets as a result: secret-a
and secret-b
.
Both of these secrets have the same property name: color=sea-blue
and color=ocean-blue
. It is undefined which
color
will end-up as part of property sources, but the prefix for it will be secret-a.secret-b
(concatenated sorted naturally, names of the secrets).
如果您需要更精细的结果,添加更多标签以唯一识别 Secret 将是一种选择。
If you need more fine-grained results, adding more labels to identify the secret uniquely would be an option.
默认情况下,除了读取在 sources
配置中指定的 ConfigMap 之外,Spring 还将尝试从“受配置文件感知”的源读取所有属性。最简单的解释方法是通过示例。假设您的应用程序启用了名为“dev”的配置文件,并且您有如下配置:
By default, besides reading the config map that is specified in the sources
configuration, Spring will also try to read
all properties from "profile aware" sources. The easiest way to explain this is via an example. Let’s suppose your application
enables a profile called "dev" and you have a configuration like the one below:
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
namespace: default-namespace
sources:
- name: config-map-one
除了读取 config-map-one
之外,Spring 还将尝试读取 config-map-one-dev
;按照此特定顺序读取。每个活动配置文件都会生成此类配置文件感知 ConfigMap。
Besides reading the config-map-one
, Spring will also try to read config-map-one-dev
; in this particular order. Each active profile
generates such a profile aware config map.
尽管您的应用程序不应该受此类 ConfigMap 的影响,但可以在需要时禁用它:
Though your application should not be impacted by such a config map, it can be disabled if needed:
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
includeProfileSpecificSources: false
namespace: default-namespace
sources:
- name: config-map-one
includeProfileSpecificSources: false
请注意,与之前一样,您可以指定此属性的两个级别:所有 ConfigMap 或单个 ConfigMap;后者具有更高的优先级。
Notice that just like before, there are two levels where you can specify this property: for all config maps or for individual ones; the latter having a higher priority.
你应该检查一下安全配置部分。要从 pod 内访问 ConfigMap,你需要具有正确的 Kubernetes 服务账户、角色和角色绑定。 |
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. |
使用 ConfigMap
实例的另一种选择是通过运行 Spring Cloud Kubernetes 应用程序并将 Spring Cloud Kubernetes 从文件系统读取它们来将它们装载到 Pod 中。
Another option for using ConfigMap
instances is to mount them into the Pod by running the Spring Cloud Kubernetes application
and having Spring Cloud Kubernetes read them from the file system.
此功能已弃用,并将在未来版本中移除(请改用`spring.config.import`)。此行为受`spring.cloud.kubernetes.config.paths`属性的控制。你可以在此外机制之外或改用该机制使用它。`spring.cloud.kubernetes.config.paths`需要每个属性文件的完整路径列表,因为不递归解析目录。例如: |
This feature is deprecated and will be removed in a future release (Use |
spring:
cloud:
kubernetes:
config:
paths:
- /tmp/application.properties
- /var/application.yaml
如果你使用`spring.cloud.kubernetes.config.paths`或`spring.cloud.kubernetes.secrets.path`,则自动重新加载功能将不工作。你将需要向`/actuator/refresh`端点发送一个`POST`请求或重新启动/重新部署应用程序。 |
If you use |
在某些情况下,您的应用程序可能无法使用 Kubernetes API 加载一些 ConfigMap
。如果您希望应用程序在这种情况发生时终止启动过程,您可以设置`spring.cloud.kubernetes.config.fail-fast=true` 以使应用程序启动因异常而失败。
In some cases, your application may be unable to load some of your ConfigMaps
using the Kubernetes API.
If you want your application to fail the start-up process in such cases, you can set
spring.cloud.kubernetes.config.fail-fast=true
to make the application start-up fail with an Exception.
您还可以让您的应用程序在失败时重试加载 ConfigMap
属性源。首先,您需要设置 spring.cloud.kubernetes.config.fail-fast=true
。然后,您需要将 spring-retry`和 `spring-boot-starter-aop
添加到类路径。您可以配置重试属性,如最大尝试次数,初始间隔、乘数、最大间隔等回退选项,方法是设置`spring.cloud.kubernetes.config.retry.*` 属性。
You can also make your application retry loading ConfigMap
property sources on a failure. First, you need to
set spring.cloud.kubernetes.config.fail-fast=true
. Then you need to add spring-retry
and spring-boot-starter-aop
to your classpath. You can configure retry properties such as
the maximum number of attempts, backoff options like initial interval, multiplier, max interval by setting the
spring.cloud.kubernetes.config.retry.*
properties.
如果你出于某种原因在类路径中已经有了`spring-retry`和`spring-boot-starter-aop`,并想要启用快速失败,但不想启用重试;你可以通过设置`spring.cloud.kubernetes.config.retry.enabled=false`禁用`ConfigMap``PropertySources`的重试。 |
If you already have |
Name | Type | Default | Description |
---|---|---|---|
|
|
|
Enable ConfigMaps |
|
|
|
Sets the name of |
|
|
Client namespace |
Sets the Kubernetes namespace where to lookup |
|
|
|
Sets the paths where |
|
|
|
Enable or disable consuming |
|
|
|
Enable or disable failing the application start-up when an error occurred while loading a |
|
|
|
Enable or disable config retry. |
|
|
|
Initial retry interval in milliseconds. |
|
|
|
Maximum number of attempts. |
|
|
|
Maximum interval for backoff. |
|
|
|
Multiplier for next interval. |