I am running a Spring Cloud application inside a Docker container. While I can tell Eureka to use the exposed port (e.g. EUREKA_INSTANCE_NON_SECURE_PORT: 8081) , it doesn't seem to let you tell it to register using the host's ip address. Instead, eureka registers the instance using the container's ip address. That fine unless I want to access the container from another host. What would be great is the ability to set an environment variable such as EUREKA_INSTANCE_NON_SECURE_HOST: docker_host_ip_address

Comment From: spencergibb

I wonder if eureka.instance.hostname will work. If not, then we'll have to do something to fix it.

Comment From: brenuart

And what about: - eureka.instance.prefer-ip-address=true - eureka.instance.ip-address=

Comment From: cer

Difficult to tell from looking at the class in isolation. Depends on whether getHostName(refresh) is called with refresh=true or false.

Comment From: spencergibb

@cer maybe an option to disable the refresh

Comment From: cer

I haven't looked at Spring Cloud enough to know precise what refresh is intended to do. However, I think that a user specified host name/ip address should always take precedence.

Comment From: brenuart

Maybe I don't get it, but setting eureka.instance.hostname to the desired value should work (at least it does on our side). If you set eureka.instance.prefer-ip-address=true, then the registration with Eureka will instead use the IP address specified by eureka.instance.ip-address (which defaults to host's IP after resolving).

@cer: the user specified value takes precedence over the default values. Do you see a different behaviour?

Comment From: spencergibb

@brenuart we used to ignore the refresh, but then I did 9149319bd73f228896d52b733894447170e4f26f which will refresh at somepoint in netflix code. @cer, I agree, we just have trouble knowing when the value was user specified or not, so either another user specified hostname field or the flag to not refresh.

Comment From: brenuart

@spencergibb Ok - I see. Sorry, I wasn't aware of that change. To be honest, we used to override part of the EurekaInstanceConfigBean to add some validation and other useful default values/behaviour. To make it short, we moved the initialisation of default values out of the config bean to the method that creates it. The config bean is now a simple POJO and we are not "hit" by your latest change... I should definitely create a PR with those changes for you to see and pickup what you believe is interesting.

Comment From: ccit-spence

@cer @spencergibb Having a slightly more complicated version of the same problem. I am experiencing the same issue for the host. On top of that the container is launched with -P meaning a random host port is assigned. With the current setup there is no way to get that random port assignment. The port is being pulled from server.port.

Another note, about assigning something within eureka.instance.hostname or eureka.instance.ip-address is that if this is a docker cluster in our case AWS ECS. The host and IP can't be statically configured within properties.

Comment From: ccit-spence

Something that can be done from docker is just using the docker run -h hostname or ip Eureka will pick up the host name since it it written to the etc/hosts file

Not sure yet how to handle this for a cluster.

Comment From: ccit-spence

Update: Further testing with AWS ECS even with adding the hostname to the properties it does not work. Unless all instances are docker containers i.e. Eureka, Zuul and UI and API services on the same host. Not sure If I am missing something. It seems that Ribbon is looking for something different than what Eureka is showing via the UI. Even if I could get it to work. As soon as the docker container switched to a different EC2 container the old hostname would be invalid.

Comment From: cer

What do you mean by "docker container switched to a different EC2 container" exactly?

Comment From: ccit-spence

@cer In ECS you have a cluster of EC2 instances. Due to the nature of EC2 unless you specify a Service to run on only one EC2 instance it can appear anywhere within the cluster.

That being said I now have ECS working for Spring Cloud. The solution is to curl the hostname of the host from within the Docker container during its boot process and assign the hostname to an environment variable. Then add the discovered hostname to the Eureka instance metadata.

Comment From: rozhok

@cer look at this - #30 I've got same problem - AWS, Docker and I've resolved it using proposed custom configurations.

Comment From: ccit-spence

@rozhok Are you doing something like the below? This is how I managed to get ECS to work.

entrypoint.sh

#!/bin/sh
export HOST=$(curl --retry 5 --connect-timeout 3 -s 169.254.169.254/latest/meta-data/local-hostname)
export LOCAL_IP=$(curl --retry 5 --connect-timeout 3 -s 169.254.169.254/latest/meta-data/local-ipv4)
exec "$@"

Dockerfile

FROM privaterepo/oracle-java8

RUN bash -c 'apt-get -qq update'
RUN bash -c 'DEBIAN_FRONTEND=noninteractive apt-get install -y curl'

EXPOSE 8080

COPY *.jar target/app.jar

COPY entrypoint.sh /usr/local/bin/entrypoint.sh

RUN touch target/app.jar

RUN chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

CMD java -jar target/app.jar

Comment From: rozhok

No, I've created custom Eureka Config so I don't need to setup additional scripts in Dockerfile. All stuff are described in #30 .

Comment From: rozhok

Another one approach described in Spring Cloud Netflix docs:

