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.
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?
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
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With