序言
之前介绍过Kubernetes可以将ConfigMap或Secret作为卷挂载到应用程序容器中,当配置项发生变化时,也能实时更新挂载的卷。但是Spring Boot不会自动更新这些变更,除非重启应用。
当然Spring Cloud也提供了在不重启应用的情况下刷新应用程序上下文的能力,通过访问/refresh端点或者使用Spring Cloud Bus发布RefreshRemoteApplicationEvent。
本篇介绍Spring Cloud Kubernetes提供的直接读取ConfigMap或Secret,并自动刷新变更的方案。
Spring Cloud Kubernetes Config
Kubernetes的PropertySource实现
Kubernetes提供两种方式来实现配置数据的存储:
- ConfigMap用来将非机密性的数据保存到键值对中。
- Secret 类似于 ConfigMap 但专门用于保存机密数据。
PropertySource在Spring中用于指定资源文件读取的位置,Spring Cloud Kubernetes提供了两种实现方式。
- ConfigMap PropertySource
- Secret PropertySource
ConfigMap PropertySource
目标ConfigMap的名称只能在bootstrap.yaml中配置。
配置项:spring.cloud.kubernetes.config.name。如果没有配置,则默认使用spring.application.name作为ConfigMap的名称去查找。
如果需要读取多个ConfigMap实例的配置数据,则可以使用spring.cloud.kubernetes.config.sources来配置。
下面的配置展示了多ConfigMap实例的配置方法。
spring:
application:
# 如果没有配置spring.cloud.kubernetes.config.name,则直接使用spring.application.name
name: cloud-k8s-app
cloud:
kubernetes:
config:
name: default-name
namespace: default-namespace
sources:
# 在default-namespace命名空间下查找名为c1的ConfigMap
- name: c1
# 在n2命名空间下查找名为default-name的ConfigMap
- namespace: n2
# 在n3命名空间下查找名为c3的ConfigMap
- namespace: n3
name: c3
如果希望应用无法正确读取ConfigMap时启动失败,可设置如下参数:
spring.cloud.kubernetes.config.fail-fast=true
Secrets PropertySource
Secrets的使用方式和ConfigMap类似。相关的配置项将config改成secrets即可。
例如:如果希望应用无法正确读取Secrets时启动失败,可设置如下参数:
spring.cloud.kubernetes.secrets.fail-fast=true
自动刷新PropertySource
通常我们都需要应用具备实时刷新配置数据的功能。即修改配置数据后,应用程序能即时感知配置变化。Spring Cloud Kubernetes的重载特性能够在相关的ConfigMap或Secret更改时触发应用程序重新加载。
重载特性默认情况下是关闭的,需要使用以下配置开启。
spring.cloud.kubernetes.reload.enabled=true
Spring Cloud Kubernetes支持三种重载策略,通过spring.cloud.kubernetes.reload.strategy属性配置。
- refresh(默认值)
只有用@ConfigurationProperties或@RefreshScope注释的配置bean才会被重新加载。这个重新加载级别利用Spring Cloud Context的刷新特性。
- restart_context
整个Spring ApplicationContext被优雅地重新启动。使用新的配置重新创建bean。为了使重启上下文功能正常工作,必须启用并公开 restart actuator端点。
management:
endpoint:
restart:
enabled: true
endpoints:
web:
exposure:
include: restart
- shutdown
停止并重新启动应用容器。使用此级别时,要确保所有非守护线程的生命周期都绑定到ApplicationContext,并配置Replication Controller或Replica Set以确保应用容器关闭后能重新启动pod.
示例程序开发
依赖组件
在pom.xml添加依赖组件如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
</dependency>
配置类
ConfigMap配置读取类
@Configuration(proxyBeanMethods = false)
@ConfigurationProperties(prefix = "examples.configmap")
@Getter
@Setter
public class ConfigMapProperties {
private String errorMessage;
private Integer retryCount;
}
Secret配置读取类
@Configuration(proxyBeanMethods = false)
@ConfigurationProperties(prefix = "spring.datasource")
@Getter
@Setter
public class SecretProperties {
private String username;
private String password;
}
Application启动类
Application里写个轮询打印,1000毫秒打印一次
@SpringBootApplication
@EnableScheduling
@Slf4j
public class ConfigReloadApplication {
@Resource
private ConfigMapProperties configProperties;
@Resource
private SecretProperties secretProperties;
public static void main(String[] args) {
SpringApplication.run(ConfigReloadApplication.class, args);
}
/**
* 定时调度,每1000毫秒打印一次ConfigMap和Secrets中的配置项数据
*/
@Scheduled(fixedDelay = 1000)
public void hello() {
log.info("重试次数:{},错误消息:{},用户名:{},密码:{}",
configProperties.getRetryCount(),
configProperties.getErrorMessage(),
secretProperties.getUsername(),
secretProperties.getPassword()
);
}
}
bootstrap.yml配置
spring:
cloud:
kubernetes:
reload:
# 开启重载
enabled: true
config:
# k8s中ConfigMap的名称
name: config-reload
secrets:
# ConfigMap开启,Secrets默认关闭
enabled: true
# k8s中Secrets的名称
name: config-reload
configmap.yml
metadata:
name: ${project.artifactId}
data:
application.properties: |-
examples.configmap.errorMessage = bad gateway!
examples.configmap.retryCount = 3
secret.yml
这里的配置项默认情况下都必须转换成Base64编码,否则部署会报错(也可配置成明文存储)。
metadata:
name: ${project.artifactId}
data:
spring.datasource.username : cm9vdA==
spring.datasource.password : cm9vdA==
deployment.yml
将Secrets的配置项设置成环境变量
spec:
template:
spec:
serviceAccount: ${project.artifactId}
containers:
- env:
- name: spring.datasource.username
valueFrom:
secretKeyRef:
name: config-reload
key: spring.datasource.username
- name: spring.datasource.password
valueFrom:
secretKeyRef:
name: config-reload
key: spring.datasource.password
这样配置如果配置项很多的话,那将是一场灾难。也可以采取一次性导入的方式:
spec:
template:
spec:
serviceAccount: ${project.artifactId}
containers:
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- secretRef:
name: config-reload
帐号授权
由于要访问pods,configmaps,secrets,所以还需要对serviceAccount授权。
role.yml
metadata:
name: ${project.artifactId}-reader
rules:
- apiGroups: [ "" ]
resources: [ "pods","configmaps", "secrets" ]
verbs: [ "get", "watch", "list" ]
rolebinding.yml
metadata:
name: ${project.artifactId}-reader-bind
roleRef:
kind: Role
name: ${project.artifactId}-reader
subjects:
- kind: ServiceAccount
name: ${project.artifactId}
执行效果
部署启动后查看日志
kubectl logs -f config-reload-5d59c6fbf6-9bpb8
可以看到Secrets中Base64编码被转化成正常字符后打印出来了:
修改配置,重试次数改成333
kubectl edit configmap/config-reload
再看日志,马上打印新配置了。
附配置表
ConfigMap PropertySource属性配置
| Name | Type | Default | Description |
|---|---|---|---|
spring.cloud.kubernetes.config.enabled | Boolean | true | Enable ConfigMaps PropertySource |
spring.cloud.kubernetes.config.name | String | ${spring.application.name} | Sets the name of ConfigMap to look up |
spring.cloud.kubernetes.config.namespace | String | Client namespace | Sets the Kubernetes namespace where to lookup |
spring.cloud.kubernetes.config.paths | List | null | Sets the paths where ConfigMap instances are mounted |
spring.cloud.kubernetes.config.enableApi | Boolean | true | Enable or disable consuming ConfigMap instances through APIs |
spring.cloud.kubernetes.config.fail-fast | Boolean | false | Enable or disable failing the application start-up when an error occurred while loading a ConfigMap |
spring.cloud.kubernetes.config.retry.enabled | Boolean | true | Enable or disable config retry. |
spring.cloud.kubernetes.config.retry.initial-interval | Long | 1000 | Initial retry interval in milliseconds. |
spring.cloud.kubernetes.config.retry.max-attempts | Integer | 6 | Maximum number of attempts. |
spring.cloud.kubernetes.config.retry.max-interval | Long | 2000 | Maximum interval for backoff. |
spring.cloud.kubernetes.config.retry.multiplier | Double | 1.1 | Multiplier for next interval. |
Secrets PropertySource属性配置
| Name | Type | Default | Description |
|---|---|---|---|
spring.cloud.kubernetes.secrets.enabled | Boolean | true | Enable Secrets PropertySource |
spring.cloud.kubernetes.secrets.name | String | ${spring.application.name} | Sets the name of the secret to look up |
spring.cloud.kubernetes.secrets.namespace | String | Client namespace | Sets the Kubernetes namespace where to look up |
spring.cloud.kubernetes.secrets.labels | Map | null | Sets the labels used to lookup secrets |
spring.cloud.kubernetes.secrets.paths | List | null | Sets the paths where secrets are mounted (example 1) |
spring.cloud.kubernetes.secrets.enableApi | Boolean | false | Enables or disables consuming secrets through APIs (examples 2 and 3) |
spring.cloud.kubernetes.secrets.fail-fast | Boolean | false | Enable or disable failing the application start-up when an error occurred while loading a Secret |
spring.cloud.kubernetes.secrets.retry.enabled | Boolean | true | Enable or disable secrets retry. |
spring.cloud.kubernetes.secrets.retry.initial-interval | Long | 1000 | Initial retry interval in milliseconds. |
spring.cloud.kubernetes.secrets.retry.max-attempts | Integer | 6 | Maximum number of attempts. |
spring.cloud.kubernetes.secrets.retry.max-interval | Long | 2000 | Maximum interval for backoff. |
spring.cloud.kubernetes.secrets.retry.multiplier | Double | 1.1 | Multiplier for next interval. |
PropertySource重新装载属性配置
| Name | Type | Default | Description |
|---|---|---|---|
spring.cloud.kubernetes.reload.enabled | Boolean | false | Enables monitoring of property sources and configuration reload |
spring.cloud.kubernetes.reload.monitoring-config-maps | Boolean | true | Allow monitoring changes in config maps |
spring.cloud.kubernetes.reload.monitoring-secrets | Boolean | false | Allow monitoring changes in secrets |
spring.cloud.kubernetes.reload.strategy | Enum | refresh | The strategy to use when firing a reload (refresh, restart_context, or shutdown) |
spring.cloud.kubernetes.reload.mode | Enum | event | Specifies how to listen for changes in property sources (event or polling) |
spring.cloud.kubernetes.reload.period | Duration | 15s | The period for verifying changes when using the polling strategy |