Spring configuration server timeout in docker - spring

I have 6 spring boot projects:
rabbitmq
configserver
discrovery
apigateway (zuul)
users-ms
business-ms
When I run these applications natively on my computer everything works fine. I need to dockerize these apps to form microservice architecture.
I adopted the properties files for a profile, called "dockertest".
I start containers in the following order (without docker compose):
docker run -d --network test-net --hostname rabbitmq-service --name rabbitmq-service -p 4369:4369 -p 5671:5671 -p 5672:5672 -p 15671:15671 -p 15672:15672 -p 25672:25672 rabbitmq-service
docker run -d --network test-net --hostname configserver --name configserver -p 8888:8888 -e "SPRING_PROFILES_ACTIVE=dockertest" configserver
docker run -d --network test-net --hostname discrovery --name discrovery -p 8710:8710 -e "SPRING_PROFILES_ACTIVE=dockertest" discrovery
docker run -d --network test-net --hostname apigateway --name apigateway -p 8770:8770 -e "SPRING_PROFILES_ACTIVE=dockertest" apigateway
docker run -d --network test-net --hostname users-ms --name users-ms -P -e "SPRING_PROFILES_ACTIVE=dockertest" users-ms
...and the problem starts here.
discrovery service is not depend on config server, so it starts fine.
apigateway is depend on configserver, but everything is ok, gets configs and starts fine.
user-ms is also depend on configserver, but the connection hangs out and after a long time throws read timeout exception and exits.
user-ms sees configserver (i think), because if I set wrong configserver params voluntarily the service immediately exits (fail-fast=true).
Do you have any idea how can I solve this problem?
---- Update ----
I paste here the relevant configuration and Dockerfiles:
Every services depend on configserver have these configuration to reach configserver:
spring.config.import=configserver:
spring.cloud.config.uri=http://configserver:8888
spring.cloud.config.username=...
spring.cloud.config.password=...
spring.cloud.config.fail-fast=true
configserver
FROM openjdk:13-alpine
ADD /target/configserver-service-0.0.1-SNAPSHOT.jar app.jar
ADD /healthcheck.sh healthcheck.sh
RUN chmod 777 /healthcheck.sh
RUN mkdir /tmp/tomcat static
EXPOSE 8888
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
apigateway
It starts fine, connects to configserver and gets configs.
FROM openjdk:13-alpine
ADD /target/apigateway-service-0.0.1-SNAPSHOT.jar app.jar
ADD /healthcheck.sh healthcheck.sh
RUN chmod 777 /healthcheck.sh
RUN mkdir /tmp/tomcat static
EXPOSE 8770
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
users-ms
This one exits after long time (default timeout in spring.config.request_timeout is 185000 and requset_connection_timeout is 1000)by throwing read timeout exception.
FROM openjdk:13-alpine
ADD /target/users-service-0.0.1-SNAPSHOT.jar app.jar
ADD /healthcheck.sh healthcheck.sh
RUN chmod 777 /healthcheck.sh
RUN mkdir /tmp/tomcat static
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]
The read timeout exception what I get (there is no any other logs in docker desktop console (mac), futhermore the log screen is empty during this hangout period):
15:39:14.816 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:148)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:84)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.load(ConfigServerConfigDataLoader.java:59)
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:102)
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:118)
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:82)
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:119)
at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:294)
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:223)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:88)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:80)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:100)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:86)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:82)
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:63)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:117)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:111)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:62)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:362)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1309)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1298)
at com.xyz.ms..api.users.XYZUsersServiceApplication.main(XYZUsersServiceApplication.java:16)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://configserver:8888/users-ws/dockertest": Read timed out; nested exception is java.net.SocketTimeoutException: Read timed out
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:784)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:710)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:601)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.getRemoteEnvironment(ConfigServerConfigDataLoader.java:250)
at org.springframework.cloud.config.client.ConfigServerConfigDataLoader.doLoad(ConfigServerConfigDataLoader.java:100)
... 35 common frames omitted
Caused by: java.net.SocketTimeoutException: Read timed out
at java.base/sun.nio.ch.NioSocketImpl.timedRead(NioSocketImpl.java:284)
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:310)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:351)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:802)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:919)
at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:245)
at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:285)
at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:344)
at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:746)
at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:689)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1610)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1515)
at java.base/java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:527)
at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:82)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:775)
... 39 common frames omitted
-----Update: solution -----
It's not too sexy.
To check myself, I went back to native (host) platform and tried to start everything to make sure its running. And it didn't. It's suprise me.
I use Intellij and Spring Boot 2.4.1.
I thought something messed up, so I check spring initilzr for the proper settings in pom file again, and cleared the cache of IntelliJ, and this did the trick. Everything works now. Thanks for your time!

