application configuration for java apps in kubernetes - java

I'm new to java and k8, and I have some doubts about how to handle application configurations for my java apps. I've got one spring boot app and the other three use wildfly.
So, they all got hardcoded application configurations, and when starting them the just use something like:
java -Dswarm.project.stage=development -jar foobar/target/foobar-swarm.jar
except for the spring boot which has an application.properties file that consists of application configuration data.
So basically the three java apps have backed in two files (which I know is a no no):
- project-stages.yml
- standalone.xml
And when the developer wants to deploy to production he uses:
java -Dswarm.project.stage=production -jar foobar/target/foobar-swarm.jar
And, now we come to kubernetes which has three ways of dealing with application configuration data:
1.) Env variables
2.) Config maps
3.) Secrets
I was thinking of using configmaps instead of env variables because they have more benefits.
So, the developer gave me the possibility of overwriting those hardcoded variables with an external file : Dsystem.properties.file=/var/foobar/environment.properties
But I'm still overwriting an hardcoded files with an external file, and I'm not happy with that solution!
So, I'm basically looking on advise can those hardcoded files be supplied externally and populated with configmaps in k8 - what would be the best practice of handling the config files in the world of k8?
Tnx,
Tom

There are several questions in the post, but I can address only the one related to spring-boot.
The simplest and the most convenient way of specifying configurations to spring boot app is via its built in profiling feature. As you already mentioned you have application.properties. You can create similar files according to your usage cases: application-production.properties, application-staging.properties, application-k8s.properties, etc.
Kubernetes deployment doesn't change this in any way.
You can control which configuration to pick by setting SPRING_PROFILES_ACTIVE env variable from the kubernetes.
You might have something like this:
docker run -e SPRING_PROFILES_ACTIVE=k8s -d -p 0.0.0.0:8080:8080 \
--name=yourapp your_image_name bash -c "java -jar yourapp.jar"
It will pick configuration from application-k8s.properties.
Configuration files support environment variables as well.
You can have placeholders like ${YOUR_DB} in your properties files and Spring will automatically pick up env variable with name YOUR_DB. It is convenient to use this feature let's say when your app pod must have its own db pod.

If I got your question right you are asking how to configure a Spring Boot application via a k8s ConfigMap. Yes, you can do that.
Create a Docker image with WORKDIR work_dir in which you start the Spring Boot application eg via java -jar /work_dir/app.jar
Create a ConfigMap
Run a container of the above mentioned image within k8s
Mount the ConfigMap for the Spring Boot application.properties into the Container as /work_dir/config/application.properties
On changes in the ConfigMap the file within the container gets updated. You have to restart the Spring Boot Application to set your changes active.

Related

Spring boot pick up dynamic application.properties from kubernetes configmap

We have springboot application running as a pod , it picks from application.properties from configmap. When we update configmap this change is not picked up springboot aplication , we need to restart the application to pick new property change.
Can we do this without restarting the sringboot application pod to pick new properties.
No, ideally you can not do it, you need to restart the POD if you are using the config map.
However, you can set the auto reloader which will do work for you, whenever configmap will get updated it will auto restart the PODs of deployment so you won't need to manually restart the PODs.
You can read more about it here Reloader : https://github.com/stakater/Reloader
Or else
you can export the variable with this command however it not permanent solution
kubectl exec -it <pod_name> export VARIABLENAME=<value>
The problem you are facing is that spring boot config doesn't know when to do a refresh of the config.
You have two options
If you want to refresh whenever the config changes use spring cloud k8s watcher link to project
2. Restart the pod whenever config changes. There are many controllers available to do

Using application.properties to set jvm arguments

