I deployed a Eureka Client to cloud foundry, however when it registers with the Eureka server (also running on CF) it does not register it with the a route bound to the application. (I am actually not really sure where it is getting the hostname it is registering with. I am sure the hostname the container thinks it has is not the route that the CF router mapped to the application.) I am wondering if there is a best practice for dealing with this?
I got something working by setting eureka.instance.hostname to ${vcap.application.application_uris[0]}. However I am not sure how robust of a solution this actually is, especially since I could have multiple routes bound to the application.
Comment From: dsyer
Works for me (no config needed for hostname). What version of Spring Cloud are you using? Are you adding your own EurekaInstanceConfig bean or just using the default? Here's a eureka on PWS (username:password) that shows it working: http://eureka.cfapps.io/eureka/apps/configserver.
Comment From: ryanjbaxter
I am using a build-snapshot for my Eureka server (because of #100) and the M3 release for my Eureka client. No I am not adding my own EurekaInstanceConfig bean.
Here is what is being registered for my Eureka server http://sessionqa-eureka.mybluemix.net/.
Here is what my Eureka config looks like in the client.
eureka:
instance:
leaseRenewalIntervalInSeconds: 10
metadataMap:
instanceId: ${vcap.application.instance_id:${spring.application.name}:${spring.application.instance_id:${server.port}}}
client:
region: default
registryFetchIntervalSeconds: 5
availabilityZones:
default: ${APPLICATION_DOMAIN:${DOMAIN:defaultZone}}
serviceUrl:
defaultZone: ${vcap.services.sessionqaeureka.credentials.uri:http://localhost:8761/eureka/}
I took most of this from the customers-stores sample except for the defaultZone property (that is not specified in the sample).
Comment From: ryanjbaxter
So I think I am the right track, after looking at the application.yml in the config server sample it also sets the eureka.instance.hostname when the cloud profile is active. The difference in my case is that the application name in CF is not the same as the application name in Spring.
I think I have come up with a potential work around for the problem though. I can set an environment variable when I deploy my app to CF with the host name I deployed the app with and use that environment variable as the value to eureka.instance.hostname. Thoughts on that approach?
Whatever we decide as the right approach, I think the fact that you need to use eureka.instance.hostname when deploying to CF needs to be called out in the documentation. Unless I am missing it, I dont see it there today.
Comment From: dsyer
That's actually exactly the approach we took in the samples: an environment variable converts the application name to the CF route by prepending it - it's a simple convention that works, but I don't think there is a "right" approach. Need for documentation noted.
Comment From: ccit-spence
I have something similar to this issue, the difference being this is on AWS. Right now Eureka is pulling the private hostname ip-192-0-0-1 How would you get the public hostname. If I set this via the eureka.instance.hostname and Amazon reboots me I get a new hostname but it would be hardwired in the properties.
Comment From: spencergibb
@ccit-spence netflix uses elastic IP's for eureka, how are client's going to know how to connect to eureka? CF takes care of that, but on AWS, you'll have a problem. What are you planning on doing?
Comment From: ccit-spence
@spencergibb I am using elastic IP's for eureka. Eureka instances are ok since I am using elastic IP's. What I am seeing is that other services are registering with the private hostname instead of the public hostname.
Comment From: dsyer
If you use Spring Cloud out of the box it will not use the Netflix EurekaInstanceConfigImpl (which would default to being AWS datacenter aware). You could set up your own bean of that type, or use the Spring one (EurekaInstanceConfigBean) and inject the datacenter metadata in your configuration. I believe the Netflix native datacenter info does it through an API call at runtime (so it needs API credentials).
Is the private IP not a decent default anyway (services in AWS can contact each other directly that way)? I would also assume that the public IP is available through an API call or environment variable (maybe only the latter if you set your EC2 instance up to populate it on startup)?
Comment From: rozhok
Hey @ccit-spence did you resolve your issue? I'm currently trying to run some services using spring-boot cloud on aws cloud and facing same problem.
Comment From: DirkLachowski
@dsyer Regarding private vs. public ips: The problem here is that we have a mix of private ips and public eips. The discovery client registers the eureka servers with their private ip but the replication is using public eips. I think that's the reason for the registered replicas / available replicas mismatch.
See also: http://stackoverflow.com/q/36284246/1686330
Any hint how i can get eureka to use only private or only public ips?
Comment From: rozhok
@DirkLachowski use following snippet:
@Bean
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.publicHostname));
config.setHostname(info.get(AmazonInfo.MetaDataKey.publicHostname));
config.setIpAddress(info.get(AmazonInfo.MetaDataKey.publicIpv4));
config.setNonSecurePort(port);
return config;
}
Instead of publicIpv4 you may use local one.
Comment From: DirkLachowski
@rozhok thanks for the hint. Still not exactly what i was looking for but the missing hint i needed. I ended up with the following:
@SpringBootApplication
@EnableEurekaServer
@EnableDiscoveryClient
public class EurekaServer {
@Value("${server.port:8761}")
private int port;
public static void main(String[] args) {
SpringApplication.run(EurekaServer.class, args);
}
@Bean
@Autowired
public EurekaInstanceConfigBean eurekaInstanceConfig(InetUtils inetUtils) {
EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils);
AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
config.setHostname(info.get(AmazonInfo.MetaDataKey.publicHostname));
config.setIpAddress(info.get(AmazonInfo.MetaDataKey.publicIpv4));
config.setNonSecurePort(port);
config.setDataCenterInfo(info);
return config;
}
}
Comment From: rozhok
@DirkLachowski you don't need @Autowired for bean. Also, why you have @EnableEurekaServer? The snippet I provided is for clients only.
And what's your question again?
Comment From: DirkLachowski
@rozhok First of all, i have no question (at least not more). Your code snipped was the one missing piece for me, many thanks for that (I'm creating a dns based multi zone eureka setup).
Regarding Autowiring: You need an instance of InetUtils for the public ctor of EurekaInstanceConfigBean (and that is autowired, an instance of InetUtils is created by autoconfig). Your code shouldn't compile, the no-args ctor is private (see https://github.com/spring-cloud/spring-cloud-netflix/blob/master/spring-cloud-netflix-eureka-client/src/main/java/org/springframework/cloud/netflix/eureka/EurekaInstanceConfigBean.java#L284 ).
Regarding @EnableEurekaServer: A eureka server is also a eureka client (used for the registered vs available stuff), so i had a eureka client problem but for a eureka server.
Never mind, works perfect now. Thanks again for your help.
Comment From: rozhok
@DirkLachowski sorry bud, thought you have issues with my snippet :) Btw, I took my sample from actual code, maybe it compiles because I use a bit old version of spring-cloud-netflix.
Comment From: richardvaldiviesomacias
I am having an issue that might be related. I deployed my eureka service and my services that supposed to connect but without look.
Here is the config in my eureka-service:
spring.application.name=eureka-service eureka.client.register-with-eureka=false eureka.client.fetch-registry=false eureka.server.enableSelfPreservation=true
And here is one of my client:
eureka.client.service-url.default-zone = ${EUREKA_URI:https://myapp.cfapps.io/eureka} eureka.instance.[nonSecurePortEnabled,securePortEnabled] = [false, true] eureka.instance.hostname=${vcap.application.uris[0]}
I can see the eureka page but not service register. Could someone help me please?
Comment From: rozhok
@richardvaldiviesomacias You probably misconfigured eureka ip on the client side.
${EUREKA_URI:https://myapp.cfapps.io/eureka} ?
Is this expression points to actual eureka ip?
Comment From: ryanjbaxter
@richardvaldiviesomacias please open a new issue for your problem
Comment From: hussainssabir
@rozhok @DirkLachowski : Thanks, Worked for me as well on AWS.
This is my config without "DNS".
eureka: datacenter: cloud client: registerWithEureka: true fetchRegistry: true region: eu-west-1 eurekaServerPort: ${server.port} useDnsForFetchingServiceUrls: false availabilityZones: eu-west-1: 'eu-west-1a,eu-west-1b,eu-west-1c' serviceUrl: eu-west-1a: http:/myelasticIp-west-1.compute.amazonaws.com:${server.port}/eureka eu-west-1b: http://myelasticIp-west-1.compute.amazonaws.com:${server.port}/eureka eu-west-1c: http://myelasticIp-west-1.compute.amazonaws.com:${server.port}/eureka
Comment From: bsushant-athena
@hussainssabir is it possible for you to share repo?
Comment From: YogeshMCA
Works for me (no config needed for hostname). What version of Spring Cloud are you using? Are you adding your own
EurekaInstanceConfigbean or just using the default? Here's a eureka on PWS (username:password) that shows it working: http://eureka.cfapps.io/eureka/apps/configserver.
Could you please share, which version is suitable?
Comment From: YogeshMCA
@ryanjbaxter I am also using the service registry from PCF marketplace. But i couldn't able to register my client in eureka server. could you please share the yml config file and also share the working project repository if you have
Comment From: ryanjbaxter
That is something different. The service registry from the PCF marketplace is our productized version of Spring Cloud called Spring Cloud Services. Is you are having an issue with that then you should reach out to https://pivotal.io/support
Comment From: YogeshMCA
@ryanjbaxter Thanks for your quick response... Actually i have created the Service Registry from PCF marketplace and bind my application to that service. But still i couldn't see my client application in eureka service registry. Do we have to mention the eureka service details in client application.yml file. Please share what are all the things that needs to be configured in client application.
Comment From: spencergibb
Please see the appropriate documentation of the commercial project https://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/index.html
Comment From: YogeshMCA
@ryanjbaxter It is working now.. Eureka client got registered in PCF service Registry. But when i am trying to communicate b/w two client which is registered in service registry, am getting "com.netflix.client.ClientException: Load balancer does not have available server for client: currexchange"
Note: Am using @FeignClient("https://currexchange"). Please suggest me how to use FeginClient with service registry.
Thanks in advance!!
Comment From: ryanjbaxter
There are plenty of examples in our documentation, please read the documentation and if you are still having an issue open an issues in Spring Cloud OpenFeign
Comment From: magixsource
@Component
public class PodEnvironmentAware implements EnvironmentAware {
private static final Logger LOGGER = LoggerFactory.getLogger(PodEnvironmentAware.class);
@Override
public void setEnvironment(Environment environment) {
Properties props = new Properties();
try {
props.setProperty("POD_OWN_IP_ADDRESS", InetAddress.getLocalHost().getHostAddress());
PropertiesPropertySource propertySource = new PropertiesPropertySource("K8S", props);
if (environment instanceof StandardEnvironment) {
((StandardEnvironment) environment).getPropertySources().addFirst(propertySource);
}
} catch (UnknownHostException e) {
LOGGER.warn("Could not get k8s pod ip address.");
}
}
}
spring:
cloud:
client:
hostname: ${POD_OWN_IP_ADDRESS:localhost}
:) it's works
Comment From: wsingleton
I managed to solve this issue by implementing a BeanPostProcessor that intercepted the EurekaInstanceConfigBean during the postProcessAfterInitialization lifecycle hook so I could manually set the instance id, IP address, hostname, status page URL, and health check URL using the host address of the Fargate instance that the task is running on. Below is the implementation I came up with:
@Component
@Profile("fargate")
public class EurekaInstanceConfigBeanPostProcessor implements BeanPostProcessor {
private static final Logger LOGGER = LoggerFactory.getLogger(EurekaInstanceConfigBeanPostProcessor.class);
@Value("${spring.application.name}")
private String serviceName;
@Value("${server.port}")
private int port;
private String fargateIp;
public EurekaInstanceConfigBeanPostProcessor() {
try {
fargateIp = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
LOGGER.warn("Could not get the Fargate instance ip address.");
}
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof EurekaInstanceConfigBean) {
LOGGER.info("EurekaInstanceConfigBean detected. Setting IP address to {}", fargateIp);
EurekaInstanceConfigBean instanceConfigBean = ((EurekaInstanceConfigBean) bean);
instanceConfigBean.setInstanceId(fargateIp + ":" + serviceName + ":" + port);
instanceConfigBean.setIpAddress(fargateIp);
instanceConfigBean.setHostname(fargateIp);
instanceConfigBean.setStatusPageUrl("http://" + fargateIp + ":" + port + "/actuator/info");
instanceConfigBean.setHealthCheckUrl("http://" + fargateIp + ":" + port + "/actuator/info");
}
return bean;
}
}
I ran into the same issue working with ECS/Fargate on AWS, but this might be a solution that works regardless of the cloud provider.