{"id":284,"date":"2019-05-02T00:19:14","date_gmt":"2019-05-02T07:19:14","guid":{"rendered":"http:\/\/vinodsr.com\/myblog\/?p=284"},"modified":"2020-04-24T05:08:12","modified_gmt":"2020-04-24T12:08:12","slug":"eureka-and-aws-ecs","status":"publish","type":"post","link":"https:\/\/vinodsr.com\/myblog\/2019\/05\/eureka-and-aws-ecs\/","title":{"rendered":"Eureka and AWS ECS"},"content":{"rendered":"<p>Reading time : [est_time]<\/p>\n<blockquote><p><em>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.<\/em><\/p><\/blockquote>\n<h1>What is Eureka<\/h1>\n<p><a href=\"https:\/\/spring.io\/guides\/gs\/service-registration-and-discovery\/\">Eureka<\/a> is the service discovery engine, which is used in the netflix microservice&nbsp;stack. Netflix stack is based on java and it is now integrated with&nbsp;<a href=\"https:\/\/cloud.spring.io\/spring-cloud-static\/spring-cloud.html#_spring_cloud_netflix\" target=\"_blank\" rel=\"noopener noreferrer\">spring cloud ecosystem<\/a>.&nbsp; 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.<\/p>\n<h1>Problem with AWS ECS<\/h1>\n<p>Eureka works fine if integrated in any local environment. But when we deploy it to&nbsp;<a href=\"https:\/\/docs.aws.amazon.com\/AmazonECS\/latest\/developerguide\/Welcome.html\" target=\"_blank\" rel=\"noopener noreferrer\">AWS ECS<\/a>,&nbsp; 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.<\/p>\n<h1>Solution<\/h1>\n<p>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.<\/p>\n<p>In order to get the public ip of the ec2, we just need to call a url hosted by AWS &#8220;<a href=\"http:\/\/169.254.169.254\/latest\/meta-data\/local-ipv4\">http:\/\/169.254.169.254\/latest\/meta-data\/local-ipv4<\/a>&#8221; which returns the public ip of the calling ec2 instance.<\/p>\n<p>For getting the exposed port, we will use a spotify&#8217;s&nbsp;<a href=\"https:\/\/github.com\/spotify\/docker-client\" target=\"_blank\" rel=\"noopener noreferrer\">docker library<\/a>, which gives the container details.<\/p>\n<p>Add the below dependencies to the build.gradle<\/p>\n<pre class=\"theme:eclipse lang:default decode:true\">dependencies {\n  compile (\"com.spotify:docker-client:8.13.0\")\n}\n<\/pre>\n<p>Then you need to create the below configuration class.<\/p>\n<pre class=\"theme:eclipse lang:java decode:true\">@Configuration\npublic class EurekaCustomConfiguration {\n\n@Bean\npublic EurekaInstanceConfigBean eurekaInstanceConfig(\nfinal InetUtils inetUtils) {\n\n\/\/ You can move this to application.properties\nfinal String applicationPort = 8080;\nfinal String awsHostIPUrl = \"http:\/\/169.254.169.254\/latest\/meta-data\/local-ipv4\";\n\n\nfinal EurekaInstanceConfigBean eurekaConfig =\nnew EurekaInstanceConfigBean(inetUtils);\ntry {\nfinal AmazonInfo serviceInfo =\nAmazonInfo.Builder.newBuilder().autoBuild(\"eureka\");\neurekaConfig.setDataCenterInfo(serviceInfo);\nfinal DockerClient docker = DefaultDockerClient.fromEnv().build();\n\n\/\/ Get the current container Id.\nfinal String containerId = containerId();\nif (StringUtils.isEmpty(containerId)) {\nreturn null;\n}\n\n\/\/ Get the exported port of the container\nfinal ContainerInfo contInfo = docker.inspectContainer(containerId);\nfinal List&lt;PortBinding&gt; exportedPorts =\ncontInfo.networkSettings().ports().get(applicationPort + \"\/tcp\");\nif (exportedPorts.isEmpty()) {\n\/\/ No ports have been exported\nreturn null;\n}\n\nfinal int hostPort = Integer.parseInt(outsidePorts.get(0).hostPort());\n\n\/**\n* We are using AWS method to get the private IP of the host as the docker\n* client returns the IP 0.0.0.0 unless specified.\n*\/\neurekaConfig.setIpAddress(getContent(awsHostIPUrl));\neurekaConfig.setNonSecurePort(hostPort);\neurekaConfig.setInstanceId(UUID.randomUUID().toString()); \/\/ any random id.\n} catch (final Exception e) {\n\/\/ handle the error\nreturn null;\n}\n\nreturn eurekaConfig;\n}\n\n\nprivate static String containerId() {\ntry (InputStream inputStream = Files.newInputStream(Paths.get(\"\/etc\/hostname\"));\nInputStreamReader inputStreamReader =\nnew InputStreamReader(inputStream, Charset.forName(\"UTF-8\"));\nBufferedReader bufferedReader = new BufferedReader(inputStreamReader)) {\nreturn bufferedReader.readLine().trim();\n} catch (final IOException exception) {\nreturn System.getenv(\"HOSTNAME\");\n}\n}\n\n\npublic static String getContent(final String url)\nthrows IOException, IllegalArgumentException {\nfinal RestTemplate restTemplate = new RestTemplate();\nreturn restTemplate.getForObject(url, String.class);\n\n}\n}<\/pre>\n<p>Now go and check the eureka&#8217;s dashboard.&nbsp; You will see the external IP and port for the microservice.<\/p>\n<blockquote><p><span style=\"font-family: 'Scope One';\"><strong>Eureka !!!<\/strong><\/span><\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>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&hellip;<\/p>\n","protected":false},"author":1,"featured_media":290,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[66],"tags":[70,71,72,69,68,67],"class_list":["post-284","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-microservice","tag-aws","tag-awsecs","tag-docker","tag-eureka","tag-microservice","tag-netflix","has-post-thumbnail-archive"],"aioseo_notices":[],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/posts\/284","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/comments?post=284"}],"version-history":[{"count":6,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/posts\/284\/revisions"}],"predecessor-version":[{"id":303,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/posts\/284\/revisions\/303"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/media\/290"}],"wp:attachment":[{"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/media?parent=284"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/categories?post=284"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vinodsr.com\/myblog\/wp-json\/wp\/v2\/tags?post=284"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}