Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker and Eureka with Spring Boot failing to register clients

I have a very simple demo of using Spring Boot + Docker Compose + Eureka.

My server runs on port 8671 with the following application properties:

server:
  port: 8761
eureka:
  instance:
    prefer-ip-address: true
  client:
    registerWithEureka: false
    fetchRegistry: false
  server:
    waitTimeInMsWhenSyncEmpty: 0

My Eureka client runs on port 9000 with the following application properties:

server:
  port: 9000
spring:
  application:
    name: user-registration
eureka:
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

When I start up my docker.compose file in the parent maven project, this is the contents of my docker-compose file:

eureka-server:
  image: rosenthal/eureka-server
ports:
   - "8761:8761"
user-registration:
  image: rosenthal/user-registration
  ports:
   - "9000:9000"
  links:
   - eureka-server

When I run my application by first starting the eureka server, following by the client via

mvn spring-boot:run 

The server successfully registers my client (I call it user-registration).

When I run my application through docker-compose, the client fails to register with the following output:

 DiscoveryClient_USER-REGISTRATION/0fd640cbc3ba:user-registration:9000: 
 registering service...
 user-registration_1  | 2017-06-21 04:36:05.120 ERROR 1 --- [nfoReplicator-0]        
 c.n.d.s.t.d.RedirectingEurekaHttpClient  : Request execution error
 user-registration_1  | 
 user-registration_1  | com.sun.jersey.api.client.ClientHandlerException: 
 java.net.ConnectException: Connection refused (Connection refused)

My first assumption was that running docker-compose ran into a race condition on waiting for the server to start, but my eureka client seems to have a heartbeat trying to call home to the server it's configured with. This means it's just not able to find the Eureka server I have registered (and is running, I can navigate to it on localhost:8671).

What am I missing here? Everything runs fine running locally with spring-boot starting up with it's own embedded tomcat containers. As soon as I start to do it with docker-compose, it doesn't want to work.

EDIT

I realized my problem, I believe. So docker doesn't run on localhost, it runs on the public IP it is assigned when I start up docker. Navigating to this ip + port shows my service running for Eureka Server. The client still doesn't register.

SO, I made changes to the application.yml file for my eureka client to:

serviceUrl:
  defaultZone: http://192.168.59.103:8761/eureka/

That IP is the one my docker daemon is running under. Now, it misses the first registration when I do docker-compose, but the second heartbeat picks up my client.

How can I ensure the client waits until the server is FULLY up? I used the proper docker "links" field in my docket compose file, but it didn't work as I hoped. Additionally, how can I see the defaultZone file to be my DOCKER_HOST IP?

Final result

The resulting docker-compose file that got everything working for me was:

eureka-server:
  image: thorrism/eureka-server
  ports:
   - "8761:8761"
user-registration:
  image: thorrism/user-registration
  ports:
   - "9000:9000"
  links:
   - eureka-server
  environment:
    EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://eureka-server:8761/eureka
like image 439
rosenthal Avatar asked Jun 21 '17 04:06

rosenthal


2 Answers

Set an environment property to override the eureka.client.serviceUrl.defaultZone to match the service name in your docker compose file.

eureka-server:
  image: rosenthal/eureka-server
  ports:
   - "8761:8761"
user-registration:
  image: rosenthal/user-registration
  ports:
   - "9000:9000"
  environment:
   - EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://eureka-server:8761/eureka

This will override the property from the packaged application.properties.

NOTE: As mentioned in the comments you don't need the links section in the compose file. I removed is as such. See https://docs.docker.com/compose/networking/ for info on that.

like image 133
M. Deinum Avatar answered Nov 02 '22 23:11

M. Deinum


UPDATE:

It looks like for the newer versions of spring-boot (in my case 2.4.5) this solution does not work. The EUREKA_CLIENT_SERVICEURL_DEFAULTZONE property is not picked up automatically. There is a permanent issue with camelcasing which creates an inconsistency. EUREKA_CLIENT_SERVICEURL_DEFAULTZONE is not converted to eureka.client.serviceUrl.defaultZone. It's converted to eureka.client.serviceurl.defaultzone. Please look at this Github Issue for spring-cloud-netflix for more details. They cannot change the parameter now as this will break backward compatibility. Here is the code that finally worked for me

   discovery:
     container_name: discovery
     build: .
     ports:
       - "8761:8761"

   user-registration:
     container_name: user-registration
     build: .
     ports:
       - "8080:8080"
     environment:
       SPRING_APPLICATION_JSON: '{"eureka":{"client":{"serviceUrl":{"defaultZone":"http://discovery:8761/eureka"}}}}'

For only this property to set through environment variable you have to user SPRING_APPLICATION_JSON. It's ugly but it works.

like image 36
Tanbir Ahmed Avatar answered Nov 03 '22 00:11

Tanbir Ahmed