Spring Cloud Kubernetes-ConfigMap配置中心

1,224 阅读4分钟

序言

之前介绍过Kubernetes可以将ConfigMap或Secret作为卷挂载到应用程序容器中,当配置项发生变化时,也能实时更新挂载的卷。但是Spring Boot不会自动更新这些变更,除非重启应用。

当然Spring Cloud也提供了在不重启应用的情况下刷新应用程序上下文的能力,通过访问/refresh端点或者使用Spring Cloud Bus发布RefreshRemoteApplicationEvent。

本篇介绍Spring Cloud Kubernetes提供的直接读取ConfigMap或Secret,并自动刷新变更的方案。

源码:github.com/tzjavadmg/s…

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编码被转化成正常字符后打印出来了: image.png

修改配置,重试次数改成333

kubectl edit configmap/config-reload

再看日志,马上打印新配置了。 image.png

附配置表

ConfigMap PropertySource属性配置

NameTypeDefaultDescription
spring.cloud.kubernetes.config.enabledBooleantrueEnable ConfigMaps PropertySource
spring.cloud.kubernetes.config.nameString${spring.application.name}Sets the name of ConfigMap to look up
spring.cloud.kubernetes.config.namespaceStringClient namespaceSets the Kubernetes namespace where to lookup
spring.cloud.kubernetes.config.pathsListnullSets the paths where ConfigMap instances are mounted
spring.cloud.kubernetes.config.enableApiBooleantrueEnable or disable consuming ConfigMap instances through APIs
spring.cloud.kubernetes.config.fail-fastBooleanfalseEnable or disable failing the application start-up when an error occurred while loading a ConfigMap
spring.cloud.kubernetes.config.retry.enabledBooleantrueEnable or disable config retry.
spring.cloud.kubernetes.config.retry.initial-intervalLong1000Initial retry interval in milliseconds.
spring.cloud.kubernetes.config.retry.max-attemptsInteger6Maximum number of attempts.
spring.cloud.kubernetes.config.retry.max-intervalLong2000Maximum interval for backoff.
spring.cloud.kubernetes.config.retry.multiplierDouble1.1Multiplier for next interval.

Secrets PropertySource属性配置

NameTypeDefaultDescription
spring.cloud.kubernetes.secrets.enabledBooleantrueEnable Secrets PropertySource
spring.cloud.kubernetes.secrets.nameString${spring.application.name}Sets the name of the secret to look up
spring.cloud.kubernetes.secrets.namespaceStringClient namespaceSets the Kubernetes namespace where to look up
spring.cloud.kubernetes.secrets.labelsMapnullSets the labels used to lookup secrets
spring.cloud.kubernetes.secrets.pathsListnullSets the paths where secrets are mounted (example 1)
spring.cloud.kubernetes.secrets.enableApiBooleanfalseEnables or disables consuming secrets through APIs (examples 2 and 3)
spring.cloud.kubernetes.secrets.fail-fastBooleanfalseEnable or disable failing the application start-up when an error occurred while loading a Secret
spring.cloud.kubernetes.secrets.retry.enabledBooleantrueEnable or disable secrets retry.
spring.cloud.kubernetes.secrets.retry.initial-intervalLong1000Initial retry interval in milliseconds.
spring.cloud.kubernetes.secrets.retry.max-attemptsInteger6Maximum number of attempts.
spring.cloud.kubernetes.secrets.retry.max-intervalLong2000Maximum interval for backoff.
spring.cloud.kubernetes.secrets.retry.multiplierDouble1.1Multiplier for next interval.

PropertySource重新装载属性配置

NameTypeDefaultDescription
spring.cloud.kubernetes.reload.enabledBooleanfalseEnables monitoring of property sources and configuration reload
spring.cloud.kubernetes.reload.monitoring-config-mapsBooleantrueAllow monitoring changes in config maps
spring.cloud.kubernetes.reload.monitoring-secretsBooleanfalseAllow monitoring changes in secrets
spring.cloud.kubernetes.reload.strategyEnumrefreshThe strategy to use when firing a reload (refreshrestart_context, or shutdown)
spring.cloud.kubernetes.reload.modeEnumeventSpecifies how to listen for changes in property sources (event or polling)
spring.cloud.kubernetes.reload.periodDuration15sThe period for verifying changes when using the polling strategy