使用 `ConfigMap` `PropertySource`
Kubernetes 提供了一个名为 ConfigMap
的资源,用于以键值对或嵌入式 application.properties
或 application.yaml
文件的形式将参数外部化到您的应用程序。 Spring Cloud Kubernetes Config 项目在应用程序启动期间使 Kubernetes `ConfigMap` 实例可用,并在检测到观察到的 `ConfigMap` 实例发生更改时触发 Bean 或 Spring 上下文的热重载。
以下所有内容主要通过使用 ConfigMap 的示例进行解释,但 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 或属性文件时。在这种情况下,键的名称不必是 `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 不同,这可能导致读取 *多个* 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
在前面的情况下,加载到具有 `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 时激活特定配置文件的一种方法是使用可以在容器规范的 PodSpec 中定义的环境变量启动 Spring Boot 应用程序。部署资源文件,如下所示:
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 获胜)。例如:
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 的前缀;对于基于名称的 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 map。唯一的区别是,通过标签查找 secrets 可能会找到多个源。在这种情况下,前缀(如果通过useNameAsPrefix
指定)将是为这些特定标签找到的所有 secrets 的名称。
还有一点需要注意的是,我们支持每个源的prefix
,而不是每个 secret 的prefix
。最简单的解释方法是通过一个例子
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
(自然排序连接的 secrets 名称)。
如果您需要更细粒度的结果,可以添加更多标签来唯一标识 secret。
默认情况下,除了读取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
;按照此特定顺序。每个活动的配置文件都会生成这样的配置文件感知的 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 map 或单个 config map;后者具有更高的优先级。
您应该检查安全配置部分。要从 Pod 内部访问 config map,您需要拥有正确的 Kubernetes 服务帐户、角色和角色绑定。 |
使用ConfigMap
实例的另一种方法是,通过运行 Spring Cloud Kubernetes 应用程序并将 Spring Cloud Kubernetes 从文件系统中读取它们,将其安装到 Pod 中。
此功能已弃用,将在未来的版本中删除(请改用spring.config.import )。此行为由spring.cloud.kubernetes.config.paths 属性控制。您可以将其与前面描述的机制一起使用,也可以代替它。spring.cloud.kubernetes.config.paths 需要每个属性文件的完整路径列表,因为不会递归解析目录。例如 |
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 ,并且想要启用快速失败,但不想启用重试;您可以通过设置spring.cloud.kubernetes.config.retry.enabled=false 来禁用ConfigMap PropertySources 的重试。 |
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
|
|
|
启用 ConfigMaps |
|
|
|
设置要查找的 |
|
|
客户端命名空间 |
设置要在其中查找的 Kubernetes 命名空间 |
|
|
|
设置安装 |
|
|
|
启用或禁用通过 API 使用 |
|
|
|
启用或禁用在加载 |
|
|
|
启用或禁用配置重试。 |
|
|
|
以毫秒为单位的初始重试间隔。 |
|
|
|
最大尝试次数。 |
|
|
|
回退的最大间隔。 |
|
|
|
下一个间隔的乘数。 |