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
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?