一、介绍
组件简介
SpringCloud 一般都是用 SpringBoot 来做脚手架,而 SpringBoot 的配置一般都在 resources 目录中的 application.yaml
、bootstrap.yaml
文件中。并且 SpringCloud 在本地开发模式中用的是组件 SpringCloud Config 配置中心来对配置文件进行统一管理、动态更新等,不过在我们开发环境中在这种模式下将配置文件存入 SVN 或者 Git,当网络不稳定发生波动时候,服务无法与这些仓库建立连接而导致不可用。
由于 Kubernetes 本身存在 ConfigMap
与 Secret
对象来存储配置,所以在 Kubernetes 部署 SpringCloud 的应用尝试不再采用统一配置中心管理配置,而是将配置文件存入 Kubernetes 的 ConfigMap 与 Secret 资源中,经过尝试这种做法确实可行。不过用这种方法还面临一个问题是直接存入 ConfigMap 或者 Secret 中如果配置发生变化,程序是无法感知到变化从而不会进行自动重启或刷新配置。
由于上面问题,SpringCloud Kubernetes 提供了 spring-cloud-starter-kubernetes-config
组件来解决在 Kubernetes 环境中使用 ConfigMap 或 Secret 动态配置发现与更新问题,当存在 ConfigMap 中的配置或者存在 Secret 中的密码发生更改时候,在 Kubernetes 中的服务能及时监控到这一变化从而按照配置的配置更新策略进行动态更新或者服务重启。
功能简介
SpringCloud Kubernetes Config 组件主要提供以下几种功能:
- 实时监控 ConfigMap、Secret 配置变化从而更新服务配置。
- 定时轮询加载 ConfigMap、Secret 配置从而更新服务配置。
二、SpringCloud Kubernetes 动态配置示例
这里写一个使用 spring-cloud-starter-kubernetes-config 组件动态引用 Kubernetes 中的 Config 与 Secret 配置的示例。
注意:示例是在本地启动,通过 Kubectl 的配置文件 config 连接 Kubernetes 获取 ConfigMap、Secret 而并非 Kubernetes 中。如果需要将项目推送到 Kubernetes 中进行测试,需要提前创建好一个能读取 Config 与 Secret 的 ServiceAccount 账户供项目使用,防止因为没有权限而导致无法获取 Kubernetes 中的配置信息。
1、Kubernetes 中部署 ConfigMap、Secret
提前创建 ConfigMap
与 Secret
两个配置文件,并操作 kubectl
工具将两个对象部署到 Kubernetes 集群方便测试。
test-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
data:
config.booleanValue: "false"
config.numberValue: "1000"
config.stringValue: "configMap中的字符串"
test-secret.yaml
apiVersion: v1
kind: Secret
type: Opaque
metadata:
labels:
secret: enabled
name: test-secret
data:
secret.username: YWRtaW4NCg== #值:admin
secret.password: MTIzNDU2 #值:123456
将两个对象部署到 Kubernetes
- -n :创建资源到指定的 Namespace
$ kubectl apply -f test-configmap.yaml -n mydlqcloud
$ kubectl apply -f test-secret.yaml -n mydlqcloud
2、创建 SpringCloud Config 示例项目
这里用 SpringCloud Kubernetes 中的服务发现组件 spring-cloud-starter-kubernetes-config
来演示获取 Kubernetes 环境中的 Config
和 Secret
示例。
(1)、Maven 引入相关变量
在"pom.xml"文件中引入 SpringBoot 与 SpringCloud Kubernetes Config 相关 Jar。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>
<groupId>club.mydlq</groupId>
<artifactId>springcloud-kubernetes-config-demo</artifactId>
<version>0.0.1</version>
<name>springcloud-kubernetes-config-demo</name>
<description>springcloud kubernetes config demo</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--SpringBoot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--SpringBoot Actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!--SpringCloud Kubernetes Config-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-config</artifactId>
<version>1.0.2.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(2)、配置 Bootstrap.yml 文件
创建 bootstrap.yml
文件并设置 flush
、config
与 secret
的相关配置参数。
spring:
application:
name: springcloud-kubernetes-config-demo
cloud:
kubernetes:
reload:
enabled: true
mode: polling #监听模式:
# (1)、polling:从 ConfigMap 和 Secret 中定期刷新配置,检测是否进行了修改。
# (2)、event(默认):监视配置映射或机密的更改。任何事件都会对配置进行重新检查,如果发生更改,则会重新加载。
period: 5000 #刷新间隔,单位(ms)
strategy: shutdown #刷新模式:
# (1)、refresh(默认):仅注释@ConfigurationProperties或@RefreshScope重新加载的配置Bean
# (2)、restart_context:整个Spring ApplicationContext正常重启。使用新配置重新创建Bean。
# (3)、shutdown:关闭以激活容器的重启。使用此级别时,请确保将所有非守护程序线程的生命周期绑定到该级别,
# 并将ApplicationContext 复制控制器或副本集配置为重新启动该pod。
monitoring-secrets: true #是否监控 Secret 的更改来执行更新
config:
enabled: true #启用 ConfigMap 配置功能
enableApi: true #启用通过 K8S API 发现 ConfigMap 配置
sources:
- namespace: mydlqcloud #指定 ConfigMap 名称
name: test-config #指定 Namespace 名称
secrets:
enabled: true #启用 Secret 配置功能
enableApi: true #启用通过 K8S API 发现 Secret 配置,默认不开启
namespace: mydlqcloud #指定 Namespace 名称
name: test-secret #指定 Secret 名称,根据这个名词引入对应 Secret 配置
#labels: #指定 Label 标签名词,根据这个标签筛选 Secret,读取其中配置
# secret: enabled #自定义的 Label
(3)、配置 application 文件
自定义本地配置,变量名保持和 ConfigMap
与 Secret
中的一致,并且值要设置的不同,这样方便测试时候区分获取的变量是从本地获取的还是从 Kubernetes 中的 ConfigMap
与 Secret
中获取的。
服务动态配置需要设置"management.endpoint.restart.enabled=true"这个参数,否则启动会报错。
management: #Actuator 配置
server:
port: 8081
endpoints:
web:
exposure:
include: "*"
endpoint:
restart:
enabled: true
config: #自定义程序中的 ConfigMap 参数配置
numberValue: 1
stringValue: 这是在程序中的配置
booleanValue: "true"
secret: #自定义程序中的 Secret 参数配置
username: application
password: 123456
(4)、设置 ConfigRead 类读取自定义配置
设置 ConfigRead 类用于测试读取 Kubernetes 中 ConfigMap 中的配置。
ConfigRead.java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "config")
public class ConfigRead {
private String stringValue;
private Integer numberValue;
private boolean booleanValue;
public String getStringValue() {
return stringValue;
}
public void setStringValue(String stringValue) {
this.stringValue = stringValue;
}
public Integer getNumberValue() {
return numberValue;
}
public void setNumberValue(Integer numberValue) {
this.numberValue = numberValue;
}
public boolean isBooleanValue() {
return booleanValue;
}
public void setBooleanValue(boolean booleanValue) {
this.booleanValue = booleanValue;
}
}
(5)、设置 SecretRead 类读取自定义配置
设置 SecretRead 类用于测试读取 Kubernetes 中 Secret 中的配置。
SecretRead.java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "secret")
public class SecretRead {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
(6)、创建 Controller 类显示自定义配置信息
创建 ConfigController 类中写两个接口,分别用于测试调用 ConfigMap
和 Secret
。
import club.mydlq.admin.configMap.ConfigRead;
import club.mydlq.admin.secret.SecretRead;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class ConfigController {
@Autowired
private ConfigRead configRead;
@Autowired
private SecretRead secretRead;
@GetMapping("/configmap")
public Map<String,Object> getConfig() {
Map<String,Object> map = new HashMap<>();
map.put("StringValue:",configRead.getStringValue());
map.put("NumberValue:",configRead.getNumberValue());
map.put("BooleanValue:",configRead.isBooleanValue());
return map;
}
@GetMapping("/secret")
public Map<String,Object> getSecret() {
Map<String,Object> map = new HashMap<>();
map.put("username:",secretRead.getUsername());
map.put("password:",secretRead.getPassword());
return map;
}
}
(7)、创建启动类并启用服务发现注解
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3、调用接口测试
上面定义了两个接口分别为:
- 服务发现列表接口:/configmap
- 服务实例信息接口:/secret
然后进行测试,首先测试直接调用接口查看是否能获取 Kubernetes 中 ConfigMap
、Secret
中的参数信息。之后更改 Kubernetes 中 ConfigMap、Secret 参数的值后等待一段时间再次调用接口测试,检测新获取的参数信息中的值是否发生变化。最后将 Kubernetes 中的 ConfigMap
、Secret
删除,查看是否能获取程序内部设定的默认的参数。
下面按上面的步骤进行测试:
调用接口读取 ConfigMap 与 Secret 配置测试
/configmap 信息:
{
"StringValue:": "configMap中的字符串",
"NumberValue:": 1000,
"BooleanValue:": false
}
/secret 信息:
{
"username:": "admin",
"password:": "123456"
}
更新 ConfigMap 与 Secret 后调用接口测试
在 Kubernetes 中更改 ConfigMap 中的 StringValue
参数,往后面追加两个字符 AB
,再
更改 Secret 中的 Username
参数的值 “admin” 往后面追加两个字符 AB
形成新的 Base64字符串值为 “YWRtaW5BQgo=” ,用这个值替换 Secret 的参数 Username
值,这时候等几秒后再次调用接口测试,查看配置是否发生变化。
/configmap 信息:
{
"StringValue:": "configMap中的字符串AB",
"NumberValue:": 1000,
"BooleanValue:": false
}
/secret 信息:
{
"username:": "adminAB",
"password:": "123456"
}
本人这里调用接口获取的信息跟之前的已经发生变化。
将 ConfigMap 与 Secret 删除后调用接口测试
将 Kubernetes 中的 ConfigMap
、Secret
删除后再次调用接口进行测试。
{
"StringValue:": "这是在程序中的配置",
"NumberValue:": 1,
"BooleanValue:": true
}
/secret 信息:
{
"username:": "application",
"password:": "123456"
}
可以看到配置已经变成程序中设定的配置,由此可以推测出使用 SpringCloud Kubernetes Config
可以获取 Kubernetes 中 ConfigMap
与 Secret
的配置。如果配置发生更改,程序能够及时检测到并更新程序中的配置。如果不能获取 Kubernetes 中的配置信息,则直接使用程序中配置的默认信息。
三、可配置的参数列表
SpringCloud kubernetes Config 中可以设置 ConfigMap 与 Secret 动态配置参数,如下:
ConfigMap 可配置参数
读取 ConfigMap 的配置
参数名称 | 类型 | 默认值 | 参数描述 |
spring.cloud.kubernetes.config.enabled | Boolean | true | 是否启动 Config 动态配置 |
String | 设置要查找的 ConfigMap 的名称 | ||
spring.cloud.kubernetes.config.namespace | String | Client名称空间 | 设置在哪个 Kubernetes Namespace 查找 ConfigMap 资源 |
spring.cloud.kubernetes.config.paths | List | null | 设置ConfigMap装入实例的路径 |
spring.cloud.kubernetes.config.enableApi | Boolean | true | ConfigMap通过API 启用或禁用使用实例 |
Secret 可配置参数
读取 Secret 的配置
参数名称 | 类型 | 默认值 | 参数描述 |
spring.cloud.kubernetes.secrets.enabled | Boolean | true | 是否启动 Secret 动态配置 |
String | 设置要查找的 Secret 的名称 | ||
spring.cloud.kubernetes.secrets.namespace | String | Client名称空间 | 设置在哪个 Kubernetes Namespace 查找 Secret 资源 |
spring.cloud.kubernetes.secrets.labels | Map | null | 设置用于查找 Secret 的标签 |
spring.cloud.kubernetes.secrets.paths | List | null | 设置安装 Secret 的路径 |
spring.cloud.kubernetes.secrets.enableApi | Boolean | false | 启用或禁用通过 API 监听 Secret |
Reload 可配置参数
配置动态更新配置
参数名称 | 类型 | 默认值 | 参数描述 |
spring.cloud.kubernetes.reload.enabled | Boolean | false | 启动动态配置监控 |
spring.cloud.kubernetes.reload.monitoring-config-maps | Boolean | true | 允许监视 ConfigMap 中的更改 |
spring.cloud.kubernetes.reload.monitoring-secrets | Boolean | false | 允许监控 Secret 的变化 |
spring.cloud.kubernetes.reload.strategy | Enum | refresh | 配置更新策略: - refresh(更新) - restart_context(重启Spring容器) - shutdown(杀死应用使Kubernetes对其重启)) |
spring.cloud.kubernetes.reload.mode | Enum | event | 指定监听策略: - event:配置发生变化就执行更新 - polling:定时检测配置变化从而更新配置 |
spring.cloud.kubernetes.reload.period | Duration | 15s | 使用 polling 策略时检测间隔时间 |