微服务中的配置管理在SpringCloud和K8S中有着不同的实现方式:

SpringCloudK8S
配置管理配置中心(SpringCloudConfig、Nacos等)ConfigMap、Secret

下面将基于NacosConfigMap分别介绍SpinrgCloud与K8S中配置管理的过程。

一、SpringCloud中的配置管理

(一)Nacos配置中心服务

根据Nacos官网步骤启动Nacos配置中心。

访问http://127.0.0.1:8848进入Nacos首页。

随后在配置管理页面新建一个配置,Data ID填写nacos-config.yaml,配置格式勾选YAML,配置内容编辑如下:

switch:
    fun1: false

至此,一个独立于应用的远程配置已经定义好了,该配置控制了fun1这个功能的启用状态,接下来将在客户端读取此项配置以实现流程控制。

(二)配置获取与动态刷新

pom.xml中导入nacos-config相关依赖。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    <!-- 新版本SpringCloud需要手动导入bootstrap以启动bootstrap.yml配置 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>
</dependencies>

在resources下新增bootstrap.yml配置文件。

server:
  port: 8180

spring:
  application:
    name: nacos-config
  cloud:
    nacos:
      config:
        file-extension: yaml
        server-addr: 127.0.0.1:8848

这里之所以使用bootstrap.yml而不是application.yaml,是因为bootstrap优先于application加载,其配置优先级更高,保证了远程配置中心的配置永远在本地配置文件中的配置之前生效。

该文件通过server-addr指定了nacos配置中心的地址,应用启动后,会在对应的配置中心中寻找Data IDnacos-config.yaml且配置格式为YAML的配置项(正如上述Nacos配置中心服务中配置的一样)。

SpringBoot可以使用@ValueConfigurationProperties读取配置,它们本质都是读取Environment中的值,下面将基于这两种方式分别演示Nacos配置的读取。新建入口程序如下:

@RestController
@RefreshScope
public class NacosConfigController {

    // 注入Nacos配置方式一:Value
    @Value("${switch.fun1:false}")
    private boolean fun1Switch;

    // 注入Nacos配置方式二:ConfigurationProperties
    @Autowired
    private FunSwitchProperties properties;

    @GetMapping("/value")
    public String value() {
        return dealFun1(fun1Switch);
    }

    @GetMapping("/properties")
    public String properties() {
        return dealFun1(properties.getFun1());
    }

    private String dealFun1(boolean theSwitch) {
        if (theSwitch) {
            return "do fun1";
        } else {
            return "do nothing";
        }
    }

    @ConfigurationProperties(prefix = "switch")
    @Component
    public static class FunSwitchProperties {
        private boolean fun1;

        public boolean getFun1() {
            return fun1;
        }

        public void setFun1(boolean fun1) {
            this.fun1 = fun1;
        }
    }
}
@SpringBootApplication
public class NacosConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(NacosConfigApplication.class, args);
    }

}

上述代码详见github

启动应用,访问服务:

curl -X GET 'http://127.0.0.1:8180/value'
curl -X GET 'http://127.0.0.1:8180/properties'

它们的响应结果都是:

do nothing

这符合预期,因为现在switch.fun1的本地默认值和Nacos配置的值都是false,下面,在Nacos页面修改对应的配置:

switch:
    fun1: true

此时应用控制台打印如下日志,说明配置刷新成功。

Located property source: [BootstrapPropertySource {name='bootstrapProperties-nacos-config.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-nacos-config,DEFAULT_GROUP'}]

再次访问服务:

curl -X GET 'http://127.0.0.1:8180/value'
curl -X GET 'http://127.0.0.1:8180/properties'

它们的响应结果变成了:

do fun1

可以看到,配置获取与动态刷新都正常运行了。

二、K8S中的配置管理

K8S的配置管理主要由ConfigMapSecret组成,其中,ConfigMap用于保存非机密性数据,Secret则用于保存敏感数据。它们的使用方法很类似,下面以ConfigMap为例介绍K8S的配置管理。

(一)创建ConfigMap

创建并执行configmap.yml文件:

apiVersion: v1
kind: ConfigMap
metadata:
  name: configmap-demo
data:
  key: "value"
kubectl apply -f configmap.yml

查看创建成功的ConfigMap:

kubectl get cm 
kubectl describe cm configmap-demo
Name:         configmap-demo
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
key:
----
value

BinaryData
====

Events:  <none>

可以看到,该ConfigMap中存在了一个key-value配置,下面将在pod中使用它。

(二)使用ConfigMap实现配置获取与动态刷新

创建并执行pod.yml文件:

apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
    - name: demo
      image: alpine
      command: ["sleep", "3600"]
      # env方式获取configmap
      env:
        - name: KEY
          valueFrom:
            configMapKeyRef:
              name: configmap-demo
              key: key
      # volumeMounts方式获取configmap
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
  - name: config
    configMap:
      name: configmap-demo
kubectl apply -f pod.yml

查看Pod中的环境变量与挂载文件的值:

kubectl exec configmap-demo-pod -- env
kubectl exec configmap-demo-pod -- cat /config/key

它们key的值都是value,说明配置的获取正常运行了。

随后,修改ConfigMap中的值:

kubectl edit cm configmap-demo

value修改为newvalue,随后等待片刻,挂载的ConfigMap将会被自动更新。再次查看Pod中挂载文件的值:

kubectl exec configmap-demo-pod -- cat /config/key

可以发现,key的值已经变成了newvalue,说明配置的动态刷新也正常运行了(需要注意的是,环境变量不会动态刷新)。

三、总结

SpringCloud通过SpringCloudConfig、Nacos等配置中心实现配置获取与动态刷新。

K8S通过ConfigMap与Secret对象实现配置获取与动态刷新。

与SpringCloud与K8S中的服务调用中类似:SpringCloud偏向于开发,而K8S则更偏向于运维。有关技术选型,需视情况而定。

参考文档

  1. 《深入理解SpringCloud与实战 方剑 著》
  2. SpringCloud官方网站
  3. 黑马程序员SpringCloud微服务技术栈教程
  4. K8S官方网站