Related

Microservice java property not set in application.properties

I have the following line in micros1-mvc microservice application.properties: eureka.client.serviceUrl.defaultZone=${EUREKA_SERVER}
I execute the microservice inside the container with:
sudo docker run -p 8081:8081 --network mynetw --env JAVA_OPTS="-DEUREKA_SERVER=http://eurekaserver:8761/eureka" micros1-mvc
And when the microservice tries to connect with Eureka it says:
overyClient :
DiscoveryClient_SERVICEASERVICE/1754e70517a8:serviceaservice:8081 -
was unable to refresh its cache! This periodic background refresh will
be retried in 30 seconds. status = There is no known eureka server;
cluster server list is empty stacktrace =
com.netflix.discovery.shared.transport.TransportException: There is no
known eureka server; cluster server list is empty at
com.netflix.discovery.shared.transport.decorator.RetryableEurekaHttpClient.execute(RetryableEurekaHttpClient.java:108)
at
com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134)
at
com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator$6.execute(EurekaHttpClientDecorator.java:137)
at
com.netflix.discovery.shared.transport.decorator.SessionedEurekaHttpClient.execute(SessionedEurekaHttpClient.java:77)
at
com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134)
at
com.netflix.discovery.DiscoveryClient.getAndStoreFullRegistry(DiscoveryClient.java:1101)
at
com.netflix.discovery.DiscoveryClient.fetchRegistry(DiscoveryClient.java:1014)
at
com.netflix.discovery.DiscoveryClient.refreshRegistry(DiscoveryClient.java:1531)
It looks like the microservice properties file doesn't receive the specified value in docker execution
After some searching, I came across the fact that JAVA_OPTS are very specific to Catalina (Tomcat). Looking in the bin folder of a tomcat install you'll find a shell script that handles passing JAVA_OPTS into the exec lines.
A Dockerfile like:
FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","${JAVA_OPTS}","-jar","/app.jar"]
With:
docker run -p 9000:9000 -e JAVA_OPTS=-Dserver.port=9000 myorg/myapp
Fails. This fails because the ${} substitution requires a shell. The exec form does not use a shell to launch the process, so the options are not applied. You can get around that by moving the entry point to a script or by explicitly creating a shell in the entry point. The following example shows how to create a shell in the entry point:
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]
You can then launch this app by running the following command:
docker run -p 8080:8080 -e "JAVA_OPTS=-Ddebug -Xmx128m" myorg/myapp

Failed to bind properties under 'server.port' to java.lang.Integer

Some time ago I faced with such issue:
Failed to bind properties under 'server.port' to java.lang.Integer:
Property: server.port
Value: $PORT
Origin: "server.port" from property source "systemProperties"
Reason: failed to convert java.lang.String to java.lang.Integer
Action:
Update your application's configuration
I tried to run my docker container in DigitalOcean.
I observed some similar topics here and I tried to apply advices. For instance I added server.port=${PORT:8080} to my application.properties but it didn't work for me.
Here's my docker run command:
docker run -p 8080:8080 --name nostalgia --env-file vars.txt --rm -it registry.digitalocean.com/alex-registry/nostalgia
And this is my vars.txt (only one variable at the moment):
PORT=8080
Also I should say that I tried another form of command:
docker run -p 8080:8080 --name nostalgia -e PORT=8080 --rm -it registry.digitalocean.com/alex-registry/nostalgia
But result is the same.
What should I do next to overcome this issue and successfully launch the container? Thanks for your answers!!!

