How to register spring boot microservices on spring cloud Netflix eureka? - spring-boot

We were planning to use spring cloud Netflix oss components. So I was doing a small sample project.
I developed 2 spring microservices and those services runs well on
http://localhost:9000/microsvc-one http://localhost:9001/microsvc-two
And also wrote a sample spring cloud etflix eureka maven project which runs well on
http://localhost:8761
I used annotations #EurekaDiscoveryClient and #SpringBootApplication on both the spring boot microservices main class
I used annotation #EnableEurekaServer and #SpringBootApplication
Now I am facing a problem in registering those services in eureka server. I referred some samples. I am not understanding those.
I did some changes in application.yml files of microsvc-one and microsvc-two and also application.yml file of eureka server.
But still it shows empty.
What all changes are required or missing or correct configuration to be done so that my services are being registered on eureka.
I also have other question like do i need to create a separate project which has #EnableConfigServer and #SpringBootApplication Annotations other than the above 2 microservices and eureka server project module to register the services on eureka.
I see those in most of the examples.
If yes..how do we link between all these?

If you are using springBoot application you will need the annotaion #SpringBootApplication thats why that annotation is there on the project you are seeing. #EnableConfigServer is when you are using the spring-cloud config server it is used to externalize the configuration properties but since you have the application.yml inside the project so you donot need that either.
I am thinking you have a spring boot application for both Microservices and the Eureka server. You need to annotate the eureka main class with
#SpringBootApplication
#EnableEurekaServer
#EnableDiscoveryClient
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
Additionally you need annotate you microservice's main class with..
#SpringBootApplication
#EnableDiscoveryClient
public class MicroApplication {
public static void main(String[] args) {
SpringApplication.run(MicroApplication.class, args);
}
}
Since you donot have you application.yml file in the question here is what you need.
You need the below configuration in application.yml of the microservices.
eureka:
client:
serviceUrl:
defaultZone: ${eurekaurl:http://localhost:8761/eureka/}
In the Eureka Server application.yml file I have this in mine. you might need to tweak it based on what you want.
info:
component: Registry Server
server:
port: ${port:8761}
eureka:
client:
registerWithEureka: false
fetchRegistry: false
server:
enable-self-preservation: false
waitTimeInMsWhenSyncEmpty: 0
instance:
hostname: localhost
lease-expiration-duration-in-seconds: 15
lease-renewal-interval-in-seconds: 5

Suppose you have a microservice named "LoginServer" now, let's see how to register this service with discovery server (Eureka Server) at startup.
Here Spring Boot startup class of LoginServer.java:
#EnableAutoConfiguration
#EnableDiscoveryClient
public class LoginServer {
public static void main(String[] args) {
// Will configure using login-server.yml
System.setProperty("spring.config.name", "login-server");
SpringApplication.run(LoginServer.class, args);
}
}
The #EnableDiscoveryClient - enables service registration and discovery. In this case, this process registers itself with the discovery-server service using its application name, that is configured in YML configuration file.
let's see the complete setup:
First create a login-server.yml (any name but extension should be .yml) file into src/main/resources package folder. And write those configurations and save.
# Spring properties
spring:
application:
name: login-server # This name used as ID so ("spring.config.name",
#"login-server"); must be same.
# Discovery Server Access
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1111/eureka/
# HTTP Server
server:
port: 2222 # HTTP (Tomcat) port
Run the LoginServer and let it finish initializing. Open the dashboard by putting this URL http://localhost:1111 in your favorite browser and refresh. After few seconds later you should see the LOGIN-SERVER. Generally registration takes up to 30 seconds (by default) so wait or restart.
And this is the microservice complete registration process.

Related

Why #LoadBalanced annotation is necessary while using RestTemplate and eureka server for service discovery

I have two microservices deployed and a eureka server. The microservices are eureka clients, viz, eureka-client-1 and eureka-client-2 respectively.
Using, service discovery, I want to call an API from eureka-client-1 of eureka-client-2.
Following is the supported code and configurations:
discovery-server (eureka server) configuration:
server:
port: 8761
eureka:
client:
fetch-registry: false
register-with-eureka: false
spring:
application:
name: discovery-server
eureka-client-1 and eureka-client-2 have same configurations:
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
In eureka-client-1 I am using RestTemplate to communicate with the eureka-client-2
Notice that I have currently commented the LoadBalanced annotation.
#Bean
// #LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
I access the api of eureka-client-2 as follows:
restTemplate.getForObject(
"http://EUREKA-CLIENT-2/api/v1/check/{customerId}", Response.class, customer.getId());
When I deploy and test the application, I am getting UnknownHostException for EUREKA-CLIENT-2. But, as soon as I enable the annotation #LoadBalanced everything works fine and eureka-client-1 can successfully communicate with eureka-client-2.
My question is: Why #LoadBalanced annotation is absolutely compulsory? If I have deployed only single instances of each microservices, why can't the discovery-server return the information of the only service with given name that is deployed? And even if same service is deployed multiple times, why it can't internally apply the loadbalancing algorithm? Why the client has to specifically add the annotation

Feign Client Prioritizing URL's in yaml over Eureka

I have a Spring Boot application which serves as a Eureka client. The application has the need to call another micro-service through REST, and I wish to make this call using Feign. The issue I am having is, my application is trying to lookup the service name in Eureka, when it is only defined in my applications yaml file.
I apologize for the hard to follow explanation, hopefully the following code snippets will help clarify.
Feign client:
#FeignClient("foo")
#Component
public interface FooServiceProxy{
#RequestMapping(value = "/balance", method = RequestMethod.POST, produces = "application/json")
ServiceResponse execute(ServiceRequest serviceRequest);
}
In my controller who calls this Feign client, the FooServiceProxy is defined using #AutoWired:
#Autowired
private FooServiceProxy fooServiceProxy;
My yaml file is as follows:
spring:
application:
name: app-name
server:
port: 8080
foo:
ribbon:
listOfServers: http://hostname:8081/balance
eureka:
client:
fetchRegistry: false
serviceUrl:
defaultZone: http://eurekasrver:8761/eureka/
My issue is, during run-time, the following error is thrown:
java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: foo
Interestingly, if I remove the #EnableEurekaClient annotation from the application, everything works. I believe I understand the problem which is that instead of looking up the server for foo in my yaml file, because the application is a Eureka client, Feign is going straight to Eureka to lookup a server ip, then failing as none can be found. Despite seeming to understand the problem, I have been unable to find a solution online or to think of one myself.
Any help will be appreciated.
Thank you!
Concerning this question, you should take in account that when eureka is on your classpath, all ribbon configuration are charged by eureka, so it'll use eureka server's list.
Spring Cloud uses #RibbonClient to configure the types used by ribbon, like server list. If you have eureka on the classpath, by default it uses the eureka server list (hence your need for the flag to disable eureka).
Commented by spencergibb https://github.com/spring-cloud/spring-cloud-netflix/issues/564
You can try either by adding the NIWSServerListClassName configuration:
`someservice.ribbon:
NIWSServerListClassName:com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: server1:80`
Or try the solution proposed in this issue https://github.com/spring-cloud/spring-cloud-netflix/issues/564

Spring Config-Client doesn't refresh if Config-Server is down during initial startup

I am running a test with a barebones Spring cloud config-server and a client-application. I executed a refresh scenario (by calling /refresh endpoint on the client-application)
after config-server was down initially. Here is what I found
Client starts up with locally packaged properties when config-server is not reachable on startup. (I have the properties in application.yml that is bundled with client-application)
Git backend has different values for the properties compared to locally packaged version. Config-server is aware of the changes in git (Confirmed by connecting directly to config-server)
I bring up config-server and do a POST to /refresh endpoint on the client-application.
Client-application is not aware of the new properties from config-server.
In the second usecase
Client-application starts up and connects to config-server successfully. I see that the values from config-server have been fetched by the client-application successfully
I make a change in Git and call the /refresh endpoint on the client-application. Properties are refreshed successfully.
At this point it looks like /refresh doesn't work if the client-application comes up initially without being able to successfully connect to config-server. I am doing this to test
a fallback strategy for the client-application if config-server is not reachable when the client-application is starting up. (The fallback strategy is to have locally packaged properties
that will be used if config-server is not available on startup. If the config-server is available then the local properties are overriden). Any pointers to why this is not working and
what I could do differently? Thanks in advance.
Edit
Server-Code
#EnableConfigServer
#SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
Client-Code
#RestController
#RefreshScope
#Component
public class Greeter {
#Value("${message.greeting}")
String greeting;
#RequestMapping(value = "/",produces = "application/json")
public List<String> index(){
List<String> env = Arrays.asList("message.greeting: " + greeting);
return env;
}
}
bootstrap.yml (On config-client application)
spring:
application:
name: configclient
cloud:
config:
uri: http://localhost:8888
management:
security:
enabled: false
logging:
config: classpath:logback.xml
server:
port: 8000
application.yml
message:
greeting: Hello from Local!
Config in Git (Served through config-server)
message:
greeting: Hello from Git-Edited!
According to spring-cloud-config documentation -
If you expect that the config server may occasionally be unavailable
when your app starts, you can ask it to keep trying after a failure.
First you need to set spring.cloud.config.failFast=true, and then you
need to add spring-retry and spring-boot-starter-aop to your
classpath. The default behaviour is to retry 6 times with an initial
backoff interval of 1000ms and an exponential multiplier of 1.1 for
subsequent backoffs. You can configure these properties (and others)
using spring.cloud.config.retry.* configuration properties.
Reference -> http://cloud.spring.io/spring-cloud-static/spring-cloud-config/1.3.1.RELEASE/

Eureka on spring-cloud-netflix with DNS based config, all instances showing up as unavailable

I'm trying to setup a eureka cluster on aws with DNS-based EIP configuration as described at https://github.com/Netflix/eureka/wiki/Configuring-Eureka-in-AWS-Cloud
Everything seems to work, but the eureka dashboard insists that the eureka instances are unavailable. I'm now wondering if this is only an ui problem (i think so) or if i'm missing something.
As i understand the "unavailable-replicas" logic in the dashboard this is because eureka is comparing the registration hostname and the replica hostname. The instances register with their internal VPC ip at the discovery client but with their EIP when looking for replica peers (strange enough, in the eureka log i can see internaly they are also using the internal VPC ip).
The question is: Is that only some cosmetic ui problem that i shouldn't worry about or are bigger problems waiting to step in because of some misconfiguration? If it's only an ui thing: can i "repair" that somehow?
Edit:
Maybe related https://github.com/spring-cloud/spring-cloud-netflix/issues/102#issuecomment-74446709
With the help of #rozhok in the related github issue i now have a working solution. If anyone is facing the same problem, here's what i've done:
application.yml
eureka:
datacenter: cloud
client:
eurekaServerDNSName: your.dns.name
eurekaServerPort: 8761
eurekaServerURLContext: eureka
region: eu-west-1
registerWithEureka: true
fetchRegistry: true
useDnsForFetchingServiceUrls: true
server:
waitTimeInMsWhenSyncEmpty: 0
enableSelfPreservation: true
EurekaServer
#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 eurekaInstanceConfigBean(InetUtils inetUtils) {
EurekaInstanceConfigBean config = new EurekaInstanceConfigBean(inetUtils);
AmazonInfo info = AmazonInfo.Builder.newBuilder().autoBuild("eureka");
// Don't use spring cloud's hostname here.
// See comment below by Michal
config.setHostname(
info.get(AmazonInfo.MetaDataKey.publicHostname));
config.setIpAddress(info.get(AmazonInfo.MetaDataKey.publicIpv4));
config.setNonSecurePort(port);
config.setDataCenterInfo(info);
return config;
}
}
With that configuration each eureka server sees only the other servers as available replicas:

Port binding for Spring RESTful Web Service

I've used the Building a RESTful Web Service tutorial to build a WebService for my purpose. It was quite easy, but now I'm struggeling to configure the port the WebService should be binded through. There is no config.xml or anything to configure in this project. Can anyone give me a hint about how to configure the WebService's port?
As these details might be helpful. I'm starting the server with the code below, containing the #EnableAutoConfiguration tag. The configuration is done by Spring Boot.
#ComponentScan
#EnableAutoConfiguration
public class ServerStarter{
public static void main(String[] args) {
SpringApplication.run(ServerStarter.class, args);
}
}
To configure the ports you can set the server.port and management.port properties by writing the following in the "application.properties" file located under "src/main/resources":
server.port = 9000
management.port = 9001
Similarly if you need to specify the management address:
management.address = 127.0.0.1
There are more properties you can set for the server and management server. See spring-boot's documentation: http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/
For a quick and dirty solution you can employ the command line option arguments (source):
--server.port=9000

Resources