Kubernetes autogenerated environment variables set wrong? - spring-boot

During pod startup Kubernetes is creating some environment variables based on services i created (via downward API?). Problem is that one of them, MY_APPLICATION_PORT, seems to be initialized incorrectly, it looks like:
MY_APPLICATION_PORT=tcp://192.168.0.5:7777
whereas i expect it to hold only 7777 value. The problem is that i have a Spring Boot application that has this property in application.properties:
my.application.port=7777
So when spring resolves it's properties, it prefers value from environment variable over one from .properties file, thus overwriting it with incorrect value.
My question is - do you guys know how to control creation of kubernetes env variables? I can overwrite it in my deployment.yaml, but I wonder if there's another way.
EDIT:
I've found this as a closest description of my issue I've seen online:
https://github.com/kubernetes/kubernetes/issues/65130

This environment variable comes from compatibility with a very old Docker feature. You can disable it in Kubernetes by setting enableServiceLinks: false on a Container object in a Pod spec, anywhere that may appear. For example:
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: ...
enableServiceLinks: false
env: [...]
In particular the syntax is intended to be compatible with the environment variables generated by container links in first-generation Docker networking. Since then Docker has also introduced a DNS system into its core, and in pure Docker using links at all is now considered obsolete. It should be safe to always set this Kubernetes property, especially if it causes conflicts like what you describe here.

Related

override application.yaml properties of spring boot app using k8s deployment/configmap

I have a spring boot app that has an application YAML file (src/main/resources/).
app:
props:
-
key1: value
key2: value
-
key3: value
key4: value
-
key5: value
key6: value
I want to override the entire list of props in the deployment's env section (k8s). is there any way to do it in Kubernetes?
Spring will automatically allow you to override properties via environment variables.
So if you want to change key3, then all you need to do is to create an environment variable called: APP_PROPS_1_KEY3 and you can override this value. This can be done via K8.
More here: https://stackoverflow.com/a/58186093/5563263
As per this SO, Assuming the App is deployed on Kubernetes with a Pod you can inject environment variables inside the container by either directly assigning them to the Deployment itself, or with a ConfigMap, Here in this Tutorial you have detailed info and steps about this process.
Adding the support links:
Here is the doc for :
Expose Pod Information to Containers Through Environment Variables.
Configure a Pod to Use a ConfigMap.
Spring Boot features external configuration.

Dynamically change log levels across all instances

Let's say, I have a spring boot application where I am using Log4j for logging.
In there, I want to change the log level dynamically without staring the whole application.
This can be achieved by exposing some endpoint to set the levels.
But, at production level, there might be multiple instances of the same application running across different servers.
So, how can we set the logging levels dynamically across all the container instances running the applications which are managed by kubernetes?
If your application read log levels from application.properties or application.yaml, ConfigMap would do it:
A ConfigMap is an API object used to store non-confidential data in key-value pairs. Pods can consume ConfigMaps as environment variables, command-line arguments, or as configuration files in a volume
A ConfigMap allows you to decouple environment-specific configuration from your container images, so that your applications are easily portable.
You can check my other answer where I wrote step by step with explanation how to use a ConfigMap

Do SpringBoot Configuration Trees support refresh

Do SpringBoot Configuration Trees support refresh?
I have the following. If the /mnt/secrets/ volume changes does Spring automatically refresh Beans with #ConfigurationProperties?
spring:
application:
name: "foo"
# Read Secrets
config:
import:
- configtree:/mnt/secrets/
activate:
on-cloud-platform: kubernetes
Currently if a Kubernetes configmap or secret is modified/updated, it does not redeploy the pod automatically. There needs to be a manual deployment to pick the new changes.
This is currently a feature in progress to facilicate this. https://github.com/kubernetes/kubernetes/issues/22368
So going by above, can you see if your case falls on the same lines. If so, check if below helps.
From a Kubernetes perspective, you can use Reloader to look for changes and auto redeployment.
For now, use Reloader - https://github.com/stakater/Reloader
It watches if some change happens in ConfigMap and/or Secret; then performs a rolling upgrade on relevant DeploymentConfig, Deployment, Daemonset, Statefulset and Rollout
How to use it - https://github.com/stakater/Reloader#how-to-use-reloader

how to set a Property name based on another Property in Application.yaml

I have a dynamic service name and to configure it in the application.yml I'm trying to set it up using
my_service: ${vcap.services.${service_name}.credentials.hostname}
It fails parsing the document, trying using 2 different properties
my_property: vcap.services.${service_name}.credentials.hostname
my_service: ${my_property}
In this case it can compose the property name correctly but it uses that content as a string, not resolving it.
Any idea?
You can have a property reference another property (i.e. nested), but you can't embed a property inside another property.
This works (Spring Boot 2.1 & Spring 5.1):
my.url=http://localhost:8888/service/${nestedProperty}
nestedProperty=foo/bar/baz
but as you've found this does not properly parse:
my_service: ${vcap.services.${service_name}.credentials.hostname}
I was able to get something working using a combination of property place holder and SPEL.
vcap:
services:
test-db:
credentials:
hostname: freedom
service_name: test-db
my_service: "#{'${vcap.services.${service_name}.credentials.hostname}'}"
Obviously you can leave out the vcap part, I just did that to make testing easier. Using '${..}' will cause SPEL to look up a property & it seems like that is capable of parsing an embedded property.
It's all kinda ugly though. You might want to consider using profiles to conditionally wire up different database dependencies, or use java-cfenv to obtain Cloud Foundry provided service info.
Hope that helps!

How does Spring map Docker environment variables?

So I found this sample project. In docker-compose.yml I notice that he is supplying a environment variable called REGISTRY_HOST, and that this is then used in various application.yml files in the project, here for instance.
What I am wondering is, how does this mapping work and is it Docker or Spring that performs the magic? For instance, he is binding registry.host and registry.port, but how exactly is this mapped? How come it is registry that is the prefix, and where does registry.host come from when it isn't in the compose file?
Basically what docker does is it just assigns the environment variable, nothing more. But on Spring side, it reads this variables and tries to assign to an application property. Which is explained in Externalized Configuration Please see the 24.7.2 Relaxed Binding part of the documentation.

Resources