K8s 上Spring boot环境变量配置无法生效问题

问题场景:

首先介绍一下,问题发现的场景,存在一个项目,在本地开发环境上,spring项目的数据库、redis等中间件的配置参数都是配置在application.yml 文件里的,所以修改配置直接改改文件就可以了,但是当项目部署在k8s的集群上,想要通过修改application.yml文件里的配置项,发现修改无效。

尝试解决

如图,在多次修改application.yml 文件里的连接配置之后,然后发现连接的仍然是修改的之前的配置。

application.yml的配置
在这里插入图片描述
运行时的连接
在这里插入图片描述
既然,配置无法加载,然后直接写死在Config配置类中,暴力解决
在这里插入图片描述

原因分析:

提示:这里填写问题的分析:

例如:Handler 发送消息有两种方式,分别是 Handler.obtainMessage()Handler.sendMessage(),其中 obtainMessage 方式当数据量过大时,由于 MessageQuene 大小也有限,所以当 message 处理不及时时,会造成先传的数据被覆盖,进而导致数据丢失。
虽然暴力解决了当时的问题,但是毕竟不够优雅。事后,有时间,我考虑了发现这种情况的原因,既然修改不生效,那生效的配置是从何而来,在我一顿操作之后发现,该一直生效的配置是通过K8s的deployment配置的。问题到了这里,就出现了一个新的问题,那就是为什么k8s的配置生效了,application的配置没有生效。理由很简单,就是配置优先级问题。


Spring boot 配置优先级

Spring Boot使用一个非常特殊的PropertySource顺序,该顺序旨在允许对值进行合理的重写。后来的属性源可以覆盖早期属性源中定义的值。默认顺序如下:

参考:Spring官方文档

  1. 默认属性(通过设置SpringApplication.setDefaultProperties指定)。
  2. @PropertySource在您的@Configuration类上的注释。请注意,在刷新应用程序上下文之前,不会将此类属性源添加到环境中。现在配 置某些属性(如logging.和spring.main.)已经太晚了,这些属性在刷新开始之前被读取。
  3. 配置数据(如application.properties文件)。
  4. 仅具有随机属性的RandomValuePropertySource。*。
  5. OS环境变量。
  6. Java系统属性(System.getProperties())。
  7. 来自java:comp/env的JNDI属性。
  8. ServletContext init参数。
  9. ServletConfig init参数。
  10. SPRING_APPLICATION_JSON的属性(嵌入环境变量或系统属性中的内联JSON)。
  11. 命令行参数。
  12. 测试中的属性属性。在@SpringBootTest和测试注释上可用,用于测试应用程序的特定片段。
  13. @TestPropertySource 测试上的注释。
  14. 当devtools处于活动状态时,Devtools在$HOME/.config/spring-boot目录中的全局设置属性。

解决方案:

现在问题就迎刃而解了,application.yml 等同于application.properties 文件,顺序在3,K8s配置的环境变量是OS环境变量,顺序在7,重写了application的配置。但问题没有这么简单,数据连接配置是通过@Value 读取的,@Value 中的变量名并不跟k8s中配置的并不一致。

注入的变量名:

在这里插入图片描述

k8s上的变量名:

在这里插入图片描述
通过上面的对比,两者之间存在一定的相似性,怀疑是spring对环境变量做了解析映射,本着刨根问底的心态,最后发现在SystemEnvironmentPropertySource 类发现了Spring 对系统环境变量的解析处理,源码如下:

protected final String resolvePropertyName(String name) {
   Assert.notNull(name, "Property name must not be null");
   String resolvedName = checkPropertyName(name);
   if (resolvedName != null) {
      return resolvedName;
   }
   String uppercasedName = name.toUpperCase();
   if (!name.equals(uppercasedName)) {
      resolvedName = checkPropertyName(uppercasedName);
      if (resolvedName != null) {
         return resolvedName;
      }
   }
   return name;
}

@Nullable
private String checkPropertyName(String name) {
   // Check name as-is
   if (containsKey(name)) {
      return name;
   }
   // Check name with just dots replaced
   String noDotName = name.replace('.', '_');
   if (!name.equals(noDotName) && containsKey(noDotName)) {
      return noDotName;
   }
   // Check name with just hyphens replaced
   String noHyphenName = name.replace('-', '_');
   if (!name.equals(noHyphenName) && containsKey(noHyphenName)) {
      return noHyphenName;
   }
   // Check name with dots and hyphens replaced
   String noDotNoHyphenName = noDotName.replace('-', '_');
   if (!noDotName.equals(noDotNoHyphenName) && containsKey(noDotNoHyphenName)) {
      return noDotNoHyphenName;
   }
   // Give up
   return null;
}

问题到了现在,总算是水落石出了,jdbc.postgres.url 会被解析成JDBC_POSTGRES_URL,所以可以读取到该系统变量。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
K8s部署Spring Cloud服务时,配置Nacos可以按照以下步骤进行: 1. 部署Nacos集群:根据引用\[1\]提到的Nacos集群部署的方法,使用StatefulSet部署Nacos集群,并使用NFS作为PVC数据卷,同时需要进行Mysql的主从部署。 2. 配置Spring Cloud服务的注册心:在Spring Cloud服务的配置文件指定Nacos作为注册心。可以通过配置`spring.cloud.nacos.discovery.server-addr`来指定Nacos的地址。 3. 注册服务到Nacos:在Spring Cloud服务的启动类上添加`@EnableDiscoveryClient`注解,以将服务注册到Nacos。 4. 配置服务的元数据:在Spring Cloud服务的配置文件,可以配置服务的元数据,例如服务的名称、端等信息。可以通过配置`spring.cloud.nacos.discovery.metadata`来指定元数据。 通过以上步骤,就可以在K8s成功配置Nacos作为Spring Cloud服务的注册心。请注意,以上步骤仅为一般的配置示例,具体的配置可能会因项目的不同而有所差异。 #### 引用[.reference_title] - *1* [SpringCloud Alibaba【一】Nacos集群部署配置](https://blog.csdn.net/wangleleb/article/details/128931959)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringCloud - Nacos 结合 K8s 优雅关闭服务(平滑升级)](https://blog.csdn.net/Dream_Weave/article/details/126379544)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [k8s 部署spring cloud项目](https://blog.csdn.net/ai418348851/article/details/122575057)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值