将 k8s 秘密实时重新加载与 spring-boot 3 和 spring-cloud-k8s-config-watcher 集成

问题描述 投票:0回答:1

我正在尝试将 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 应用程序上实时重新加载机密,但我无法理解它们......

任何帮助将不胜感激!

spring-boot spring-boot-actuator java-21
1个回答
0
投票

这个线程的帮助下,我设法让所有的工作都正常工作。

我将解释我的错误并链接一个示例项目,该项目使用 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 已经提供了此实现。

© www.soinside.com 2019 - 2024. All rights reserved.