Kubernetes 服務(wù)自動注入變量引發(fā)的血案

背景介紹

筆者最近基于kubernetes部署一套系統(tǒng)時,發(fā)現(xiàn)了一個有趣的現(xiàn)象:配置文件內(nèi)的部分變量讀取錯誤,報錯日志如下

2025-06-13T17:08:54.591570855+08:00 Caused by: org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "tcp://10.233.17.38:9200"

配置片段如下:

es:
  clusterName: es-cluster
  connectTimeout: 5000
  connectionRequestTimeout: 5000
  enableAuth: false
  host: es.demo
  maxConnectNum: 100
  maxConnectPerRoute: 100
  password: elastic
  port: 9200

明明port配置的9200,為什么取的卻是tcp://10.233.17.38:9200?

筆者開始了漫漫的探索真相之路。

ps: esjava應(yīng)用部署在同一命名空間下,且均配置了service

猜想階段

  1. 猜想配置文件未讀取到
    由于部署的是spring boot應(yīng)用,猜想可能配置的優(yōu)先級問題(畢竟spring boot可以通過多個參數(shù)配置)

論證:首先排除這種情況,因?yàn)榕渲梦募?nèi)的其他配置項(xiàng)(如數(shù)據(jù)庫連接項(xiàng))是可以正確讀取到的。

猜想失敗

  1. 猜想配置文件格式問題,導(dǎo)致的配置項(xiàng)未正確讀取到

論證:筆者將配置內(nèi)容脫敏后,使用yaml校驗(yàn)工具校驗(yàn),發(fā)現(xiàn)無誤。

猜想失敗

  1. 猜測代碼內(nèi)取值錯誤

論證:筆者將部署包反編譯后,查看配置項(xiàng)取值,發(fā)現(xiàn)無誤。

猜想失敗

求索階段

由于部署時間緊,沒有太多的時間去研究這個問題。筆者干脆通過命令行參數(shù)的形式(--es.port=9200)傳入配置項(xiàng),使其生效,問題解決。

系統(tǒng)部署交付完成后,這個問題一直困擾著筆者,想了解為什么會存在這種問題?于是筆者借助deepseek分析可能原因。deepseek給出了以下幾種可能:

  1. 配置值包含非數(shù)字字符 -> 修正配置為純數(shù)字端口
  2. 字段類型與配置類型不匹配
  3. 使用類型安全綁定(@ConfigurationProperties)
  4. 配置值被意外覆蓋 -> 檢查配置優(yōu)先級(環(huán)境變量>配置文件)
  5. 缺少 setter 方法 為配置類的每個字段添加 setter

其中第4種情況引起了筆者的注意,筆者了解到環(huán)境變量是能覆蓋配置文件內(nèi)的配置項(xiàng)的。

筆者于是進(jìn)入該應(yīng)用pod查看環(huán)境變量:

$ env|grep ES_PORT  
KUBERNETES_PORT_443_TCP=tcp://10.233.0.1:443
ES_PORT_9200_TCP_ADDR=10.233.17.38
ES_PORT=tcp://10.233.17.38:9200
KUBERNETES_PORT_443_TCP_PROTO=tcp
ES_PORT_9200_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP_ADDR=10.233.0.1
KUBERNETES_PORT=tcp://10.233.0.1:443
KUBERNETES_PORT_443_TCP_PORT=443
ES_PORT_9200_TCP_PORT=9200
ES_PORT_9200_TCP=tcp://10.233.17.38:9200

似乎我們接近了真相!

此時,筆者又有了新的疑惑:這些環(huán)境變量是誰注入進(jìn)來的?

于是再次請教deepseek,deepseek給出了 “罪魁禍?zhǔn)住?-> Kubernetes 服務(wù)自動注入變量

并給出解決方案:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  enableServiceLinks: false  # 關(guān)鍵配置!
  containers:
  - name: my-app
    image: my-image

筆者按照該樣例對問題應(yīng)用進(jìn)行配置,應(yīng)用啟動正常,可以正確讀取到配置文件內(nèi)的配置變量!筆者進(jìn)入pod查看環(huán)境變量,ES相關(guān)的環(huán)境變量全部消失了。

由此筆者得出了導(dǎo)致此次問題的原因:k8s的服務(wù)自動注入變量機(jī)制生成了”錯誤的配置環(huán)境變量值“,并被java程序取到,導(dǎo)致此次血案的發(fā)生。

進(jìn)一步思索

  1. 到底是“誰”讀取環(huán)境變量的值,覆蓋配置文件中的值?

筆者,第一時間想到的是es client,認(rèn)為是es client在初始化階段,顯示地讀取環(huán)境變量ES_PORT。于是乎翻閱了初始化es client源碼,未果。

于是又求助deepseek探求真相,deepseek給出

提問 : 為什么 Elasticsearch 配置優(yōu)先使用環(huán)境變量

↓以下是deepseek給出的回答:

1. Spring Boot 自動配置機(jī)制
當(dāng)使用 spring-boot-starter-data-elasticsearch 時,自動配置類 ElasticsearchRestClientAutoConfiguration 會讀取屬性:

Java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestHighLevelClient.class)
@EnableConfigurationProperties(ElasticsearchRestClientProperties.class) // ?? 關(guān)鍵類
public class ElasticsearchRestClientAutoConfiguration {
    // ...
}
其中的 ElasticsearchRestClientProperties 通過標(biāo)準(zhǔn) Spring 機(jī)制綁定屬性,遵守屬性優(yōu)先級規(guī)則。

2. 環(huán)境變量命名規(guī)則
Spring Boot 自動將環(huán)境變量名轉(zhuǎn)為 Spring 屬性名:

配置文件屬性:spring.elasticsearch.uris=http://localhost:9200
等效環(huán)境變量名:SPRING_ELASTICSEARCH_URIS=http://localhost:9201
如果設(shè)置了 SPRING_ELASTICSEARCH_URIS 環(huán)境變量,它會覆蓋配置文件中的值。

至此,真相水落石出。deepseek給出了解決方案:

# application.properties
spring.config.use-environment-overrides=false

PS: spring boot程序讀取配置優(yōu)先級如下(后者覆蓋前者):

  1. 默認(rèn)屬性(通過 SpringApplication.setDefaultProperties 設(shè)置)
  2. @Configuration 類上的 @PropertySource
  3. 配置文件 (application.properties 或 application.yml)
  4. 隨機(jī)屬性 (random.*)
  5. 操作系統(tǒng)環(huán)境變量
  6. Java 系統(tǒng)屬性 (System.getProperties())
  7. JNDI 屬性
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容