使用 ConfigMap PropertySource
Kubernetes 提供了一个名为 ConfigMap 的资源,用于以键值对或嵌入式 application.properties 或 application.yaml 文件的形式外部化要传递给应用程序的参数。 Spring Cloud Kubernetes Config 项目在应用程序启动期间使 Kubernetes ConfigMap 实例可用,并在检测到观察到的 ConfigMap 实例发生更改时触发 bean 或 Spring 上下文的热重载。
以下所有内容主要通过 ConfigMap 的示例进行解释,但 Secret 也是如此,即:所有功能都支持两者。
默认行为是根据 Kubernetes ConfigMap 创建一个 Fabric8ConfigMapPropertySource(或 KubernetesClientConfigMapPropertySource),该 ConfigMap 的 metadata.name 为以下之一
-
spring.cloud.kubernetes.config.name的值 -
你的 Spring 应用程序的值(由
spring.application.name属性定义) -
字符串字面量
"application"
但是,可以进行更高级的配置,其中可以使用多个 ConfigMap 实例。 spring.cloud.kubernetes.config.sources 列表使得这成为可能。例如,你可以定义以下 ConfigMap 实例
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。请参阅 命名空间解析 以更好地理解应用程序的命名空间是如何解析的。
找到的任何匹配的 ConfigMap 都将按以下方式处理
-
应用单个配置属性。
-
将名为
spring.application.name的任何属性内容(如果不存在,则为application.yaml/properties)应用为yaml(或properties) -
将上述名称 + 每个活动配置文件的内容应用为属性文件。
一个示例应该能更好地说明问题。假设 spring.application.name=my-app,并且我们有一个名为 k8s 的活动配置文件。对于如下配置
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
这就是我们最终将加载的内容
-
my-app.yaml被视为文件 -
my-app-k8s.yaml被视为文件 -
my-app-dev.yaml被忽略,因为dev不是活动配置文件 -
not-my-app.yaml被忽略,因为它与spring.application.name不匹配 -
someProp: someValue纯属性
属性的加载顺序如下
-
首先从
my-app.yaml加载所有属性 -
然后从基于配置文件的源加载所有属性:
my-app-k8s.yaml -
然后加载所有纯属性
someProp: someValue
这意味着基于配置文件的源优先于非基于配置文件的源(就像在普通的 Spring 应用程序中一样);并且纯属性优先于基于配置文件和非基于配置文件的源。以下是一个示例
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。
上述流程的唯一例外是当 ConfigMap 包含一个单个键表示该文件是 YAML 或属性文件时。在这种情况下,键的名称不必是 application.yaml 或 application.properties(它可以是任何名称),并且属性的值会被正确处理。此功能方便了以下用例:ConfigMap 是通过使用如下方式创建的
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
假设我们有一个名为 demo 的 Spring Boot 应用程序,它使用以下属性来读取其线程池配置。
-
pool.size.core -
pool.size.maximum
这可以按以下方式外部化为 yaml 格式的配置映射
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
pool.size.core: 1
pool.size.max: 16
对于大多数情况,单独的属性工作正常。然而,有时,嵌入式 yaml 更方便。在这种情况下,我们使用一个名为 application.yaml 的单个属性来嵌入我们的 yaml,如下所示
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yaml: |-
pool:
size:
core: 1
max:16
以下示例也有效
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
custom-name.yaml: |-
pool:
size:
core: 1
max:16
您还可以根据标签定义搜索,例如
spring:
application:
name: labeled-configmap-with-prefix
cloud:
kubernetes:
config:
enabled: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
letter: a
这将在命名空间 spring-k8s 中搜索所有带有标签 {letter : a} 的 configmap。这里需要注意的重要一点是,与按名称读取 configmap 不同,这可能导致读取多个 configmap。像往常一样,Secrets 也支持相同的功能。
您还可以根据活动的配置文件以不同的方式配置 Spring Boot 应用程序,这些配置文件在读取 ConfigMap 时会合并在一起。您可以使用 application.properties 或 application.yaml 属性为不同的配置文件提供不同的属性值,每个值都在其自己的文档中指定(由 --- 序列指示),如下所示
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
在前面的情况下,加载到您的 Spring 应用程序中带有 development 配置文件的配置如下所示
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
但是,如果 production 配置文件处于活动状态,则配置变为
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
如果两个配置文件都处于活动状态,则 ConfigMap 中最后出现的属性将覆盖所有先前的值。
另一个选项是为每个配置文件创建一个不同的配置映射,Spring Boot 将根据活动的配置文件自动获取它
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 文档。在部署到 Kubernetes 时激活特定配置文件的一种选择是使用环境变量启动您的 Spring Boot 应用程序,您可以在 PodSpec 中的容器规范处定义该变量。部署资源文件,如下所示
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"
您可能会遇到多个配置映射具有相同属性名称的情况。例如
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-one
data:
application.yml: |-
greeting:
message: Say Hello from one
和
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-two
data:
application.yml: |-
greeting:
message: Say Hello from two
根据您在 bootstrap.yaml|properties 中放置这些的顺序,您可能会得到意想不到的结果(最后一个配置映射获胜)。例如
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。
有一种方法可以通过指定 useNameAsPrefix 来更改此默认配置。例如
spring:
application:
name: with-prefix
cloud:
kubernetes:
config:
useNameAsPrefix: true
namespace: default-namespace
sources:
- name: config-map-one
useNameAsPrefix: false
- name: config-map-two
这样的配置将生成两个属性
-
greetings.message等于Say Hello from one。 -
config-map-two.greetings.message等于Say Hello from two
请注意,spring.cloud.kubernetes.config.useNameAsPrefix 的优先级低于 spring.cloud.kubernetes.config.sources.useNameAsPrefix。这允许您为所有源设置“默认”策略,同时允许仅覆盖少数几个。
如果使用配置映射名称不可行,您可以指定另一种策略,称为:explicitPrefix。由于这是一个您选择的显式前缀,因此它只能提供给 sources 级别。同时,它的优先级高于 useNameAsPrefix。假设我们有第三个配置映射,其中包含以下条目
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-three
data:
application.yml: |-
greeting:
message: Say Hello from three
如下面的配置
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
将生成三个属性
-
greetings.message等于Say Hello from one。 -
two.greetings.message等于Say Hello from two。 -
config-map-three.greetings.message等于Say Hello from three。
以同样的方式为 ConfigMap 配置前缀,您也可以为 Secrets 进行配置;无论是基于名称的 Secret 还是基于标签的 Secret。例如
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enabled: 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 的名称。
需要记住的另一件事是,我们支持每个 Secret 的 prefix。最简单的解释方法是通过一个示例
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enabled: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
color: blue
useNameAsPrefix: true
假设匹配此类标签的查询将返回两个 Secrets:secretA 和 secretB。这两个 Secret 具有相同的属性名称:color=sea-blue 和 color=ocean-blue。由于 useNamesAsPrefix=true,将加载两个属性源
-
secretA.color=sea-blue -
secretB.color=ocean-blue
默认情况下,除了读取 sources 配置中指定的配置映射外,Spring 还会尝试从“配置文件感知”源中读取所有属性。最简单的解释方法是通过一个示例。假设您的应用程序启用了名为“dev”的配置文件,并且您有如下配置
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。
您可以禁用此“基于配置文件的源”,然后将不再尝试 config-map-one-dev
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
includeProfileSpecificSources: false
namespace: default-namespace
sources:
- name: config-map-one
includeProfileSpecificSources: false
自版本 5.0.0 起,includeProfileSpecificSources 仅支持命名源 (spring.cloud.kubernetes.sources.name=XXX);对带标签源的支持已被移除。 |
请注意,就像以前一样,您可以在两个级别指定此属性:针对所有配置映射或针对单个配置映射;后者具有更高的优先级。
| 您应该检查安全配置部分。要从 Pod 内部访问配置映射,您需要拥有正确的 Kubernetes 服务帐户、角色和角色绑定。 |
在某些情况下,您的应用程序可能无法使用 Kubernetes API 加载某些 ConfigMaps。如果您希望您的应用程序在这种情况下启动失败,您可以设置 spring.cloud.kubernetes.config.fail-fast=true,使应用程序启动时抛出异常。
您还可以让应用程序在失败时重试加载 ConfigMap 属性源。首先,您需要设置 spring.cloud.kubernetes.config.fail-fast=true。然后您需要在类路径中添加 spring-retry 和 spring-boot-starter-aspectj。您可以通过设置 spring.cloud.kubernetes.config.retry.* 属性来配置重试属性,例如最大尝试次数、退避选项(如初始间隔、乘数、最大间隔)。
如果您由于某种原因已将 spring-retry 和 spring-boot-starter-aspectj 放在类路径中,并且希望启用快速失败,但又不想启用重试;您可以通过设置 spring.cloud.kubernetes.config.retry.enabled=false 来禁用 ConfigMap PropertySources 的重试。 |
自版本 5.0.0 起,我们引入了单独读取源的可能性。到目前为止,我们会转到命名空间并读取所有可用的 configmap / secrets,然后过滤掉请求的那些。自 5.0.0-M3 起,您可以通过设置属性 spring.cloud.kubernetes.config.read-type=SINGLE 来指定要单独读取它们。以前在命名空间中全部读取的选项由 spring.cloud.kubernetes.config.read-type=BATCH 控制,并且是默认选项。 |
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
|
|
|
启用 ConfigMaps |
|
|
|
设置要查找的 |
|
|
客户端命名空间 |
设置要查找的 Kubernetes 命名空间 |
|
|
|
在加载 |
|
|
|
启用或禁用配置重试。 |
|
|
|
初始重试间隔,单位为毫秒。 |
|
|
|
最大尝试次数。 |
|
|
|
回退的最大间隔。 |
|
|
|
下一个间隔的乘数。 |