feign.RetryableException Connection refused executing ... Spring Boot + Feign + Docker Compose - spring

I'm facing this issue when trying to use a microservice in docker (this doesn't happen in local).
An exception occurred in RetryableException, in the line -2:
Connection refused executing GET http://localhost:8082/api/car/findAll
this is my docker-compose file
version: '3.9'
services:
people:
build:
context: peoplems
ports:
- '8081:8081'
networks:
- host
vehicles:
build:
context: vehiclesms
ports:
- '8082:8082'
networks:
- host
api:
build:
context: apigateway
dockerfile: Dockefile
ports:
- '8080:8080'
networks:
- host
networks:
host:
driver: bridge
The services are running

The error was that I was trying to call "localhost" using feignclient
url = http://localhost:8081/api/car
So, when the app was 'deployed' in docker, docker wouldn't find the localhost address. I had to change "localhost" by the name of the container where the service was deployed: parking-people-1. My new url in feignclient is now
url = http://parking-people-1:8081/api/car
and it works.
NOTE: with this solution, you don't have to create a new network anymore. (at least in this case.)
I hope this could be useful for someone.

Related

Register Dockerized microservice to Eureka server - Springboot

In my production environment I have an Eureka Server running inside a docker container.
I can register to it other basic microservices with this kind of Application.yml
Application.yml:
server:
port: '8095'
spring:
application:
name: sap-listener
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://172.17.0.2:8761/eureka
I create a DockerImage with this Dockerfile:
Dockerfile
FROM openjdk:17-jdk
ARG JAR_FILE=target/*.jar
COPY target/sap-listener-*.jar /sap-listener.jar
ENTRYPOINT ["java", "-jar", "/sap-listener.jar" ]
EXPOSE 8095
and then I run it in production with this command:
docker run -d -p 8095:8095 --name sap myrepo/sap-listener1.0:latest
The service is successfully registered to the Eureka server.
I came across to some problems when I try to run a bigger microservice which have a docker-compose file.
I send directly this docker-compose file in production:
Docker-compose
version: "3.3"
services:
docker-mysql:
image: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'password'
MYSQL_DATABASE: 'db'
ports:
- "3007:3306"
phpmyadmin:
image: phpmyadmin
restart: always
container_name: php-my-admin-users
ports:
- "8081:80"
ldap-app:
image: myRepo/service1:latest
ports:
- "8090:8090"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://docker-mysql:3306/db
depends_on:
- docker-mysql
And I run it with docker-compose -f docker-compose.yml up -d
service1 application.yml have the same type of connection with Eureka server of the previous microservice.
service1 is correctly deployed but It can't register himself to the Eureka server, if I log out the container output I have this error:
2022-06-29 15:45:20.551 INFO 1 --- [ main] c.n.d.s.t.d.RedirectingEurekaHttpClient : Request execution error. endpoint=DefaultEndpoint{ serviceUrl='http://172.17.0.2:8761/eureka/}, exception=I/O error on GET request for "http://172.17.0.2:8761/eureka/apps/": Connect to 172.17.0.2:8761 [/172.17.0.2] failed: Connection timed out; nested exception is org.apache.http.conn.ConnectTimeoutException: Connect to 172.17.0.2:8761 [/172.17.0.2] failed: Connection timed out stacktrace=org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://172.17.0.2:8761/eureka/apps/": Connect to 172.17.0.2:8761 [/172.17.0.2] failed: Connection timed out; nested exception is org.apache.http.conn.ConnectTimeoutException: Connect to 172.17.0.2:8761 [/172.17.0.2] failed: Connection timed out
I read that someone directly insert the Eureka Server data as a service inside the Docker-Compose.yml file, but my Eureka Server is already deployed and is already listening to a specific port.
That is probably happening because docker-compose automatically assign a network to the containers.
Try adding network_mode: host to your services in the compose file, like so:
version: "3.3"
services:
docker-mysql:
network_mode: host
image: mysql
restart: always
environment:
MYSQL_ROOT_PASSWORD: 'password'
MYSQL_DATABASE: 'db'
ports:
- "3007:3306"
phpmyadmin:
network_mode: host
image: phpmyadmin
restart: always
container_name: php-my-admin-users
ports:
- "8081:80"
ldap-app:
network_mode: host
image: myRepo/service1:latest
ports:
- "8090:8090"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://docker-mysql:3306/db
depends_on:
- docker-mysql
First I would suggest you get familiar with how networking in Docker works and then have a look at networking in Docker-Compose.
When you run docker network ls when your containers are deployed you will see that they are running on different networks, which isolates them. Inspect the networks using docker network inspect <id> and you'll see they have different subnets. So for the services to be able to communicate they need to be on the same network.
You can manually create a network and use it in both compose and the docker cli.

How to connect to external port DB in docker [duplicate]

I'm working with spring boot, hibernate & MySql. While running the application it is running well as per expectation . But while making the docker-compose file and running the app docker image with mysql docker image it gives this error.
Error
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
java.net.ConnectException: Connection refused.
private Connection createConnection() throws SQLException
{
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
String mysqlUrl = "jdbc:mysql://localhost/database?autoReconnect=true&useSSL=false";
Connection connection = DriverManager.getConnection(mysqlUrl, "root", "root");
return connection;
}
Application.properties
spring.datasource.url=jdbc:mysql://localhost/database?autoReconnect=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
Please guide me how to tackle this.
docker-compose.yml
version: '3'
services:
docker-mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=database
- MYSQL_USER=root
- MYSQL_PASSWORD=root
ports:
- 3307:3306
app:
image: app:latest
ports:
- 8091:8091
depends_on:
- docker-mysql
Issue is due to reference of localhost in the jdbc url.
Below configuration should work.
**docker-compose.yml**
version: '3'
services:
docker-mysql:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=database
- MYSQL_USER=root
- MYSQL_PASSWORD=root
ports:
- 3307:3306
app:
image: app:latest
ports:
- 8091:8091
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://docker-mysql:3306/database?autoReconnect=true&useSSL=false
depends_on:
- docker-mysql
This Docker forum discussion helped me when I was running into this error. For me it was a problem with cache and I didn't get the error after running docker-compose down --rmi all
For me, it was the version of mysql
image: mysql:8 -> image: mysql:5.7
did you tell your docker that it depends on SQL?
I mean is there something like this:
depends_on:
- mysql_server
in your docker-compose.yml ?
looks like a configuration issue.
In my case I have provided proper privilege for my user to get connected from docker host and the error war gone.
I have provided % as host for my user which will provide access to connect from any host. The default root user will only connects from localhost.
Put something like this in the application.properties
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:${MYSQL_PORT:3306}/test
spring.datasource.username=${MYSQL_USER:root}
spring.datasource.password=${MYSQL_PASSWORD:password}

RabbitMQ not working when services are dockerized

So I have 2 services. Kweet (which is a tweet) and User. When I run the 2 services manually + rest of the services in docker, it works. Rest of services include MongoDB, RabbitMQ, Spring Cloud Gateway, Eureka Discovery. But the moment I run the 2 (micro)services in Docker (I just use a docker compose), the rabbitmq functionality stops working. The normal API calls work, it's specifically the RabbitMQ calls that fail.
RabbitMQ functionality:
EditUsername, edits username in user-service.
Than sends data via RabbitMQ (this is where it goes wrong I think) to kweet-service where it edits the username of a kweet.
Docker-compose file:
version: '3.8'
services:
eureka-service:
build: ./eureka-discovery-service
restart: always
container_name: eureka-service
ports:
- 8087:8087
api-gateway:
build: ./api-gateway
restart: always
container_name: api-gateway
depends_on:
- eureka-service
ports:
- 8080:8080
user:
build: ./user
restart: unless-stopped
container_name: user-ms
ports:
- 8081:8081
depends_on:
- eureka-service
kweet:
build: ./kweet
restart: unless-stopped
container_name: kweet-ms
depends_on:
- eureka-service
ports:
- 8082:8082
mongodb:
image: mongo
restart: always
container_name: mongodb
ports:
- 27017:27017
rabbitmq:
image: rabbitmq:management
restart: always
container_name: rabbitmq
hostname: rabbitmq
ports:
- 5672:5672
- 15672:15672
When I try to make a call the console shows:
user-ms | 2022-04-27 08:52:04.823 INFO 1 --- [nio-8081-exec-4] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:5672]
The postman status I get back is 503 Service Unavailable which isn't from any try-catch's I made. Anybody have any clue where the problem might be?
EDIT[ConnectionFactory]:
I tried to use the documentation and added a the CachingConnectionFactory but it had the same result. Am I doing it wrong?
I added this to the RabbitMQ/Message-config (HOST, USERNAME, PASSWORD come from application.properties:
#Bean
public AmqpTemplate template() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(HOST);
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMessageConverter(converter());
return rabbitTemplate;
}
EDIT [docker-compose]:
Found this source (https://www.linkedin.com/pulse/binding-your-docker-app-container-rabbitmq-phani-bushan/) that got rid of my 503 Service Unavailable error. The problem I found now is that whenever I start up the containers, it generates new queues and exchanges that aren't the ones I set up in my application.properties.
Now whenever I make a call, it shows this log:
user-ms | 2022-04-28 07:36:28.825 INFO 1 --- [nio-8081-exec-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory#2ca65ce4:0/SimpleCo
nnection#7e7052f [delegate=amqp://guest#172.23.0.4:5672/, localPort= 43208]
Things tried:
change host to [rabbitmq-container-name] in code via CachingConnectionFactory
change host to [rabbitmq-container-name] in docker compose with environment: - spring_rabbitmq_host=[rabbitmq-container-name]
build: ./user
restart: unless-stopped
container_name: user-ms
depends_on:
- eureka-service
- rabbitmq
ports:
- 8081:8081
environment:
- spring_rabbitmq_host=[rabbitmq-container-name]
Instead of [rabbitmq-container-name] I've tried host.docker.internal and localhost
When you dockerize your services are no longer listening in localhost. If you need to network connect services you need to use container_name instead of localhost.
localhost points to the container itself, where only one service is listening. Do not mistake for when you develop on your laptop without containers, where everything is in localhost
More about this here
By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.
You must configure, somewhere in your user-ms application (we do not know what kind of applicatin is), that RabbitMQ service is listening at rabbitmq (container_name) not localhost.
Try to use the container with environment variables. For me it is enough for working.
rabbitmq:
image: rabbitmq:management
restart: always
container_name: rabbitmq
environment:
RABBITMQ_DEFAULT_USER: guest
RABBITMQ_DEFAULT_PASS: guest
RABBITMQ_DEFAULT_VHOST: /
ports:
- 5672:5672
- 15672:15672
I can open this container in a browser: http://localhost:15672/
I use PHP FPM and Symfony and I pass env value to this container to connect to rabbitmq.
services:
php-fpm:
environment:
ENQUEUE_DSN: amqp://guest:guest#rabbitmq:5672
For Java you need to find and define or redefine application properties. The config may use the default value for localhost, like this spring.rabbitmq.host=localhost, but you need to use Docker's host, it is rabbitmq.
spring.rabbitmq.host=rabbitmq
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
I have made a grave mistake. 2 things that I did before it started working.
Change Dockerfile ADD command to COPY (Don't think that was the problem though)
Deleted all my images and containers and re-made them a.k.a instead of docker-compose up I should've been typing docker-compose up --build. This was most likely the issue
brb gonna cry in a corner

Communication between 2 dockerized spring boot applications using custom docker network

I have a Hello service and World service. The Hello service has a rest point /hello/hw which internally calls rest end point in World service to return string "Hello World".
The application works fine as expected if the system is not dockerized.
However the issue is when I want to dockerize the system.
I use docker-compose to containerize both services. I have defined a custom network in the docker compose file (named as custom_net).
The rest end point /hello/hw is reachable but Hello service is not able to call the rest end point in the World service.
The application.properties in Hello service has the url of World service as http://localhost:8082/world
I get UnknownHostException when I set the url as http://custom_net:8082/world or to http://custom_net:8092/world
I get Connection refused exception when I don't change the url in application.properties.
The log message states 'failed: Connection refused: localhost/127.0.0.1:8082;'
I am not sure what configurations are needed to bridge the 2 services
The command docker network list shows the name of custom network as 'tempfolder_custom_net'.
The command docker inspect shows that both hello and world service are registered to this network
version: '3'
services:
hello_service:
image: 'openjdk:8-jdk-alpine'
restart: always
container_name: hello_service
volumes:
- ./deploy:/root
networks:
- custom_net
depends_on:
- world_service
command: sh -c "java -jar -Dspring.config.location=file:///root/hello/application.yml /root/hello/hello-0.0.1-SNAPSHOT.jar "
ports:
- 8091:8081
world_service:
image: 'openjdk:8-jdk-alpine'
restart: always
container_name: world_service
volumes:
- ./deploy:/root
command: sh -c "java -jar -Dspring.config.location=file:///root/world/application.yml /root/world/world-0.0.1-SNAPSHOT.jar "
ports:
- 8092:8082
networks:
- custom_net
networks:
custom_net:
driver: bridge
Application.yml of Hello service ...
server:
port: 8081
services:
world:
url: http://localhost:8082/world
You should build new image base on openjdk:8-jdk-alpine image, and add ENTRYPOINT
You should change this:
server:
port: 8081
services:
world:
url: http://localhost:8082/world
To :
server:
port: 8081
services:
world:
url: http://world_service:8092/world
Make sure, both containers are running.
#Thanh Nuguyen Van thanks for providing useful hints in troubleshooting.
The issue was with the host name world_service. Looks like underscore is not a valid URL. Below is my updated docker compose file. I didn't even have to use custom docker network. I updated the url in application.yml to http://worldservice:8082/world.
Also note that the port is 8082 not 8092. We have to mention the application's port and not the docker exposed port.
version: '3'
services:
helloservice:
image: 'openjdk:8-jdk-alpine'
restart: always
container_name: helloservice
volumes:
- ./deploy:/root
#networks:
#- custom_net
depends_on:
- worldservice
command: sh -c "java -Xdebug -jar -Dspring.config.location=file:///root/hello/application.yml /root/hello/hello-0.0.1-SNAPSHOT.jar "
ports:
- 8091:8081
worldservice:
image: 'openjdk:8-jdk-alpine'
restart: always
container_name: worldservice
volumes:
- ./deploy:/root
command: sh -c "java -Xdebug -jar -Dspring.config.location=file:///root/world/application.yml /root/world/world-0.0.1-SNAPSHOT.jar "
ports:
- 8092:8082
#networks:
#- custom_net
#networks:
#custom_net:
#driver: bridge

Connection refused when connecting to keycloak container from backend container

I have two containers backend (spring boot application) and Keycloak. if I run keycloak in a container and backend locally : it works
If both of them are run in container the backend doesn't start and shows the following error :
Failed to instantiate [org.springframework.security.oauth2.jwt.JwtDecoder]: Factory method 'jwtDecoderByIssuerUri' threw exception; nested exception is java.lang.IllegalArgumentException: Unable to resolve the Configuration with the provided Issuer of "http://keycloak:8082/auth/realms/myrealm"
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://keycloak:8082/auth/realms/myrealm/.well-known/openid-configuration": Connection refused (Connection refused);
following are my configs :
docker-compose :
services:
keycloak:
image: jboss/keycloak:8.0.1
command:
- " -b 0.0.0.0"
container_name: "keycloak"
networks:
- myproject
volumes:
- "./keycloak/realm-export.json:/opt/jboss/keycloak/bin/keycloak_export_dir/realm-export.json"
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: admin
KEYCLOAK_IMPORT: /opt/jboss/keycloak/bin/keycloak_export_dir/realm-export.json
ports:
- "8082:8080"
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: "backend"
environment:
- spring.oauth2.resourceserver.jwt.issuer-uri= http://keycloak:8082/auth/realms/myrealm
links:
- keycloak
networks:
- myproject
restart: on-failure
ports:
- "8080:8080"
networks:
myproject:
driver: bridge
application.yml:
application:
name: backend
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8082/auth/realms/myrealm
do you have any Idea why do I get connection refused ?
any help is appreciated :)
Your Keycloak container using the following port configuration
ports:
- "8082:8080"
That mean:
Keycloak is reachable from Outside via Port 8082.
But internally (in this docker network), keycloak is only reachable via the exposed 8080 port. So your backend application need to connect (internally) to http://keycloak:8080

Resources