How to remote debug attach Keycloak in versions > 8

I recently upgraded Keycloak to version 9, and when running in Docker, I'm having trouble attaching a remote debugger. I suspect this has to do with Keycloak's underlying upgrade to Java 9+.
The error I get is:
handshake failed - connection prematurally closed
I have my ports mapped correctly within Docker (I can run Keycloak version 7 and it attaches just fine).
The approach depends on whether you're using standalone.sh (or .bat presumably) or a docker image.
If you're using standalone.sh, you can use the --debug option, documented in standalone.sh -h:
standalone.sh --debug '*:8000'
(the * is to allow access from any host. Plain --debug 8000 will allow access only from localhost)
For docker images, this will be the documented approach from version 12 on, and it works at least from Keycloak 11.0.2:
$ git diff
diff --git a/docker-compose/keycloak-standalone/docker-compose.yml b/docker-compose/keycloak-standalone/docker-compose.yml
index fcf3a52..93b7209 100644
--- a/docker-compose/keycloak-standalone/docker-compose.yml
+++ b/docker-compose/keycloak-standalone/docker-compose.yml
## -11,11 +11,14 ## services:
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
+ DEBUG: "true"
+ DEBUG_PORT: "*:8000"
ports:
- 8080:8080
+ - 8000:8000
volumes:
- data:/opt/jboss/keycloak/standalone/data
(Again, the * is to allow access from any host.)
As it turns out, Java 9 introduced a security enhancement with respect to debugging. Information here: https://stackoverflow.com/a/60090750/2117355
In my Keycloak docker-compose service definition, I was able to add under environment:
DEBUG_PORT: "*:8787"
And that fixed the problem. I'm now able to debug.
For Keycloak version 7
I'm using this command to run the docker container to enable debugging at port 1234
docker run -e KEYCLOAK_USER=admin -e KEYCLOAK_PASSWORD=admin
-e JAVA_OPTS="-server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
-Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman
-Djava.awt.headless=true
-agentlib:jdwp=transport=dt_socket,address=1234,server=y,suspend=n"
-p 8080:8080 -p 1234:1234 jboss/keycloak:7.0.0
Connecting it to the IntelliJ using Remote Configuration
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1234
*Note: The default value of the JAVA_OPTS is below so I prepended it with the above configuration
-server -Xms64m -Xmx512m -XX:MetaspaceSize=96M -XX:MaxMetaspaceSize=256m
-Djava.net.preferIPv4Stack=true -Djboss.modules.system.pkgs=org.jboss.byteman
-Djava.awt.headless=true
You can replace debug params by creating your own image, using Dockerfile
Dockerfile:
FROM jboss/keycloak:latest
ENV DEBUG true
ENV DEBUG_PORT *:8787
EXPOSE 8080 8443 9990 8787
ENTRYPOINT ${JBOSS_HOME}/../tools/docker-entrypoint.sh
console:
docker build -t local/debug-keycloack ..
docker run -p 8080:8080 -p 8443:8443 -p 9990:9990 -p 8787:8787 --name debug-keycloack local/debug-keycloack

Failed to deploy Spring and MySQL application using Docker

