78 lines
16 KiB
HTML
78 lines
16 KiB
HTML
<html><head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
<title>67. Service Discovery with Consul</title><link rel="stylesheet" type="text/css" href="css/manual-multipage.css"><meta name="generator" content="DocBook XSL Stylesheets V1.78.1"><link rel="home" href="multi_spring-cloud.html" title="Spring Cloud"><link rel="up" href="multi__spring_cloud_consul.html" title="Part IX. Spring Cloud Consul"><link rel="prev" href="multi_spring-cloud-consul-agent.html" title="66. Consul Agent"><link rel="next" href="multi_spring-cloud-consul-config.html" title="68. Distributed Configuration with Consul"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">67. Service Discovery with Consul</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="multi_spring-cloud-consul-agent.html">Prev</a> </td><th width="60%" align="center">Part IX. Spring Cloud Consul</th><td width="20%" align="right"> <a accesskey="n" href="multi_spring-cloud-consul-config.html">Next</a></td></tr></table><hr></div><div class="chapter"><div class="titlepage"><div><div><h2 class="title"><a name="spring-cloud-consul-discovery" href="#spring-cloud-consul-discovery"></a>67. Service Discovery with Consul</h2></div></div></div><p>Service Discovery is one of the key tenets of a microservice based architecture. Trying to hand configure each client or some form of convention can be very difficult to do and can be very brittle. Consul provides Service Discovery services via an <a class="link" href="https://www.consul.io/docs/agent/http.html" target="_top">HTTP API</a> and <a class="link" href="https://www.consul.io/docs/agent/dns.html" target="_top">DNS</a>. Spring Cloud Consul leverages the HTTP API for service registration and discovery. This does not prevent non-Spring Cloud applications from leveraging the DNS interface. Consul Agents servers are run in a <a class="link" href="https://www.consul.io/docs/internals/architecture.html" target="_top">cluster</a> that communicates via a <a class="link" href="https://www.consul.io/docs/internals/gossip.html" target="_top">gossip protocol</a> and uses the <a class="link" href="https://www.consul.io/docs/internals/consensus.html" target="_top">Raft consensus protocol</a>.</p><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_how_to_activate" href="#_how_to_activate"></a>67.1 How to activate</h2></div></div></div><p>To activate Consul Service Discovery use the starter with group <code class="literal">org.springframework.cloud</code> and artifact id <code class="literal">spring-cloud-starter-consul-discovery</code>. See the <a class="link" href="http://projects.spring.io/spring-cloud/" target="_top">Spring Cloud Project page</a> for details on setting up your build system with the current Spring Cloud Release Train.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_registering_with_consul" href="#_registering_with_consul"></a>67.2 Registering with Consul</h2></div></div></div><p>When a client registers with Consul, it provides meta-data about itself such as host and port, id, name and tags. An HTTP <a class="link" href="https://www.consul.io/docs/agent/checks.html" target="_top">Check</a> is created by default that Consul hits the <code class="literal">/health</code> endpoint every 10 seconds. If the health check fails, the service instance is marked as critical.</p><p>Example Consul client:</p><pre class="programlisting"><em><span class="hl-annotation" style="color: gray">@SpringBootApplication</span></em>
|
|
<em><span class="hl-annotation" style="color: gray">@RestController</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span> Application {
|
|
|
|
<em><span class="hl-annotation" style="color: gray">@RequestMapping("/")</span></em>
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> String home() {
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">return</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-string">"Hello world"</span>;
|
|
}
|
|
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">public</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">static</span> <span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">void</span> main(String[] args) {
|
|
<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">new</span> SpringApplicationBuilder(Application.<span xmlns:d="http://docbook.org/ns/docbook" class="hl-keyword">class</span>).web(true).run(args);
|
|
}
|
|
|
|
}</pre><p>(i.e. utterly normal Spring Boot app). If the Consul client is located somewhere other than <code class="literal">localhost:8500</code>, the configuration is required to locate the client. Example:</p><p><b>application.yml. </b>
|
|
</p><pre class="screen">spring:
|
|
cloud:
|
|
consul:
|
|
host: localhost
|
|
port: 8500</pre><p>
|
|
</p><div class="caution" style="margin-left: 0.5in; margin-right: 0.5in;"><table border="0" summary="Caution"><tr><td rowspan="2" align="center" valign="top" width="25"><img alt="[Caution]" src="images/caution.png"></td><th align="left">Caution</th></tr><tr><td align="left" valign="top"><p>If you use <a class="link" href="multi_spring-cloud-consul-config.html" title="68. Distributed Configuration with Consul">Spring Cloud Consul Config</a>, the above values will need to be placed in <code class="literal">bootstrap.yml</code> instead of <code class="literal">application.yml</code>.</p></td></tr></table></div><p>The default service name, instance id and port, taken from the <code class="literal">Environment</code>, are <code class="literal">${spring.application.name}</code>, the Spring Context ID and <code class="literal">${server.port}</code> respectively.</p><p>To disable the Consul Discovery Client you can set <code class="literal">spring.cloud.consul.discovery.enabled</code> to <code class="literal">false</code>.</p><p>To disable the service registration you can set <code class="literal">spring.cloud.consul.discovery.register</code> to <code class="literal">false</code>.</p></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_http_health_check" href="#_http_health_check"></a>67.3 HTTP Health Check</h2></div></div></div><p>The health check for a Consul instance defaults to "/health", which is the default locations of a useful endpoint in a Spring Boot Actuator application. You need to change these, even for an Actuator application if you use a non-default context path or servlet path (e.g. <code class="literal">server.servletPath=/foo</code>) or management endpoint path (e.g. <code class="literal">management.server.servlet.context-path=/admin</code>). The interval that Consul uses to check the health endpoint may also be configured. "10s" and "1m" represent 10 seconds and 1 minute respectively. Example:</p><p><b>application.yml. </b>
|
|
</p><pre class="screen">spring:
|
|
cloud:
|
|
consul:
|
|
discovery:
|
|
healthCheckPath: ${management.server.servlet.context-path}/health
|
|
healthCheckInterval: 15s</pre><p>
|
|
</p><p>You can disable the health check by setting <code class="literal">management.health.consul.enabled=false</code>.</p><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_metadata_and_consul_tags" href="#_metadata_and_consul_tags"></a>67.3.1 Metadata and Consul tags</h3></div></div></div><p>Consul does not yet support metadata on services. Spring Cloud’s <code class="literal">ServiceInstance</code> has a <code class="literal">Map<String, String> metadata</code> field. Spring Cloud Consul uses Consul tags to approximate metadata until Consul officially supports metadata. Tags with the form <code class="literal">key=value</code> will be split and used as a <code class="literal">Map</code> key and value respectively. Tags without the equal <code class="literal">=</code> sign, will be used as both the key and value.</p><p><b>application.yml. </b>
|
|
</p><pre class="screen">spring:
|
|
cloud:
|
|
consul:
|
|
discovery:
|
|
tags: foo=bar, baz</pre><p>
|
|
</p><p>The above configuration will result in a map with <code class="literal">foo→bar</code> and <code class="literal">baz→baz</code>.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_making_the_consul_instance_id_unique" href="#_making_the_consul_instance_id_unique"></a>67.3.2 Making the Consul Instance ID Unique</h3></div></div></div><p>By default a consul instance is registered with an ID that is equal to its Spring Application Context ID. By default, the Spring Application Context ID is <code class="literal">${spring.application.name}:comma,separated,profiles:${server.port}</code>. For most cases, this will allow multiple instances of one service to run on one machine. If further uniqueness is required, Using Spring Cloud you can override this by providing a unique identifier in <code class="literal">spring.cloud.consul.discovery.instanceId</code>. For example:</p><p><b>application.yml. </b>
|
|
</p><pre class="screen">spring:
|
|
cloud:
|
|
consul:
|
|
discovery:
|
|
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}</pre><p>
|
|
</p><p>With this metadata, and multiple service instances deployed on localhost, the random value will kick in there to make the instance unique. In Cloudfoundry the <code class="literal">vcap.application.instance_id</code> will be populated automatically in a Spring Boot application, so the random value will not be needed.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_applying_headers_to_health_check_requests" href="#_applying_headers_to_health_check_requests"></a>67.3.3 Applying Headers to Health Check Requests</h3></div></div></div><p>Headers can be applied to health check requests. For example, if you’re trying to register a <a class="link" href="https://cloud.spring.io/spring-cloud-config/" target="_top">Spring Cloud Config</a> server that uses <a class="link" href="https://github.com/spring-cloud/spring-cloud-config/blob/master/docs/src/main/asciidoc/spring-cloud-config.adoc#vault-backend" target="_top">Vault Backend</a>:</p><p><b>application.yml. </b>
|
|
</p><pre class="screen">spring:
|
|
cloud:
|
|
consul:
|
|
discovery:
|
|
health-check-headers:
|
|
X-Config-Token: 6442e58b-d1ea-182e-cfa5-cf9cddef0722</pre><p>
|
|
</p><p>According to the HTTP standard, each header can have more than one values, in which case, an array can be supplied:</p><p><b>application.yml. </b>
|
|
</p><pre class="screen">spring:
|
|
cloud:
|
|
consul:
|
|
discovery:
|
|
health-check-headers:
|
|
X-Config-Token:
|
|
- "6442e58b-d1ea-182e-cfa5-cf9cddef0722"
|
|
- "Some other value"</pre><p>
|
|
</p></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_looking_up_services" href="#_looking_up_services"></a>67.4 Looking up services</h2></div></div></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_ribbon" href="#_using_ribbon"></a>67.4.1 Using Ribbon</h3></div></div></div><p>Spring Cloud has support for <a class="link" href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-feign" target="_top">Feign</a> (a REST client builder) and also <a class="link" href="https://github.com/spring-cloud/spring-cloud-netflix/blob/master/docs/src/main/asciidoc/spring-cloud-netflix.adoc#spring-cloud-ribbon" target="_top">Spring <code class="literal">RestTemplate</code></a>
|
|
for looking up services using the logical service names/ids instead of physical URLs. Both Feign and the discovery-aware RestTemplate utilize <a class="link" href="http://cloud.spring.io/spring-cloud-netflix/single/spring-cloud-netflix.html#spring-cloud-ribbon" target="_top">Ribbon</a> for client-side load balancing.</p><p>If you want to access service STORES using the RestTemplate simply declare:</p><pre class="screen">@LoadBalanced
|
|
@Bean
|
|
public RestTemplate loadbalancedRestTemplate() {
|
|
new RestTemplate();
|
|
}</pre><p>and use it like this (notice how we use the STORES service name/id from Consul instead of a fully qualified domainname):</p><pre class="screen">@Autowired
|
|
RestTemplate restTemplate;
|
|
|
|
public String getFirstProduct() {
|
|
return this.restTemplate.getForObject("https://STORES/products/1", String.class);
|
|
}</pre><p>If you have Consul clusters in multiple datacenters and you want to access a service in another datacenter a service name/id alone is not enough. In that case
|
|
you use property <code class="literal">spring.cloud.consul.discovery.datacenters.STORES=dc-west</code> where <code class="literal">STORES</code> is the service name/id and <code class="literal">dc-west</code> is the datacenter
|
|
where the STORES service lives.</p></div><div class="section"><div class="titlepage"><div><div><h3 class="title"><a name="_using_the_discoveryclient" href="#_using_the_discoveryclient"></a>67.4.2 Using the DiscoveryClient</h3></div></div></div><p>You can also use the <code class="literal">org.springframework.cloud.client.discovery.DiscoveryClient</code> which provides a simple API for discovery clients that is not specific to Netflix, e.g.</p><pre class="screen">@Autowired
|
|
private DiscoveryClient discoveryClient;
|
|
|
|
public String serviceUrl() {
|
|
List<ServiceInstance> list = discoveryClient.getInstances("STORES");
|
|
if (list != null && list.size() > 0 ) {
|
|
return list.get(0).getUri();
|
|
}
|
|
return null;
|
|
}</pre></div></div><div class="section"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="_consul_catalog_watch" href="#_consul_catalog_watch"></a>67.5 Consul Catalog Watch</h2></div></div></div><p>The Consul Catalog Watch takes advantage of the ability of consul to <a class="link" href="https://www.consul.io/docs/agent/watches.html#services" target="_top">watch services</a>. The Catalog Watch makes a blocking Consul HTTP API call to determine if any services have changed. If there is new service data a Heartbeat Event is published.</p><p>To change the frequency of when the Config Watch is called change <code class="literal">spring.cloud.consul.config.discovery.catalog-services-watch-delay</code>. The default value is 1000, which is in milliseconds. The delay is the amount of time after the end of the previous invocation and the start of the next.</p><p>To disable the Catalog Watch set <code class="literal">spring.cloud.consul.discovery.catalogServicesWatch.enabled=false</code>.</p><p>The watch uses a Spring <code class="literal">TaskScheduler</code> to schedule the call to consul. By default it is a <code class="literal">ThreadPoolTaskScheduler</code> with a <code class="literal">poolSize</code> of 1. To change the <code class="literal">TaskScheduler</code>, create a bean of type <code class="literal">TaskScheduler</code> named with the <code class="literal">ConsulDiscoveryClientConfiguration.CATALOG_WATCH_TASK_SCHEDULER_NAME</code> constant.</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="multi_spring-cloud-consul-agent.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="multi__spring_cloud_consul.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="multi_spring-cloud-consul-config.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">66. Consul Agent </td><td width="20%" align="center"><a accesskey="h" href="multi_spring-cloud.html">Home</a></td><td width="40%" align="right" valign="top"> 68. Distributed Configuration with Consul</td></tr></table></div></body></html> |