Eureka and AWS ECS

Reading time : [est_time]

Its been long time since i wrote any blogs. I have been tied up with lot of other stuffs. I had decided to continue blogging periodically.

What is Eureka

Eureka is the service discovery engine, which is used in the netflix microservice stack. Netflix stack is based on java and it is now integrated with spring cloud ecosystem.  The service discovery will act like a dns server, where the location (ip and port) for each microservice is stored. If any microservice needs to communicate to another service, it will ask the service discovery ie eureka for the location of the service.

Problem with AWS ECS

Eureka works fine if integrated in any local environment. But when we deploy it to AWS ECS,  which is a docker based container service we will face some problems. Mainly it is due to the IP resolution. The IP which is registered by any service in eureka will be the internal local container IP. This will create problems when eureka is present in a ec2 instance and service in another ec2 instance.

Solution

The solution is to get the instance ip of the ec2 where the container is running and the exported port of the container so that it is possible to connect to the service in different ec2 instances.

In order to get the public ip of the ec2, we just need to call a url hosted by AWS “http://169.254.169.254/latest/meta-data/local-ipv4” which returns the public ip of the calling ec2 instance.

For getting the exposed port, we will use a spotify’s docker library, which gives the container details.

Add the below dependencies to the build.gradle

dependencies {
  compile ("com.spotify:docker-client:8.13.0")
}

Then you need to create the below configuration class.

@Configuration
public class EurekaCustomConfiguration {

@Bean
public EurekaInstanceConfigBean eurekaInstanceConfig(
final InetUtils inetUtils) {

// You can move this to application.properties
final String applicationPort = 8080;
final String awsHostIPUrl = "http://169.254.169.254/latest/meta-data/local-ipv4";


final EurekaInstanceConfigBean eurekaConfig =
new EurekaInstanceConfigBean(inetUtils);
try {
final AmazonInfo serviceInfo =
AmazonInfo.Builder.newBuilder().autoBuild("eureka");
eurekaConfig.setDataCenterInfo(serviceInfo);
final DockerClient docker = DefaultDockerClient.fromEnv().build();

// Get the current container Id.
final String containerId = containerId();
if (StringUtils.isEmpty(containerId)) {
return null;
}

// Get the exported port of the container
final ContainerInfo contInfo = docker.inspectContainer(containerId);
final List<PortBinding> exportedPorts =
contInfo.networkSettings().ports().get(applicationPort + "/tcp");
if (exportedPorts.isEmpty()) {
// No ports have been exported
return null;
}

final int hostPort = Integer.parseInt(outsidePorts.get(0).hostPort());

/**
* We are using AWS method to get the private IP of the host as the docker
* client returns the IP 0.0.0.0 unless specified.
*/
eurekaConfig.setIpAddress(getContent(awsHostIPUrl));
eurekaConfig.setNonSecurePort(hostPort);
eurekaConfig.setInstanceId(UUID.randomUUID().toString()); // any random id.
} catch (final Exception e) {
// handle the error
return null;
}

return eurekaConfig;
}


private static String containerId() {
try (InputStream inputStream = Files.newInputStream(Paths.get("/etc/hostname"));
InputStreamReader inputStreamReader =
new InputStreamReader(inputStream, Charset.forName("UTF-8"));
BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {
return bufferedReader.readLine().trim();
} catch (final IOException exception) {
return System.getenv("HOSTNAME");
}
}


public static String getContent(final String url)
throws IOException, IllegalArgumentException {
final RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject(url, String.class);

}
}

Now go and check the eureka’s dashboard.  You will see the external IP and port for the microservice.

Eureka !!!

Leave a Reply

Your email address will not be published. Required fields are marked *