使用 ConfigMap
PropertySource
Kubernetes 提供了一个名为 ConfigMap
的资源,用于将传递给应用程序的参数外部化,这些参数可以采用键值对或嵌入式 application.properties
或 application.yaml
文件形式。 Spring Cloud Kubernetes Config 项目在应用程序启动期间提供 Kubernetes ConfigMap
实例,并在检测到被观察的 ConfigMap
实例发生更改时触发 Bean 或 Spring 上下文的热重载。
以下所有内容主要参考使用 ConfigMaps 的示例进行解释,但 Secrets 也同样适用,即:每个功能都支持 ConfigMaps 和 Secrets。
默认行为是基于 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
的值命名的属性内容作为yaml
(或properties
)应用(如果不存在,则使用application.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 或 properties 文件时。 在这种情况下,键的名称不必是 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
格式的 config map:
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:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
letter: a
这将在命名空间 spring-k8s
中搜索所有具有标签 {letter : a}
的 configmap。 这里需要注意的重要一点是,与按名称读取 configmap 不同,这可能会导致读取多个 config map。 和往常一样,Secrets 也支持相同的功能。
您还可以根据读取 ConfigMap
时合并的活动配置文件来以不同方式配置 Spring Boot 应用程序。 您可以使用 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
在上述情况下,加载到您的具有 development
配置文件的 Spring 应用程序中的配置如下:
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
中最后出现的属性会覆盖所有前面的值。
另一种选择是为每个配置文件创建一个不同的 config map,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 的容器规范中定义该环境变量。Deployment 资源文件如下所示:
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"
您可能会遇到多个具有相同属性名称的 config map 的情况。例如:
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
中放置这些 config map 的顺序,您可能会得到意想不到的结果(最后一个 config map 获胜)。 例如:
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
。 这允许您为所有源设置一个“默认”策略,同时只覆盖少数几个源。
如果使用 config map 名称不是一个选择,您可以指定一个不同的策略,称为:explicitPrefix
。 由于这是一个您选择的显式前缀,因此只能应用于 sources
级别。 同时,它的优先级高于 useNameAsPrefix
。 假设我们有第三个 config map 包含这些条目:
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
。
配置 configmaps 前缀的方式同样适用于 secrets;无论是基于名称的 secrets 还是基于标签的 secrets。 例如:
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
生成属性源时,处理规则与 config maps 相同。 唯一的区别是,潜在地,按标签查找 secrets 意味着我们可能找到不止一个源。 在这种情况下,前缀(如果通过 useNameAsPrefix
指定)将是为这些特定标签找到的所有 secrets 的名称。
还需要记住一点,我们支持按源设置 prefix
,而不是按 secret 设置。 最简单的解释方法是通过示例:
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
color: blue
useNameAsPrefix: true
假设一个匹配此类标签的查询将返回两个 secrets:secret-a
和 secret-b
。 这两个 secrets 都具有相同的属性名称:color=sea-blue
和 color=ocean-blue
。 无法确定哪个 color
将最终成为属性源的一部分,但其前缀将是 secret-a.secret-b
(自然排序后拼接的 secret 名称)。
如果您需要更细粒度的结果,添加更多标签来唯一标识 secret 将是一个选项。
默认情况下,除了读取 sources
配置中指定的 config map 外,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
;顺序如前所述。 每个活动配置文件都会生成一个这样的配置文件感知 config map。
尽管您的应用程序不应受此类 config map 的影响,但如果需要,可以将其禁用。
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
includeProfileSpecificSources: false
namespace: default-namespace
sources:
- name: config-map-one
includeProfileSpecificSources: false
请注意,就像之前一样,您可以在两个级别指定此属性:应用于所有 config maps 或应用于单个 config maps;后者的优先级更高。
您应该检查安全配置部分。 要从 Pod 内部访问 config maps,您需要具有正确的 Kubernetes 服务帐户、角色和角色绑定。 |
使用 ConfigMap
实例的另一种选择是,通过运行 Spring Cloud Kubernetes 应用程序并让 Spring Cloud Kubernetes 从文件系统读取它们的方式,将它们挂载到 Pod 中。
此功能已被弃用,并将在未来的版本中移除(请改用 spring.config.import )。 此行为由 spring.cloud.kubernetes.config.paths 属性控制。 您可以使用它作为之前描述机制的补充或替代。 spring.cloud.kubernetes.config.paths 需要一个包含每个属性文件完整路径的 List,因为目录不会被递归解析。 例如: |
spring:
cloud:
kubernetes:
config:
paths:
- /tmp/application.properties
- /var/application.yaml
如果您使用 spring.cloud.kubernetes.config.paths 或 spring.cloud.kubernetes.secrets.path ,则自动重载功能将无法工作。 您需要向 /actuator/refresh 端点发送 POST 请求或重新启动/重新部署应用程序。 |
在某些情况下,您的应用程序可能无法使用 Kubernetes API 加载某些 ConfigMaps
。 如果您希望应用程序在这种情况下启动失败,可以设置 spring.cloud.kubernetes.config.fail-fast=true
使应用程序启动时抛出异常。
您还可以让应用程序在加载 ConfigMap
属性源失败时进行重试。 首先,您需要设置 spring.cloud.kubernetes.config.fail-fast=true
。 然后您需要将 spring-retry
和 spring-boot-starter-aop
添加到您的类路径。 您可以通过设置 spring.cloud.kubernetes.config.retry.*
属性来配置重试属性,例如最大尝试次数、退避选项(如初始间隔、乘数、最大间隔)。
如果您由于某种原因已将 spring-retry 和 spring-boot-starter-aop 添加到类路径中,并且想启用 fail-fast,但不想启用重试;您可以通过设置 spring.cloud.kubernetes.config.retry.enabled=false 来禁用 ConfigMap PropertySources 的重试。 |
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
|
|
|
启用 ConfigMaps |
|
|
|
设置要查找的 |
|
|
客户端命名空间 |
设置要查找的 Kubernetes 命名空间 |
|
|
|
设置挂载 |
|
|
|
启用或禁用通过 API 消费 |
|
|
|
启用或禁用在加载 |
|
|
|
启用或禁用配置重试。 |
|
|
|
初始重试间隔(毫秒)。 |
|
|
|
最大尝试次数。 |
|
|
|
退避的最大间隔。 |
|
|
|
下一个间隔的乘数。 |