springspring-bootkubernetesconfigmapspring-cloud-kubernetes

Spring cloud Kubernetes doesn't load ConfigMap


Help me please with a problem. My spring app doesn't load properties from Kubernetes config map.

My spring code:

MyConfig.class

@Configuration
@ConfigurationProperties(prefix = "my")
@Getter
@Setter
public class MyConfig {
    private String property;
}

CommonAPI.class

@RestController
@Slf4j
public class CommonAPI {

    @Autowired
    MyConfig myConfig;

    int random = new Random().nextInt();

    @PostConstruct
    void init() {
        log.info("random = {}", random);
        log.info("myProperty = {}", myConfig.getProperty());
    }

    @GetMapping("property")
    public String getMyProperty() {
        return myConfig.getProperty();
    }

    @GetMapping("random")
    public int getRandom() {
        return random;
    }
}

ClientApplication.class

@SpringBootApplication
public class ClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
}

application.yaml

spring:
  application:
    name: client
  cloud:
    bootstrap:
      enabled: true
    kubernetes:
      config:
        enabled: true
        namespace: spring-app
        name: client
        sources:
          - name: client
logging:
  level:
    org.springframework.cloud: TRACE

pom.xml

...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
...
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.0</spring-cloud.version>
    </properties>
...
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-fabric8-all</artifactId>
        </dependency>
...

My Kubernetes configs:

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: client-deployment
  namespace: spring-app
spec:
  selector:
    matchLabels:
      app: client
  replicas: 1
  template:
    metadata:
      labels:
        app: client
    spec:
      containers:
        - name: client
          image: client:1.0.8
          imagePullPolicy: Never
          resources:
            requests:
              memory: "512Mi"
              cpu: "100m"
            limits:
              memory: "1Gi"
              cpu: "600m"
          ports:
            - containerPort: 8080

cluster-role.yaml

kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: spring-app
  name: service-reader
rules:
  - apiGroups: [""]
    resources: ["*"]
    verbs: ["*"]

cluster-role-binding.yaml

kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: service-reader-pod
subjects:
  - kind: ServiceAccount
    name: default
    namespace: spring-app
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: service-reader

and config-map.yaml

kind: ConfigMap
apiVersion: v1
metadata:
  name: client
data:
  application.yaml: |-
    my:
      property: hello

And my.property isn't loaded from config map by my app. Here is log:

...
2024-03-16T17:20:29.072Z  INFO 1 --- [client] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8080 (http)
2024-03-16T17:20:29.261Z  INFO 1 --- [client] [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2024-03-16T17:20:29.262Z  INFO 1 --- [client] [           main] o.apache.catalina.core.StandardEngine    : Starting Servlet engine: [Apache Tomcat/10.1.19]
2024-03-16T17:20:30.174Z  INFO 1 --- [client] [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2024-03-16T17:20:30.181Z  INFO 1 --- [client] [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 35798 ms
2024-03-16T17:20:33.353Z  INFO 1 --- [client] [           main] ru.itanton.client.api.CommonAPI          : random = 1249102570
2024-03-16T17:20:33.357Z  INFO 1 --- [client] [           main] ru.itanton.client.api.CommonAPI          : myProperty = null
2024-03-16T17:20:45.783Z DEBUG 1 --- [client] [           main] o.s.c.k.c.KubernetesNamespaceProvider    : Looking for service account namespace at: [/var/run/secrets/kubernetes.io/serviceaccount/namespace].
2024-03-16T17:20:45.784Z DEBUG 1 --- [client] [           main] o.s.c.k.c.KubernetesNamespaceProvider    : Found service account namespace at: [/var/run/secrets/kubernetes.io/serviceaccount/namespace].
2024-03-16T17:20:45.785Z DEBUG 1 --- [client] [           main] o.s.c.k.c.KubernetesNamespaceProvider    : Service account namespace value: /var/run/secrets/kubernetes.io/serviceaccount/namespace
2024-03-16T17:20:46.059Z TRACE 1 --- [client] [           main] o.s.cloud.commons.util.InetUtils         : Testing interface: eth0
2024-03-16T17:20:46.059Z TRACE 1 --- [client] [           main] o.s.cloud.commons.util.InetUtils         : Found non-loopback interface: eth0
2024-03-16T17:20:46.064Z TRACE 1 --- [client] [           main] o.s.cloud.commons.util.InetUtils         : Testing interface: lo
2024-03-16T17:20:46.150Z DEBUG 1 --- [client] [           main] bernetesDiscoveryClientAutoConfiguration : Will publish InstanceRegisteredEvent from blocking implementation
2024-03-16T17:20:46.155Z DEBUG 1 --- [client] [           main] iscoveryClientHealthIndicatorInitializer : publishing InstanceRegisteredEvent
2024-03-16T17:20:56.480Z DEBUG 1 --- [client] [           main] s.c.c.d.h.DiscoveryClientHealthIndicator : Discovery Client has been initialized
2024-03-16T17:20:56.980Z DEBUG 1 --- [client] [           main] o.s.c.c.SpringBootVersionVerifier        : Version found in Boot manifest [3.2.3]
2024-03-16T17:20:56.983Z DEBUG 1 --- [client] [           main] o.s.c.c.CompositeCompatibilityVerifier   : All conditions are passing
2024-03-16T17:20:57.360Z DEBUG 1 --- [client] [           main] o.s.c.k.f.d.KubernetesCatalogWatch       : stateGenerator is of type: Fabric8EndpointsCatalogWatch
2024-03-16T17:20:57.572Z  WARN 1 --- [client] [           main] iguration$LoadBalancerCaffeineWarnLogger : Spring Cloud LoadBalancer is currently working with the default cache. While this cache implementation is useful for development and tests, it's recommended to use Caffeine cache in production.You can switch to using Caffeine cache, by adding it and org.springframework.cache.caffeine.CaffeineCacheManager to the classpath.
2024-03-16T17:20:58.165Z  INFO 1 --- [client] [           main] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 1 endpoint(s) beneath base path '/actuator'
2024-03-16T17:20:59.266Z  INFO 1 --- [client] [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port 8080 (http) with context path ''
2024-03-16T17:20:59.274Z TRACE 1 --- [client] [           main] o.s.cloud.commons.util.InetUtils         : Testing interface: eth0
2024-03-16T17:20:59.277Z TRACE 1 --- [client] [           main] o.s.cloud.commons.util.InetUtils         : Found non-loopback interface: eth0
2024-03-16T17:20:59.277Z TRACE 1 --- [client] [           main] o.s.cloud.commons.util.InetUtils         : Testing interface: lo
2024-03-16T17:20:59.693Z  INFO 1 --- [client] [           main] ru.itanton.client.ClientApplication      : Started ClientApplication in 80.495 seconds (process running for 85.784)

As you can see in the log, myProperty is null


Solution

  • Fixed by adding the following dependency:

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>
    

    Check here for more information: How do I load properties from a Kubernetes configmap into my Spring Boot application using Spring Cloud?