5. Kubernetes PropertySource 实现
配置 Spring Boot 应用程序的最常见方法是创建一个application.properties
或application.yaml
或
一application-profile.properties
或application-profile.yaml
文件,其中包含为
应用程序或 Spring Boot Starters。您可以通过指定系统属性或环境来覆盖这些属性
变量。
5.1. 使用ConfigMap
PropertySource
Kubernetes 提供了一个名为ConfigMap
要将
参数以键值对或嵌入式的形式传递给应用程序application.properties
或application.yaml
文件。
Spring Cloud Kubernetes Config 项目使 KubernetesConfigMap
可用实例
在应用程序引导期间,并在检测到更改时触发 bean 或 Spring 上下文的热重载
观察ConfigMap
实例。
默认行为是创建一个Fabric8ConfigMapPropertySource
基于 KubernetesConfigMap
具有metadata.name
值为
您的 Spring 应用程序(由其spring.application.name
属性)或在bootstrap.properties
file 的 key 下:spring.cloud.kubernetes.config.name
.
但是,在您可以使用多个ConfigMap
实例。
这spring.cloud.kubernetes.config.sources
List 使这成为可能。
例如,您可以定义以下内容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
未定,
这ConfigMap
叫c1
将在应用程序运行的命名空间中查找。
请参阅 命名空间解析 以更好地了解命名空间
的申请已解决。
任何匹配项ConfigMap
的处理方式如下:
-
应用单个配置属性。
-
应用身份
yaml
任何名为application.yaml
. -
将任何名为
application.properties
.
上述流程的一个例外是ConfigMap
包含一个键,该键指示
该文件是 YAML 或属性文件。在这种情况下,键的名称不必为application.yaml
或application.properties
(它可以是任何东西),并且该属性的值被正确处理。
此功能有助于ConfigMap
是使用如下内容创建的:
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
假设我们有一个名为demo
使用以下属性读取其线程池
配置。
-
pool.size.core
-
pool.size.maximum
这可以外部化到 config map 中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 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
profile 如下:
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
但是,如果production
profile 处于活动状态,则配置将变为:
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
应该在 bootstrap 中启用,你可以将SPRING_PROFILES_ACTIVE
环境变量。
为此,您可以使用环境变量启动 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"
你可能会遇到多个具有相同属性名称的 configs 映射的情况。例如:
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
.
这允许您为所有源设置 “default” 策略,同时只允许覆盖少数源。
如果无法使用配置映射名称,则可以指定不同的策略,称为: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
.
默认情况下,除了读取sources
configuration 时,Spring 也会尝试读取
来自 “Profile Aware” 源的所有属性。解释这一点的最简单方法是通过一个例子。假设您的应用程序
启用名为 “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
;按此特定顺序。每个活动配置文件
生成这样的配置文件感知配置 Map。
虽然你的应用程序不应该受到这种配置映射的影响,但如果需要,可以禁用它:
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
includeProfileSpecificSources: false
namespace: default-namespace
sources:
- name: config-map-one
includeProfileSpecificSources: false
请注意,和之前一样,有两个级别可以指定此属性:for all config maps 或 对于单个 ID;后者具有更高的优先级。
您应该检查安全配置部分。要从 Pod 内部访问配置映射,你需要拥有正确的 Kubernetes 服务帐户、角色和角色绑定。 |
使用ConfigMap
实例是通过运行 Spring Cloud Kubernetes 应用程序将它们挂载到 Pod 中
以及让 Spring Cloud Kubernetes 从文件系统中读取它们。
此行为由spring.cloud.kubernetes.config.paths
财产。您可以在
添加或代替前面描述的机制。
您可以在spring.cloud.kubernetes.config.paths
通过使用,
定界符。
您必须提供每个属性文件的完整确切路径,因为目录不会被递归解析。 |
如果您使用spring.cloud.kubernetes.config.paths 或spring.cloud.kubernetes.secrets.path 自动重新加载
功能将不起作用。您需要制作一个POST 请求发送到/actuator/refresh endpoint 或
重新启动/重新部署应用程序。 |
在某些情况下,您的应用程序可能无法加载某些ConfigMaps
使用 Kubernetes API。
如果您希望应用程序在这种情况下启动过程失败,则可以设置spring.cloud.kubernetes.config.fail-fast=true
使应用程序启动失败并显示 Exception。
您还可以让应用程序重试加载ConfigMap
property sources 的 source 来执行。首先,您需要
设置spring.cloud.kubernetes.config.fail-fast=true
.然后你需要添加spring-retry
和spring-boot-starter-aop
添加到您的 Classpath 中。您可以配置重试属性,例如
最大尝试次数、回退选项(如 Initial Interval、Multiplier、Max Interval),方法是将spring.cloud.kubernetes.config.retry.*
性能。
如果您已经拥有spring-retry 和spring-boot-starter-aop 由于某种原因,在 Classpath 上
并希望启用快速失败,但不希望启用重试;您可以对ConfigMap PropertySources 通过设置spring.cloud.kubernetes.config.retry.enabled=false . |
名字 | 类型 | 违约 | 描述 |
---|---|---|---|
|
|
|
启用 ConfigMap |
|
|
|
设置 |
|
|
客户端命名空间 |
设置要查找的 Kubernetes 命名空间 |
|
|
|
设置路径 |
|
|
|
启用或禁用使用 |
|
|
|
启用或禁用在加载 |
|
|
|
启用或禁用配置重试。 |
|
|
|
初始重试间隔(以毫秒为单位)。 |
|
|
|
最大尝试次数。 |
|
|
|
回退的最大间隔。 |
|
|
|
下一个间隔的乘数。 |
5.2. 秘密 PropertySource
Kubernetes 具有用于存储
敏感数据,例如密码、OAuth 令牌等。该项目提供与Secrets
制作 secret
可由 Spring Boot 应用程序访问。您可以通过设置spring.cloud.kubernetes.secrets.enabled
财产。
启用后,Fabric8SecretsPropertySource
在 Kubernetes 中查找Secrets
来自以下来源:
-
从 secrets 挂载中递归读取
-
以应用程序命名(由
spring.application.name
) -
匹配一些标签
注意:
默认情况下,出于安全原因,通过 API 使用密钥(上述第 2 点和第 3 点)未启用。对 Secret 的权限 'list' 允许客户端检查指定命名空间中的 Secret 值。 此外,我们建议容器通过挂载的卷共享密钥。
如果您允许通过 API 使用 Secrets,我们建议您使用授权策略(如 RBAC)来限制对 Secrets 的访问。 有关通过 API 使用 Secrets 时的风险和最佳实践的更多信息,请参阅此文档。
如果找到密钥,则其数据将可供应用程序使用。
假设我们有一个名为demo
它使用 properties 来读取其数据库
配置。我们可以使用以下命令创建 Kubernetes 密钥:
kubectl create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd
前面的命令将创建以下密钥(您可以使用kubectl get secrets db-secret -o yaml
):
apiVersion: v1
data:
password: cDQ1NXcwcmQ=
username: dXNlcg==
kind: Secret
metadata:
creationTimestamp: 2017-07-04T09:15:57Z
name: db-secret
namespace: default
resourceVersion: "357496"
selfLink: /api/v1/namespaces/default/secrets/db-secret
uid: 63c89263-6099-11e7-b3da-76d6186905a8
type: Opaque
请注意,数据包含create
命令。
然后,您的应用程序可以使用此密钥 — 例如,通过将密钥的值导出为环境变量:
apiVersion: v1
kind: Deployment
metadata:
name: ${project.artifactId}
spec:
template:
spec:
containers:
- env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
您可以通过多种方式选择要使用的密钥:
-
通过列出映射 secret 的目录:
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets/db-secret,etc/secrets/postgresql
如果您已将所有密钥映射到一个公共根,则可以像这样设置它们:
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
-
通过设置命名密钥:
-Dspring.cloud.kubernetes.secrets.name=db-secret
-
通过定义标签列表:
-Dspring.cloud.kubernetes.secrets.labels.broker=activemq -Dspring.cloud.kubernetes.secrets.labels.db=postgresql
与ConfigMap
,在您可以使用多个Secret
实例。这spring.cloud.kubernetes.secrets.sources
List 使这成为可能。
例如,您可以定义以下内容Secret
实例:
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
secrets:
name: default-name
namespace: default-namespace
sources:
# Spring Cloud Kubernetes looks up a Secret named s1 in namespace default-namespace
- name: s1
# Spring Cloud Kubernetes looks up a Secret named default-name in namespace n2
- namespace: n2
# Spring Cloud Kubernetes looks up a Secret named s3 in namespace n3
- namespace: n3
name: s3
在前面的示例中,如果spring.cloud.kubernetes.secrets.namespace
未定,
这Secret
叫s1
将在应用程序运行的命名空间中查找。
请参阅 namespace-resolution 以更好地了解命名空间
的申请已解决。
与ConfigMaps
;如果您希望应用程序无法启动
当无法加载时Secrets
property sources 中,您可以设置spring.cloud.kubernetes.secrets.fail-fast=true
.
也可以为Secret
属性源就像ConfigMaps
.
与ConfigMap
property 源,首先需要设置spring.cloud.kubernetes.secrets.fail-fast=true
.
然后你需要添加spring-retry
和spring-boot-starter-aop
添加到您的 Classpath 中。
重试行为Secret
属性源可以通过设置spring.cloud.kubernetes.secrets.retry.*
性能。
如果您已经拥有spring-retry 和spring-boot-starter-aop 由于某种原因,在 Classpath 上
并希望启用快速失败,但不希望启用重试;您可以对Secrets PropertySources 通过设置spring.cloud.kubernetes.secrets.retry.enabled=false . |
名字 | 类型 | 违约 | 描述 |
---|---|---|---|
|
|
|
启用 Secret |
|
|
|
设置要查找的 secret 的名称 |
|
|
客户端命名空间 |
设置要查找的 Kubernetes 命名空间 |
|
|
|
设置用于查找密钥的标签 |
|
|
|
设置 secret 的挂载路径(示例 1) |
|
|
|
启用或禁用通过 API 使用密钥(示例 2 和 3) |
|
|
|
启用或禁用在加载 |
|
|
|
启用或禁用密钥重试。 |
|
|
|
初始重试间隔(以毫秒为单位)。 |
|
|
|
最大尝试次数。 |
|
|
|
回退的最大间隔。 |
|
|
|
下一个间隔的乘数。 |
笔记:
-
这
spring.cloud.kubernetes.secrets.labels
属性的行为与基于 Map 的绑定定义的行为相同。 -
这
spring.cloud.kubernetes.secrets.paths
property 的行为与 Collection based binding(基于集合的绑定)定义的行为相同。 -
出于安全原因,通过 API 访问密钥可能会受到限制。首选方法是将 secret 挂载到 Pod。
您可以找到一个使用 Secret 的应用程序示例(尽管它尚未更新为使用新的spring-cloud-kubernetes
项目)位于 spring-boot-camel-config
5.3. 命名空间解析
查找应用程序命名空间是尽最大努力进行的。我们按顺序迭代一些步骤 找到它。最简单和最常见的一种是在适当的配置中指定它,例如:
spring:
application:
name: app
cloud:
kubernetes:
secrets:
name: secret
namespace: default
sources:
# Spring Cloud Kubernetes looks up a Secret named 'a' in namespace 'default'
- name: a
# Spring Cloud Kubernetes looks up a Secret named 'secret' in namespace 'b'
- namespace: b
# Spring Cloud Kubernetes looks up a Secret named 'd' in namespace 'c'
- namespace: c
name: d
请记住,也可以对 config maps 执行相同的作。如果未指定这样的命名空间,则将读取它(按此顺序):
-
from property (从属性)
spring.cloud.kubernetes.client.namespace
-
从驻留在由
spring.cloud.kubernetes.client.serviceAccountNamespacePath
财产 -
从驻留在
/var/run/secrets/kubernetes.io/serviceaccount/namespace
文件 (Kubernetes 默认命名空间路径) -
从指定的客户端方法调用(例如 fabric8 的 :
KubernetesClient::getNamespace
),如果客户端提供 这样的方法。反过来,这可以通过环境属性进行配置。例如,fabric8 客户端可以通过 “KUBERNETES_NAMESPACE” 属性;有关确切的详细信息,请参阅客户端文档。
如果无法从上述步骤中找到命名空间,将导致引发 Exception。
5.4. ConfigMap 和 Secret 的顺序
如果出于某种原因,您同时启用了 configmap 和 secrets,并且它们之间存在公共属性,则 ConfigMap 中的值将具有更高的优先级。也就是说:它将覆盖在 secret 中找到的任何值。
5.5.PropertySource
重新加载
此功能在 2020.0 版本中已弃用。请参阅 Spring Cloud Kubernetes Configuration Watcher 控制器作为另一种方式 以实现相同的功能。 |
某些应用程序可能需要检测外部属性源上的更改并更新其内部状态以反映新配置。
Spring Cloud Kubernetes 的 reload 功能能够在相关的ConfigMap
或Secret
变化。
默认情况下,此功能处于禁用状态。您可以使用spring.cloud.kubernetes.reload.enabled=true
configuration 属性(例如,在application.properties
文件)。
支持以下级别的重新加载(通过将spring.cloud.kubernetes.reload.strategy
property) 的
-
refresh
(默认):仅带有@ConfigurationProperties
或@RefreshScope
重新加载。 此重新加载级别利用 Spring Cloud Context 的刷新功能。 -
restart_context
:整个SpringApplicationContext
将正常重新启动。使用新配置重新创建 Bean。 为了使 restart context 功能正常工作,您必须启用并公开 restart actuator 端点
management: endpoint: restart: enabled: true endpoints: web: exposure: include: restart
-
shutdown
: 弹簧ApplicationContext
已关闭以激活容器的重新启动。 当您使用此级别时,请确保所有非守护进程线程的生命周期都绑定到ApplicationContext
以及将复制控制器或副本集配置为重新启动 Pod。
假设使用默认设置 (refresh
模式),当 config map 更改时,将刷新以下 Bean:
@Configuration @ConfigurationProperties(prefix = "bean") public class MyConfig { private String message = "a message that can be changed live"; // getter and setters }
要查看更改有效地发生,您可以创建另一个定期打印消息的 bean,如下所示
@Component
public class MyBean {
@Autowired
private MyConfig config;
@Scheduled(fixedDelay = 5000)
public void hello() {
System.out.println("The message is: " + config.getMessage());
}
}
您可以使用ConfigMap
如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: reload-example
data:
application.properties: |-
bean.message=Hello World!
对名为bean.message
在ConfigMap
与 Pod 关联的 Pod 反映在
输出。更一般地说,与以prefix
字段的@ConfigurationProperties
注释被检测并反映在应用程序中。将ConfigMap
带 Pod在本章前面进行了解释。
重新加载功能支持两种作模式:
* 事件 (默认):使用 Kubernetes API (Web 套接字) 监视配置映射或 secret 中的更改。
任何事件都会对配置产生重新检查,如果发生更改,则会重新加载。
这view
role,才能侦听 Config Map 更改。更高级别的角色(例如edit
) 是密钥所必需的
(默认情况下,不监控密钥)。
* 轮询:定期从配置映射和 secret 重新创建配置,以查看它是否已更改。
您可以使用spring.cloud.kubernetes.reload.period
属性,默认为 15 秒。
它需要与受监控属性源相同的角色。
这意味着,例如,对文件挂载的密钥源使用轮询不需要特定权限。
名字 | 类型 | 违约 | 描述 |
---|---|---|---|
|
|
|
支持监控资产源和配置重新加载 |
|
|
|
允许监控配置映射中的更改 |
|
|
|
允许监控密钥中的更改 |
|
|
|
开火装填时使用的策略 ( |
|
|
|
指定如何侦听属性源 ( |
|
|
|
使用 |
笔记:
* 您不应使用spring.cloud.kubernetes.reload
在 Config Maps 或 Secret 中。在运行时更改此类属性可能会导致意外结果。
* 删除属性或整个配置映射不会恢复 bean 的原始状态,当您使用refresh
水平。