Search code examples
springspring-bootspring-cloudspring-cloud-kubernetes

Refresh not working when using spring cloud starter and fabric8


I think that there is an issue when using these two dependencies in the same projet. I'm talking about spring-cloud-starter and spring-cloud-starter-kubernetes-fabric8-config.

I'm using

  • Spring Boot : 2.7.7
  • Spring Cloud : 2021.0.5

What i'm trying to build is a spring boot application on kubernetes. Each time a configmap or a sercret get changed, the app context should be updated with the new values. To achieve this, i'm using the spring cloud watcher.

https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#spring-cloud-kubernetes-configuration-watcher

For the configmap part, everything works fine but when i tried to use a secret i noticed a strange behavior. The spring watcher calls my pods on the /actuator/refresh endpoint but nothing get updated. Actually, even on my local machine, the /refresh endpoint returns 200_OK but nothing is updated. Here's the code snippet :

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
@Configuration
@ConfigurationProperties(prefix = "metadata")
@PropertySource(value = "classpath:acl-default.yaml", factory = YamlPropertySourceFactory.class)
@PropertySource(value = "file:${user.home}/acls/acl.yaml", factory = YamlPropertySourceFactory.class, ignoreResourceNotFound = true)
@Slf4j
@Getter
@Setter
public class ACLConfig implements InitializingBean {

    private List<User> users;

The ACLConfig class will load our users credentials let's say based on a file from the files system under ${user.home}/acls/acl.yaml otherwise it will get loaded from the classpath.

The content of ${user.home}/acls/acl.yaml is :

metadata:
  users:
    - name: Richard
      password: kjqsd78jkdq-local
    - name: Richard
      password: jqsd98ds78-local
    - name: Richard
      password: kSkjqf887qsd-local

bootstrap.properties

server.port=8080
spring.application.name=demo
spring.cloud.kubernetes.config.sources[0].name=${spring.application.name}
spring.cloud.kubernetes.config.sources[0].namespace=spring-cloud-watcher

application.properties

logging.level.root=INFO
logging.level.com.example.demo=DEBUG
management.endpoints.web.exposure.include=info,health,refresh
spring.config.import=optional:file:${user.home}/acls/acl.yaml

So as i said, this example does not work (the acl file update will not trigger the spring context refresh).

To make it work, you have to :

  • delete the spring-cloud-starter-kubernetes-fabric8-config dependency from pom.xml,
  • change the content of ${user.home}/acls/acl.yaml,
  • call the /actuator/refresh,
  • check the logs : you'll see that ACLConfig -> users List will be updated

You can find the example on my repo : https://github.com/mamdouni/spring-watcher-example

Delete the fabric8 dependency is not an option for me because i need to run this on kubernetes but i don't understand why it blocks the context refresh !!!

Any help will be appreciated.


Solution

  • As mentioned by @Eugene in the first comment, it was an incompatibility issue between spring boot 2 and spring cloud. It worked fine after upgrading to spring boot 3.