我正在尝试将 k8s 机密的实时重新加载集成到我的 Spring Boot 3 应用程序中。
我的设置如下:
我有一个 Java 21 应用程序,正在构建为包含可执行 jar 的 Docker 映像。 docker 镜像使用 Helm 部署在 k8s 集群上,并且在我的部署.yaml 中安装了一个密钥,如下所示:
- name: LIVE_RELOAD_SECRET
valueFrom:
secretKeyRef:
name: {{ .Chart.Name }}-live-secrets
key: TEST_LIVERELOAD_SECRET
当我部署时,秘密就存在(如果我执行到 Pod 中并执行
echo $LIVE_RELOAD_SECRET
,我会得到预期值)。
到目前为止一切顺利。
现在我希望能够在我的应用程序中读取这个秘密,并在运行时更改它。 我尝试了多种解决方案:
@RestController
@RefreshScope
public class SecretLogger {
private final PropertyResolver propertyResolver;
private String liveReloadSecret;
private String springCloudPropery;
@Autowired
public SecretLogger(@Value("${live-reload-secret}") String liveReloadSecret, @Value("${some.other.property}") String springCloudPropery, PropertyResolver propertyResolver) {
this.liveReloadSecret = liveReloadSecret;
this.propertyResolver = propertyResolver;
this.springCloudPropery = springCloudPropery;
}
@GetMapping("/secret")
public String liveReload() {
return "Injected value: " + liveReloadSecret + "\n" +
"PropertyResolver: " + propertyResolver.getProperty("live-reload-secret") + "\n" +
"System.getEnv: " + System.getenv("LIVE_RELOAD_SECRET") + "\n" +
"Spring cloud property: " + springCloudPropery;
}
}
我希望能够在执行器端点上调用
/refresh
并查看值的变化(通过随后调用 /secret
端点)。我还添加了 some.other.property
,一个 spring-cloud 属性作为检查(我们还使用 spring-cloud-config-server 作为 env 特定属性)。
spring-cloud-config 属性:
some.other.property=someTestValue
因此,当一切正常运行并且我调用
/secret
端点时,我首先得到以下输出:
Injected value: OYALELE
PropertyResolver: OYALELE
System.getEnv: OYALELE
Spring cloud property: someTestValue
这符合我的预期。 k8s 密钥的值为
OYALELE
,spring-cloud-config 的值也是 someTestValue
。
接下来,我更改 k8s 中密钥的值以及 spring-cloud-config 中的值,然后向我部署的应用程序上的
/refresh
端点发布帖子。
结果是 spring-cloud-config 属性的值发生了变化,但 k8s Secret 似乎是相同的。我能想到的唯一解释是你不能在java应用程序中“实时重新加载”环境变量。但我不知道这个 https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#monitoring-configmaps-and-secrets 应该如何用于秘密?
而且我什至还没有使用 configwatcher(这将是下一步)。我没有看到任何理由尝试配置观察器,因为它所做的只是在秘密更改时自动为我调用
/refresh
端点。但如果我手动执行时它不起作用,否则它可能也不起作用。
我想我只是缺少一些逻辑或构建块来在 k8s 部署的 Spring Boot 3 应用程序上实时重新加载机密,但我无法理解它们......
任何帮助将不胜感激!
在这个线程的帮助下,我设法让所有的工作都正常工作。
我将解释我的错误并链接一个示例项目,该项目使用 kubernetes 机密和配置映射作为属性,并且能够在调用 /actuator/refresh 端点后刷新它们。
我的第一个错误是尝试在 k8s 部署中使用“env”值。据我所知,Spring 无法通过上下文刷新来“更新”这些。我最终使用的是已安装的秘密。这意味着您将机密作为文件安装在容器上。要实现此功能,您需要使用'spring.config.import:“configtree:/mnt/secrets/”',告诉spring在指定的文件夹下查找属性。或者或组合使用,如果您想使用多个属性源,您也可以使用 'spring.config.import: "configtree:/mnt/secrets/,kubernetes:,optional:configserver:"' 。
如果您想使用 kubernetes discoveryClient 获取机密和 configMap,则使用“kubernetes:”部分,但您需要正确的 RBAC 权限(请参阅示例项目)。
一旦我做对了这一点,其他一切就开始工作了。我的示例项目不包括 spring-cloud-kubernetes-config-watcher 但一旦 /actuator/refresh 端点工作, spring-cloud-kubernetes-config-watcher 应该是遵循文档的直接实现。
我的完整实现还包括一个 SecretProviderClass,它从 AzureKeyVault 同步机密,因此我选择基于文件的属性,因为 SecretProviderClass 已经提供了此实现。