@Bean
@Profile("docker")
public EurekaInstanceConfigBean eurekaInstanceConfig() {
    EurekaInstanceConfigBean config = new EurekaInstanceConfigBean();
    AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
    config.setDataCenterInfo(info);
    info.getMetadata().put(AmazonInfo.MetaDataKey.publicHostname.getName(), info.get(AmazonInfo.MetaDataKey.publicIpv4));
    config.setHostname(info.get(AmazonInfo.MetaDataKey.publicHostname));
    config.setIpAddress(info.get(AmazonInfo.MetaDataKey.publicIpv4));
    config.setNonSecurePort(port);
    return config;
}

This will put proper IP (public in my case, but you may change it to local) and port into Eureka registry. Don't forget to add proper spring profile into Java env props, like this:

FROM java:8
EXPOSE 14862
ENV JAVA_OPTS -Dspring.profiles.active=docker
ADD build/distributions/portal.tar /
ENTRYPOINT ["/portal/bin/portal"]

Comment From: spencergibb

@cer @rozhok @brenuart @ccit-spence anyone still having issues that we need to address?

Comment From: ccit-spence

My solution works fine for me.

Comment From: rozhok

@spencergibb I'm using solution described above. A little bit hackish but fine at the moment.

Comment From: brenuart

I'm fine with this.

Comment From: Dreampie

It can be used to do my own server not AWS?

@Bean
@Profile("docker")
public EurekaInstanceConfigBean eurekaInstanceConfig() {
    EurekaInstanceConfigBean config = new EurekaInstanceConfigBean();
    AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
    config.setDataCenterInfo(info);
    info.getMetadata().put(AmazonInfo.MetaDataKey.publicHostname.getName(), info.get(AmazonInfo.MetaDataKey.publicIpv4));
    config.setHostname(info.get(AmazonInfo.MetaDataKey.publicHostname));
    config.setIpAddress(info.get(AmazonInfo.MetaDataKey.publicIpv4));
    config.setNonSecurePort(port);
    return config;
}

Comment From: rozhok

@Dreampie not, it won't be used on your own infrastructure since it using AWS-specific SDK.

Comment From: Dreampie

@rozhok thank you. and how can eureka client registered with host ip,not docker container ip?if use --net=host always return 127.0.0.1

Comment From: rozhok

Use some env variables passed into docker on startup time.

Comment From: Dreampie

@rozhok but if this machine's ip changed, must recreate container?

Comment From: rozhok

Sure.

Comment From: rozhok

Or trigg some API insinde container to reload eureka configuration. Something like /api/eureka/changeIp etc. There is a lot of ways to solve this task but non of them are obvious or elegant. Sad.

Comment From: Dreampie

💦thanks

Comment From: asarkar

@Dreampie Using the custom Eureka config as in your post, what do the application.yml and bootstrap.yml look like?

Comment From: cswanghan

is there any update about this issue?

Comment From: spencergibb

@cswanghan no, it was closed in 2015

Comment From: momentum123

@spencergibb im still facing the issue

Comment From: wenfei3

@momentum123 me too

Comment From: niall-morgan

It can be used to do my own server not AWS?

@Bean @Profile("docker") public EurekaInstanceConfigBean eurekaInstanceConfig() { EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(); AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka"); config.setDataCenterInfo(info); info.getMetadata().put(AmazonInfo.MetaDataKey.publicHostname.getName(), info.get(AmazonInfo.MetaDataKey.publicIpv4)); config.setHostname(info.get(AmazonInfo.MetaDataKey.publicHostname)); config.setIpAddress(info.get(AmazonInfo.MetaDataKey.publicIpv4)); config.setNonSecurePort(port); return config; } EurekaInstanceConfigBean is private in that package .. not sure how this would be implemented.

Comment From: spencergibb

EurekaInstanceConfigBean is public https://github.com/spring-cloud/spring-cloud-netflix/blob/c60b6dba5271e386f45347b129da6e763b8d93a7/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java#L42

Comment From: secesor

EurekaInstanceConfigBean is public

https://github.com/spring-cloud/spring-cloud-netflix/blob/c60b6dba5271e386f45347b129da6e763b8d93a7/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java#L42

It's the class that is public but the constructor is private. See https://github.com/spring-cloud/spring-cloud-netflix/blob/c60b6dba5271e386f45347b129da6e763b8d93a7/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java#L287

I have the same issue running my app inside DevContainer (docker behind the scenes). How can I then create an instance of EurekaInstanceConfigBean?

Comment From: spencergibb

Use the public constructor. InetUtils is also a bean.

public EurekaInstanceConfigBean(InetUtils inetUtils) {
    this.inetUtils = inetUtils;
    this.hostInfo = this.inetUtils.findFirstNonLoopbackHostInfo();
    this.ipAddress = this.hostInfo.getIpAddress();
    this.hostname = this.hostInfo.getHostname();
}