I'm using spring boot 2.6.2 with docker etc. - my app reads some configuration via application.properties which looks like this:
foo.bar=hello
run.jvmArguments=-Xmx1G -XX:+ExitOnOutOfMemoryError
foo.bar definitely works as expected. But I'm not sure if it's correct to put ..
run.jvmArguments=-Xmx1G -XX:+ExitOnOutOfMemoryError
.. in there too. Does this work?
Plus - I'm using DefaultPropertiesPersister from spring to manage and change some variables in application.properties which works like a charm. But for some reason it puts some backslashes in there which results in:
run.jvmArguments=-Xmx1G -XX\:+ExitOnOutOfMemoryError
.. is this still correct? Does it work?
Thanks for any help or advice :-)
Properties from application.properties are loaded after the JVM is started and before the application context is initialized.
So there isn't any chance of them affecting the JVM.
Also there is not any real relation between application properties and environment properties for JVM. Not every spring application is a spring boot application that loads a JVM for the embedded Server. Some spring applications are deployed as wars without an embedded server, where the JVM already executes and it is the hosting server, for mutliple applications (meaning probably multiple application.properties).
Also take a look on Spring doc
SpringApplication will load properties from application.properties
files in the following locations and add them to the Spring
Environment
Also here
All configuration in Spring emanates from the Spring Environment
abstraction. The Environment is sort of like a dictionary - a map with
keys and values. Environment is just an interface through which we can
ask questions about, you know, the Environment. The abstraction lives
in Spring Framework and was introduced in Spring 3, more than a decade
ago.
Spring environment is not the same as OS or System environment that affects the JVM.

Override a remote spring cloud property with a local one

I have a spring boot application which reads properties from a remote config server via spring cloud, and it works fine with different configuration files defined in the remote repository, i'm running it with following command :
java -jar my-app.jar --spring.profiles.active=my-custom-profile
However, in some special cases i would want to be able to run the application while changing some of the remote properties (these changes are not fixed, so i can't create some custom profiles for them), so i've tried to override them directly via the command line this way :
java -jar my-app.jar --spring.profiles.active=my-custom-profile --my.first.property=value1 --my.second.property=value2
But it doesn't seem to be taken into consideration, because the application still takes the remote properties on startup.
Is there any proper way to achieve that ?
Remote properties defined by Spring Cloud Config take precedence over any other property sources. If you want to override those with local properties, you need to explicitly allow this as described in Overriding the Values of Remote Properties:
spring.cloud.config.allowOverride=true
spring.cloud.config.overrideNone=true

How to run a staging environment for App Engine Cloud Endpoints?

I have 2 app engine projects that I have created in the Developers Console. One project is my production application and the other I plan to use for staging. I am developing my application using Cloud Endpoints.
I would like to have the applicationId, WEB_CLIENT_ID, ANDROID_CLIENT_ID, etc.. all be configurable such that in the terminal I can specify a 'stage' and 'prod' flag to use different configurations and push to to each respective project.
Something like:
mvn appengine:update -env=production
and
mvn appengine:update -env=stage
To do this I figure I'll need to parameterize <application> inside appengine-web.xml and also have the Constants.java file read from a config file.
How can I have different configurations for each environment?
A different approach that you could use would be to put all your CLIENT_IDs into the #API, #APIMethod annotations. This would allow the same code to be accessed from different clients via the authentication mechanisms.

Is there a standard way to customize the deploy path in Spring Boot?

I'm exploring the possibilities of Spring Boot right now, and I'm at a slight impasse. I want to be able to run two Spring Boot applications at once, both on the same server, but at different paths (one deploys on /, the other deploys at /another-path).
Because this is an embedded Tomcat instance running within Spring Boot, there's no configuration files available for me to change.
Is there a standard way to do this? Is it possible?
Spring Boot comes with some pre-built property support. If you create an application.properties file, you can include:
server.port=<another port>
server.address=<another IP address>
server.sessionTimeout=<another timeout setting>
server.contextPath=/your-other-path
This can be in application.properties adjacent to your runnable JAR, embedded inside the JAR file, or simply applied as a -Dserver.contextPath=/your-alt-path with the java command. These are cascading, meaning you can embed one set of defaults inside the JAR, override with a local application.properties file, and then finally override application.properties with the -D options.
As it uses an embedded tomcat you should be able to add a /META-INF/context.xml to each application which specifies the path (at least this should work for a normal tomcat).
That works for our normal embedded tomcat stuff, so I would expect it to work for Spring Boot as well.

Categories

Resources