使用SpringCloud Kubernetes组件获取Config和Secret

介绍

SpringCloud Kubernetes,提供了使用 Kubernetes 本地服务的 Spring Cloud 通用接口实现。目标是促进 Spring Cloud 和运行在 Kubernetes 中的 Spring Boot 应用程序的集成。

SpringCloud Kubernetes 能在 Kubernetes 中完成服务发现和配置监听功能主要依赖 Fabric8 提供的Kubernetes Client 组件,该组件是 Kubernetes Java API 的第三方客户端,它的主要功能是远程操作 Kubernetes API 完成在 Kubernetes 环境下的一系列操作。

功能:

  • 在 Kubernetes 中实现服务发现、服务名称解析功能。
  • 在 Kubernetes 中读取 ConfigMapsSecrets 的配置,当 ConfigMap 或 Secret 更改时重新加载应用程序属性。
  • 在 Kubernetes 可去掉 Kubernetes 自带的服务负载均衡,实现与 Ribbon 结合,通过 Ribbon 完成负载均衡。

权限配置

在有k8s集群的机器上把root/.kube/目录下的config文件复制一份放到windows用户下的.kube文件夹中

Maven 配置

spring boot项目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>

k8s中的config和secret文件

test-configmap.yaml

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
namespace: default
data:
config.booleanValue: "false"
config.numberValue: "1000"
config.stringValue: "configMap中的字符串"

test-secret.yaml

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: Secret
type: Opaque
metadata:
labels:
secret: enabled
name: test-secret
namespace: default
data:
secret.username: YWRtaW4NCg== #值:admin
secret.password: MTIzNDU2 #值:123456

简单的Controller类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@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.getBooleanValue());
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;
}
}

实体类

ConfigRead.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@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;
}

}

SecretRead.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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;
}
}

项目参数配置

application.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
spring:
application:
name: k8sdemo
cloud:
kubernetes:
client:
namespace: default
discovery:
enabled: true
all-namespaces: true

server:
port: 8080

management:
server:
port: 8081
endpoints:
web:
exposure:
include: "*"
endpoint:
restart:
enabled: true

config:
numberValue: 1
stringValue: 这是在程序中的配置
booleanValue: "true"

secret:
username: application
password: 123456

Bootstrap.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
spring:
application:
name: k8sdemo
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: default #指定 Namespace 名称
name: test-config #指定 ConfigMap 名称
secrets:
enabled: true #启用 Secret 配置功能
enableApi: true #启用通过 K8S API 发现 Secret 配置,默认不开启
namespace: default #指定 Namespace 名称
name: test-secret #指定 Secret 名称,根据这个名词引入对应 Secret 配置
#labels: #指定 Label 标签名词,根据这个标签筛选 Secret,读取其中配置
# secret: enabled #自定义的 Label

创建启动类并启用服务发现注解

1
2
3
4
5
6
7
8
@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

测试接口

调用接口读取 ConfigMap 与 Secret 配置测试

/configmap 信息:

1
2
3
4
5
{
"StringValue:": "configMap中的字符串",
"NumberValue:": 1000,
"BooleanValue:": false
}

/secret 信息:

1
2
3
4
{
"username:": "admin",
"password:": "123456"
}

更新 ConfigMap 与 Secret 后调用接口测试

在 Kubernetes 中更改 ConfigMap 中的 StringValue 参数,往后面追加两个字符 AB,再 更改 Secret 中的 Username 参数的值 “admin” 往后面追加两个字符 AB 形成新的 Base64字符串值为 “YWRtaW5BQgo=” ,用这个值替换 Secret 的参数 Username 值,这时候等几秒后再次调用接口测试,查看配置是否发生变化。

/configmap 信息:

1
2
3
4
5
{
"StringValue:": "configMap中的字符串AB",
"NumberValue:": 1000,
"BooleanValue:": false
}

/secret 信息:

1
2
3
4
{
"username:": "adminAB",
"password:": "123456"
}

将 ConfigMap 与 Secret 删除后调用接口测试

将 Kubernetes 中的 ConfigMapSecret 删除后再次调用接口进行测试。

1
2
3
4
5
{
"StringValue:": "这是在程序中的配置",
"NumberValue:": 1,
"BooleanValue:": true
}

/secret 信息:

1
2
3
4
{
"username:": "application",
"password:": "123456"
}

参考链接

Kubernetes 开发 SpringCloud (二)、使用 SpringCloud Kubernetes 组件进行动态配置