I am trying to connect a Spring server to a Mysql database, both running in different containers, and I got this error:
Caused by: com.mysql.cj.exceptions.WrongArgumentException: Malformed database URL, failed to parse the main URL sections.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[na:1.8.0_232]
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[na:1.8.0_232]
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ~[na:1.8.0_232]
at java.lang.reflect.Constructor.newInstance(Constructor.java:423) ~[na:1.8.0_232]
at com.mysql.cj.exceptions.ExceptionFactory.createException(ExceptionFactory.java:61) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrlParser.parseConnectionString(ConnectionUrlParser.java:162) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrlParser.<init>(ConnectionUrlParser.java:136) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrlParser.parseConnectionString(ConnectionUrlParser.java:118) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.conf.ConnectionUrl.getConnectionUrlInstance(ConnectionUrl.java:197) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:196) ~[mysql-connector-java-8.0.17.jar!/:8.0.17]
... 53 common frames omitted
For the Mysql container I am using the latest image from dockerhub.
I'm guessing that the ip address of the mysql container i'm trying to connect to is wrong, but I don't know how to obtain the correct address.
I am starting the mysql container via:
docker run -p 3036:3036 --name mysql-container -d mysql
application.properties in the Spring project:
database.ip = ${MYSQL_IP:mysql-container}
database.port = ${MYSQL_PORT:3306}
spring.datasource.url = jdbc:mysql://${database.ip}:${database.port}/${database.name}
backend container:
docker run -p 8080:8080 --name backend_container --link mysql-container:mysql -d backend_container
I didn't use Docker until now, so sorry if it is a trivial/boring question.
I would appreciate some help! :)
First of all, I don't understand why the database was containerized. Generally speaking, there's no reason for that.
Check if your database host has port-forwarding, i.e. port 3036 on the database host should be mapped to a URL or a global IP address. Check out ngrok so that you're unblocked, but there's a "proper" way to do this that's usually specific to your cloud provider.
Edit: There's also a typo in the code you posted. Your docker run command uses port 3036, but your Spring code contains database.port = ${MYSQL_PORT:3306}. Can't tell whether that's just a typo on here or in your actual code, but that's also possibly there.
As I found out, the problem was that the 2 containers were not on the same docker network.
When I started them with docker-compose using a docker-compose.yml, the 2 containers were started on the same default network, so that the spring container could connect to the mysql container ip address.
docker-compose.yml:
version: '3'
services:
mysql-container:
container_name: mysql-container
image: mysql:latest
environment:
- MYSQL_ROOT_PASSWORD=password
- MYSQL_DATABASE=db_name
- MYSQL_PASSWORD=root
spring_app_container:
container_name: spring_app_container
image: spring_app
depends_on:
- mysql-container
ports:
- 8085:8085
- 8080:8080
environment:
- DATABASE_HOST=mysql-container
- DATABASE_USER=root
- DATABASE_PASSWORD=password
- DATABASE_NAME=db_name
- DATABASE_PORT=3306

dockerized postgres and dockerized Spring boot app

my application.properties file
server.port=8085
spring.datasource.driverClassName=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://init-postgres:5432/dbname
spring.datasource.username=username
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
and for dockerizing postgres I'm using command
docker run -d -p 5432:5432 --name init-postgres -e POSTGRES_DB=dbname -e POSTGRES_USER=username -e POSTGRES_PASSWORD=password postgres
but it gives java.net.UnknownHostException: init-postgres
I'm beginner with Docker and learning it from a tutorial. to dockerized Postgresql & Spring boot app communication.
If you need to dockerize both of them without docker-compose
application.config
spring.datasource.url=jdbc:postgresql://init-postgres:5432/dbname
Create network
docker network create mynet
Run postgres container with created network
docker run --net mynet --name init-postgres -d -e POSTGRES_DB=dbname -e POSTGRES_USER=username -e POSTGRES_PASSWORD=password -p 5432:5432 postgres
Create jar archive
mvn clean
mvn compile
mvn package
Create dockerfile
FROM openjdk:8-jdk-alpine
ARG JAR_FILE=target/<HERE_IS_NAME_OF_YOUR_JAR_FILE>.jar
COPY ${JAR_FILE} myapp.jar
EXPOSE 8085
ENTRYPOINT ["java","-jar" , "/myapp.jar"]
Build spring boot image myapp
docker build -t myapp .
Run spring boot container
docker run --name myapp-container --net mynet -p 8080:8080 myapp
If your application runs on the host without docker and your database lives inside a docker container, you need to change this line:
spring.datasource.url=jdbc:postgresql://init-postgres:5432/dbname
with
spring.datasource.url=jdbc:postgresql://localhost:5432/dbname
instead, if both the application and the database are running on docker you need to refer with the docker container name, as you stated above in the snippet you posted.
I suggest to use docker-compose, it's a handy tool that can ease the difficulties of deployment and it's useful when developing too since it allows to bring up & down your application without too much hassle. In the official docker website there is a nice introduction to the tool with examples.

Resources