Reputation: 392
I have this @ConfigurationProperties:
@ConfigurationProperties(prefix = "myapp")
public class CustomProperties {
private Map<String, String> namespace = new HashMap<>();
public Map<String, String> getNamespace() {
return namespace;
}
}
Before I start the application, I put these arguments as a program arguments:
--myapp.namespace.namespace1.connection="xxxx"
--myapp.namespace.namespace1.url="yyy"
--myapp.namespace.namespace2.topic="zzz"
--myapp.namespace.namespace2.id="ccc"
And it works successfully, the namespace map will contain four entries:
{namespace2.id=ccc, namespace1.connection=xxxx, namespace2.topic=zzz, namespace1.url=yyy}
Now I am "dockerizing" the application. How can I make it work with environment variables? I tried:
MYAPP_NAMESPACE_NAMESPACE1.CONNECTION="xxxx"
MYAPP_NAMESPACE_NAMESPACE1.URL="yyy"
MYAPP_NAMESPACE_NAMESPACE2.TOPIC="zzz"
MYAPP_NAMESPACE_NAMESPACE2.ID="ccc"
and
MYAPP_NAMESPACE_NAMESPACE1_CONNECTION="xxxx"
MYAPP_NAMESPACE_NAMESPACE1_URL="yyy"
MYAPP_NAMESPACE_NAMESPACE2_TOPIC="zzz"
MYAPP_NAMESPACE_NAMESPACE2_ID="ccc"
And it doesn't work. Can you help me?
Thanks Fernando.
Upvotes: 5
Views: 7988
Reputation: 4991
Just in case it helps someone else using Kubernetes, there is a simpler way, than environment variables, to inject complex config into spring boot applications. We can have a config map entry named application.yml
with the required config, inject the entry into the container through a volume and set the environment variable SPRING_CONFIG_ADDITIONAL_LOCATION
to point to that location
Steps:
demo-config
which contains a multi-line data with the key application.yml
config-volume
from config map demo-config mapping only the data key application.yml
/etc/config
SPRING_CONFIG_ADDITIONAL_LOCATION
to /etc/config/
- the trailing slash is required/etc/config/application.yml
and logs the line com.example.demo.AppProps - Namespace: {namespace2.id=ccc, namespace1.connection=xxxx, namespace2.topic=zzz, namespace1.url=yyy}
Test Configuration class:
package com.example.demo;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Getter
@Setter
@Component
@ConfigurationProperties(prefix = "myapp")
public class AppProps {
private Map<String, String> namespace = new HashMap<>();
@PostConstruct
public void init() {
log.info("Namespace: {}", namespace);
}
}
Config map:
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-config
data:
application.yml: |
myapp:
namespace:
namespace1.connection: xxxx
namespace1.url: yyy
namespace2.topic: zzz
namespace2.id: ccc
Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
labels:
app: demo
spec:
replicas: 1
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
volumes:
- name: config-volume
configMap:
name: demo-config
items:
- key: application.yml
path: application.yml
containers:
- name: app
image: devatherock/demo:0.1.0-local.1
imagePullPolicy: Never
ports:
- containerPort: 8080
volumeMounts:
- name: config-volume
mountPath: /etc/config
env:
- name: SPRING_CONFIG_ADDITIONAL_LOCATION
value: "/etc/config/"
Upvotes: 4
Reputation: 524
You can map these properties to the environment variables in spring profile i.e. application or bootstrap properties (like in application.properties/yml or bootstrap.properties/yml file) by using the placeholders. You can map to the environment variable placeholders as below. These will resolve to the corresponding environment variable.
myapp.namespace.namespace1.connection=${MYAPP_NAMESPACE_NAMESPACE1_CONNECTION}
myapp.namespace.namespace1.url=${MYAPP_NAMESPACE_NAMESPACE1_CONNECTION}
myapp.namespace.namespace2.topic=${MYAPP_NAMESPACE_NAMESPACE1_CONNECTION}
myapp.namespace.namespace2.id=${MYAPP_NAMESPACE_NAMESPACE2_ID}
If you know know the properties name in advance and know only the prefix:
You only need to map with one placeholder and provide environmental variables by appending that placeholder and with underscores like:
myapp.namespace=${MYAPP_NAMESPACE}
If you provide env variable,
MYAPP_NAMESPACE_NAMESPACE1_CONNECTION=xxx
Springboot is smart enough to resolve this to
myapp.namespace.namespace1.connection==xxx
You just have to follow the convention to use underscores (_) only which will be resolved to dots (.).
We are using it in our application. I also tested this particular scenario and when it prints the namespaces as below:
{namespace1.connection=xxxx}
I hope I understood correctly what you want to achieve here.
Upvotes: 1
Reputation: 455
I think you can initialize it just by doing @Value("${MYAPP_NAMESPACE_NAMESPACE1_CONNECTION}") or whatever the key in your env var is
Then give it the variable you want it in like so
@Value("${variable}")
private String variable;
Upvotes: -1