Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need to tell eureka client running in Docker to use host's IP #432

Closed
cer opened this issue Jul 10, 2015 · 38 comments
Closed

Need to tell eureka client running in Docker to use host's IP #432

cer opened this issue Jul 10, 2015 · 38 comments

Comments

@cer
Copy link

cer commented Jul 10, 2015

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

@spencergibb
Copy link
Member

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

@brenuart
Copy link
Contributor

And what about:

  • eureka.instance.prefer-ip-address=true
  • eureka.instance.ip-address=

@cer
Copy link
Author

cer commented Jul 11, 2015

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

@spencergibb
Copy link
Member

@cer maybe an option to disable the refresh

@cer
Copy link
Author

cer commented Jul 13, 2015

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.

@brenuart
Copy link
Contributor

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?

@spencergibb
Copy link
Member

@brenuart we used to ignore the refresh, but then I did 9149319 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.

@brenuart
Copy link
Contributor

@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.

@ccit-spence
Copy link

@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.

@ccit-spence
Copy link

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.

@ccit-spence
Copy link

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.

@cer
Copy link
Author

cer commented Aug 19, 2015

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

@ccit-spence
Copy link

@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.

@rozhok
Copy link

rozhok commented Aug 25, 2015

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

@ccit-spence
Copy link

@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

@rozhok
Copy link

rozhok commented Aug 25, 2015

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

@rozhok
Copy link

rozhok commented Aug 27, 2015

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"]

@spencergibb
Copy link
Member

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

@ccit-spence
Copy link

My solution works fine for me.

@rozhok
Copy link

rozhok commented Nov 11, 2015

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

@brenuart
Copy link
Contributor

I'm fine with this.

@Dreampie
Copy link

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;
}

@rozhok
Copy link

rozhok commented Dec 22, 2015

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

@Dreampie
Copy link

@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

@rozhok
Copy link

rozhok commented Dec 22, 2015 via email

@Dreampie
Copy link

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

@rozhok
Copy link

rozhok commented Dec 22, 2015 via email

@rozhok
Copy link

rozhok commented Dec 22, 2015 via email

@Dreampie
Copy link

💦thanks

@asarkar
Copy link
Contributor

asarkar commented Dec 27, 2015

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

@cswanghan
Copy link

is there any update about this issue?

@spencergibb
Copy link
Member

@cswanghan no, it was closed in 2015

@momentum123
Copy link

@spencergibb im still facing the issue

@wenfei3
Copy link

wenfei3 commented Sep 6, 2018

@momentum123
me too

@niall-morgan
Copy link

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.

@spencergibb
Copy link
Member

EurekaInstanceConfigBean is public

@secesor
Copy link

secesor commented Apr 29, 2024

EurekaInstanceConfigBean is public

It's the class that is public but the constructor is private.
See

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

@spencergibb
Copy link
Member

spencergibb commented Apr 29, 2024

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();
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests