How to configure DNS caching timeout in a Spring Boot docker image?
Tags: docker, springboot, jvm
Published: 2024-03-26 15:30:53

_JVM build used for this article `eclipse-temurin:21-jdk`:_

```
openjdk 21.0.2 2024-01-16 LTS
OpenJDK Runtime Environment Temurin-21.0.2+13 (build 21.0.2+13-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.2+13 (build 21.0.2+13-LTS, mixed mode, sharing)
```

We must differentiate JVM Security properties and System properties.

* Security properties:
  * can **not** be affected directly by the command line
  * accessed with class `java.security.Security`
  * can be modified through the file `-Djava.security.properties=/java-additional.security`
* System properties
  * can be affected directly by the command line
  * accessed with class `java.lang.System`

Important to know:

* Default value of the property is **30** (seconds) and can be found in `sun.net.InetAddressCachePolicy#DEFAULT_POSITIVE`

* This class reads the property **once during the class initialization in the static method** - this is important for further conclusions

* How to debug: open `java.net.InetAddress` line ~1141 `cachePolicy = InetAddressCachePolicy.get();` and call the code `InetAddressCachePolicy.get()` through the debug execution

Initial options to set the value:

* Security property `networkaddress.cache.ttl` (through the file)
* System property `sun.net.inetaddr.ttl` (through JVM command line)

Technical in JVM it's **possible** to set a value in runtime (e.g. `System.setProperty` or `Security.setProperty` but this is misleading here's why:

> You don't know when a property will be accessed by any code. You must either determine that you set it **before** other code **accesses** it or there is a risk that it will be not applied.

Therefore, to mediate the risk and the checks we **should set the value as JVM startup parameters (not runtime)**.

Let's consider 3 typical build setups:

* fat jar
* Spring Boot docker build
* Goole jib

## Fat jar

There are plenty of options on how to set a JVM property, one example

### Security properties with Gradle example

```properties
# gradle.properties
org.gradle.org.gradle.jvmargs="-Djava.security.properties=/your/path/java-additional.security"
```

## Security properties with Googe Jib plugin

```
# build.gradle.kts
jib {
    extraDirectories {
        paths {
            path {
                setFrom("java-additional.security")
                into = "/etc/java-additional.security"
            }
        }
    }
    container {
        jvmFlags = listOf("-Djava.security.properties=/etc/java-additional.security/java.security")
    }
    from {
        image = "eclipse-temurin:21-jre"
    }
}
```

You can reproduce the same code with other build tools and with the Dockerfile too.

## Event this is not enough

Spring uses Apache HTTP client underneath and by default connection TTL there is infinite. You can change it to ([see](https://stackoverflow.com/questions/29107681/httpclients-poolinghttpclientconnectionmanager-and-dns-caching)):

```kotlin
@Bean
    fun poolingHttpClientConnectionManager(): PoolingHttpClientConnectionManager =
        PoolingHttpClientConnectionManagerBuilder
            .create()
            .apply {
                
                setDefaultConnectionConfig(ConnectionConfig
                    .custom()
                    .setTimeToLive(TimeValue.ofMinutes(30))
                    .build()
                )
            }
            .build()

// which you set to 

HttpClients.custom().setConnectionManager(poolingHttpClientConnectionManager)
```

## Links

* [Current Oracle JDK documentation](https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/net/doc-files/net-properties.html#address-cache-heading) 
* [StackOverflow the best answer](https://stackoverflow.com/questions/1256556/how-to-make-java-honor-the-dns-caching-timeout#comment21965197_15282042)
* [Sub-article JDK-related](https://dzone.com/articles/how-override-java-security)
* [Jib containerization tool relevant issue](https://github.com/GoogleContainerTools/jib/issues/3640)
* [Spring Boot relevant issue](https://github.com/spring-projects/spring-boot/issues/19376)