137. Kubernetes PropertySource 实现
配置 Spring Boot 应用程序的最常见方法是创建一个包含键-值对的application.properties|yaml
或application-profile.properties|yaml
文件,这些键-值对为应用程序或 Spring Boot 启动器提供自定义值。用户可以通过指定系统属性或环境变量来覆盖这些属性。
137.1 ConfigMap PropertySource
Kubernetes 提供了一个名为ConfigMap的资源,用于以键值对或嵌入式application.properties|yaml
文件的形式外部化要传递给您的应用程序的参数。 Spring Cloud Kubernetes 配置项目使 Kubernetes 的 ConfigMap 在应用程序引导期间可用,并且在观察到的 ConfigMap 上检测到更改时触发 Bean 或 Spring 上下文的热重载。
默认行为是基于 Kubernetes ConfigMap
创建一个ConfigMapPropertySource
,该_3 具有您的 Spring 应用程序名称(由其spring.application.name
属性定义)的metadata.name
或在bootstrap.properties
文件中的以下键spring.cloud.kubernetes.config.name
下定义的自定义名称。
但是,在可以使用多个 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 will lookup a ConfigMap named c1 in namespace default-namespace
- name: c1
# Spring Cloud Kubernetes will lookup a ConfigMap named default-name in whatever namespace n2
- namespace: n2
# Spring Cloud Kubernetes will lookup a ConfigMap named c3 in namespace n3
- namespace: n3
name: c3
在上面的示例中,尚未设置spring.cloud.kubernetes.config.namespace
,然后将在应用程序运行的名称空间中查找名为c1
的 ConfigMap。
找到的任何匹配的ConfigMap
将按以下方式处理:
-
应用各个配置属性。
-
将名为
application.yaml
的任何属性的内容用作yaml
-
将名为
application.properties
的任何属性的内容用作属性文件
上述流程的唯一 exception 是ConfigMap
包含表示文件是 YAML 或属性文件的 单 键。在这种情况下,键的名称不必为application.yaml
或application.properties
(可以是任何值),并且该属性的值将被正确处理。此功能有助于使用以下方式创建ConfigMap
的用例:
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
Example:
假设我们有一个名为demo
的 Spring Boot 应用程序,该应用程序使用属性读取其线程池配置。
-
pool.size.core
-
pool.size.maximum
可以将其外部化为yaml
格式的配置 Map:
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
pool.size.core: 1
pool.size.max: 16
在大多数情况下,单个属性都可以正常工作,但有时嵌入yaml
更为方便。在这种情况下,我们将使用一个名为application.yaml
的属性来嵌入yaml
:
```yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yaml: |-
pool:
size:
core: 1
max:16
The following also works:
```yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
custom-name.yaml: |-
pool:
size:
core: 1
max:16
还可以根据Active配置文件对 Spring Boot 应用程序进行不同的配置,这些配置文件在读取 ConfigMap 时将合并在一起。可以使用application.properties|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
配置文件处于Active状态,则配置为:
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
如果两个配置文件都处于Active状态,则配置 Map 中最后出现的属性将覆盖先前的值。
为了告诉 Spring Boot 应该在引导程序中启用哪个profile
,可以使用环境变量将系统属性传递给 Java 命令,以使用 OpenShift DeploymentConfig
或 Kubernetes ReplicationConfig
资源文件定义一个 env 变量来启动 Spring Boot 应用程序,如下所示:
apiVersion: v1
kind: DeploymentConfig
spec:
replicas: 1
...
spec:
containers:
- env:
- name: JAVA_APP_DIR
value: /deployments
- name: JAVA_OPTIONS
value: -Dspring.profiles.active=developer
注意: -检查“安全配置”部分,要从 Pod 内部访问配置 Map,您需要具有正确的 Kubernetes 服务帐户,角色和角色绑定。
使用 ConfigMaps 的另一个选项是将它们安装到运行 Spring Cloud Kubernetes 应用程序的 Pod 中,并让 Spring Cloud Kubernetes 从文件系统中读取它们。此行为由spring.cloud.kubernetes.config.paths
属性控制,可以作为上述机制的补充或替代。可以使用,
分隔符在spring.cloud.kubernetes.config.paths
中指定多个(精确)文件路径
表 137.1. 属性:
Name | Type | Default | Description |
---|---|---|---|
spring.cloud.kubernetes.config.enabled | Boolean | true | 启用机密 PropertySource |
spring.cloud.kubernetes.config.name | String | ${spring.application.name} | 将 ConfigMap 的名称设置为 lookup |
spring.cloud.kubernetes.config.namespace | String | Client namespace | 设置 Kubernetes 命名空间在哪里查找 |
spring.cloud.kubernetes.config.paths | List | null | 设置 ConfigMap 的安装路径 |
137.2 机密 PropertySource
Kubernetes 具有Secrets的概念,用于存储敏感数据,例如密码,OAuth 令牌等。此项目提供与Secrets
的集成,以使 Spring Boot 应用程序可以访问机密。可以使用spring.cloud.kubernetes.secrets.enabled
属性显式启用/禁用此功能。
启用SecretsPropertySource
后,将从以下来源查找Secrets
的 Kubernetes:
-
从 Secret 坐骑递归阅读
-
以应用程序命名(由
spring.application.name
定义) -
匹配一些标签
请注意,出于安全原因,默认情况下,未启用通过 API 消费机密(以上第 2 点和第 3 点)**,建议容器通过已安装的卷共享机密。如果启用通过 API 使用机密,则建议通过授权策略,例如 RBAC限制对机密的访问。
如果找到了机密,则其数据可供应用程序使用。
Example:
假设我们有一个名为demo
的 spring boot 应用程序,它使用属性读取其数据库配置。我们可以使用以下命令创建 Kubernetes 机密:
oc create secret generic db-secret --from-literal=username=user --from-literal=password=p455w0rd
这将创建以下 Secret(使用oc 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 命令提供的 Literals 的 Base64 编码版本。
然后,您的应用程序可以使用此 Secret,例如通过将 Secret 的值导出为环境变量来使用:
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:
- 通过列出 SecretMap 的目录:-Dspring.cloud.kubernetes.secrets.paths =/etc/secrets/db-secret,etc/secrets/postgresql``
If you have all the secrets mapped to a common root, you can set them like:
-Dspring.cloud.kubernetes.secrets.paths=/etc/secrets
-
通过设置一个命名的 Secret:``````
-
通过定义标签列表:-Dspring.cloud.kubernetes.secrets.labels.broker = activemq -Dspring.cloud.kubernetes.secrets.labels.db = postgresql
表 137.2. 属性:
Name | Type | Default | Description |
---|---|---|---|
spring.cloud.kubernetes.secrets.enabled | Boolean | true | 启用机密 PropertySource |
spring.cloud.kubernetes.secrets.name | String | ${spring.application.name} | 将 Secret 名称设置为查找 |
spring.cloud.kubernetes.secrets.namespace | String | Client namespace | 设置 Kubernetes 命名空间在哪里查找 |
spring.cloud.kubernetes.secrets.labels | Map | null | 设置用于查找机密的标签 |
spring.cloud.kubernetes.secrets.paths | List | null | 设置安装机密的路径(示例 1) |
注意: -属性spring.cloud.kubernetes.secrets.labels
的行为与Map-based binding定义的行为相同。 -属性spring.cloud.kubernetes.secrets.paths
的行为如Collection-based binding所定义。 -出于安全原因,可能会限制通过 API 访问机密,首选方式是将机密安装到 POD。
使用机密的应用示例(尽管尚未更新为使用新的spring-cloud-kubernetes
项目):spring-boot-camel-config
137.3 PropertySource 重新加载
某些应用程序可能需要检测外部属性源上的更改并更新其内部状态以反映新配置。当相关的ConfigMap
或Secret
发生更改时,Spring Cloud Kubernetes 的重新加载功能能够触发应用程序重新加载。
此功能默认情况下处于禁用状态,可以使用配置属性spring.cloud.kubernetes.reload.enabled=true
启用(例如,在 application.properties 文件中)。
支持以下级别的重载(属性spring.cloud.kubernetes.reload.strategy
):- refresh
(默认) :仅重载带有@ConfigurationProperties
或@RefreshScope
Comments 的配置 bean。此重载级别利用了 Spring Cloud Context 的刷新功能。 - restart_context
:整个 Spring * ApplicationContext *正常重启。使用新配置重新创建 Bean。 - shutdown
:关闭 Spring * ApplicationContext *以激活容器的重启。使用此级别时,请确保所有非守护进程线程的生命周期都已绑定到 ApplicationContext,并且已将复制控制器或副本集配置为重新启动 Pod。
Example:
假设使用默认设置( refresh
模式)启用了重载功能,那么当配置 Map 更改时,以下 Bean 将被刷新:
@Configuration
@ConfigurationProperties(prefix = "bean")
public class MyConfig {
private String message = "a message that can be changed live";
// getter and setters
}
观察更改有效发生的一种方法是创建另一个 bean,该 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!
与 pod 关联的ConfigMap
中名为bean.message
的属性的任何更改都将反映在输出中。更一般地说,与属性相关联的更改将以@ConfigurationProperties
注解的prefix
字段定义的值为前缀,并会在应用程序中反映出来。上面说明了将+116+
与广告连播相关联。
完整示例可在spring-cloud-kubernetes-reload-example中找到。
重新加载功能支持两种操作模式:-事件(默认) :使用 Kubernetes API(Web 套接字)监视配置 Map 或机密的更改.任何事件都会对配置进行重新检查,并在发生更改的情况下重新加载.服务帐户上的view
角色是必需的,以便侦听配置 Map 更改.Secret 需要更高级别的角色(例如edit
)(默认情况下不监视 Secret).- 轮询 :从配置 Map 和 Secret 中定期重新创建配置,以查看其是否已更改.可以使用属性spring.cloud.kubernetes.reload.period
来配置轮询时间,默认为 15 秒**。它需要与受监视的属性源相同的角色。例如,这意味着对文件安装的机密源使用轮询不需要特定的特权。
表 137.3. 属性:
Name | Type | Default | Description |
---|---|---|---|
spring.cloud.kubernetes.reload.enabled | Boolean | false | 启用监视属性源和配置重载 |
spring.cloud.kubernetes.reload.monitoring-config-maps | Boolean | true | 允许监视配置 Map 中的更改 |
spring.cloud.kubernetes.reload.monitoring-secrets | Boolean | false | 允许监视机密更改 |
spring.cloud.kubernetes.reload.strategy | Enum | refresh | 触发重新加载时使用的策略( refresh , restart_context , shutdown ) |
spring.cloud.kubernetes.reload.mode | Enum | event | 指定如何侦听属性源中的更改( event , polling ) |
注意 :- spring.cloud.kubernetes.reload. 下的属性不应在配置 Map 或机密中使用:在运行时更改此类属性可能会导致意外结果; -使用“刷新”级别时,删除属性或整个配置 Map 不会恢复 Bean 的原始状态。