From 8f5fa467551c8a957956a640f4b187d133821012 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 9 Feb 2015 17:17:49 +0000 Subject: [PATCH] Sync docs from master to gh-pages --- spring-cloud.html | 536 ++++++++++++++++++++++------------------------ 1 file changed, 257 insertions(+), 279 deletions(-) diff --git a/spring-cloud.html b/spring-cloud.html index 7c9d128..0c219e1 100644 --- a/spring-cloud.html +++ b/spring-cloud.html @@ -458,6 +458,7 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Service Discovery: Eureka Clients
  • Circuit Breaker: Hystrix Clients
  • @@ -478,18 +480,16 @@ body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-b
  • Turbine AMQP
  • -
  • Declarative REST Client: Feign - -
  • Client Side Load Balancer: Ribbon
  • +
  • Declarative REST Client: Feign
  • External Configuration: Archaius
  • Router and Filter: Zuul
  • -
  • Spring Cloud for Cloud Foundry - -
  • @@ -1005,6 +996,9 @@ the key value with "@" and provide the file path, e.g.

    AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+... +
    +

    The key argument is mandatory (despite having a -- prefix).

    +

    Key Management

    @@ -1604,7 +1598,10 @@ public class Application {
    -

    (i.e. utterly normal Spring Boot app). Configuration is required to locate the Eureka server. Example:

    +

    (i.e. utterly normal Spring Boot app). In this example we use +@EnableEurekaClient explicitly, but with only Eureka available you +could also use @EnableDiscoveryClient. Configuration is required to +locate the Eureka server. Example:

    application.yml
    @@ -1639,6 +1636,32 @@ ID, or VIP).

    +

    Status Page and Health Indicator

    +
    +

    The status page and health indicators for a Eureka instance default to +"/info" and "/health" respectively, which are the default locations of +useful endpoints 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. server.servletPath=/foo) or management endpoint path +(e.g. management.contextPath=/admin). Example:

    +
    +
    +
    application.yml
    +
    +
    eureka:
    +  instance:
    +    statusPageUrlPath: ${management.contextPath}/info
    +    healthCheckUrlPath: ${management.contextPath}/health
    +
    +
    +
    +

    These links show up in the metadata that is consumers by clients, and +used in some scenarios to decide whether to send requests to your +application, so it’s helpful if they are accurate.

    +
    +
    +

    Making the Eureka Instance ID Unique

    By default a eureka instance is registered with an ID that is equal to its host name (i.e. only one service per host). Using Spring Cloud you can override this by providing a unique identifier in eureka.instance.metadataMap.instanceId. For example:

    @@ -1837,7 +1860,7 @@ exclude it manually, e.g. in Maven

    The Eureka server does not have a backend store, but the service instances in the registry all have to send heartbeats to keep their -resistrations up to date (so this can be done in memory). Clients also +registrations up to date (so this can be done in memory). Clients also have an in-memory cache of eureka registrations (so they don’t have to go to the registry for every single request to a service).

    @@ -1847,6 +1870,10 @@ go to the registry for every single request to a service).

    the service will run and work, but it will shower your logs with a lot of noise about not being able to register with the peer.

    +
    +

    See also below for details of Ribbon +support on the client side for Zones and Regions.

    +

    Standalone Mode

    @@ -1929,6 +1956,15 @@ separated (inside a data centre or between multiple data centres) then the system can in principle survive split-brain type failures.

    +
    +

    Prefer IP Address

    +
    +

    In some cases, it is preferable for Eureka to advertise the IP Adresses +of services rather than the hostname. Set eureka.instance.preferIpAddress +to true and when the application registers with eureka, it will use its +IP Address rather than its hostname.

    +
    +
    @@ -2040,13 +2076,7 @@ for details on the properties available.

    Looking at an individual instances Hystrix data is not very useful in terms of the overall health of the system. Turbine is an application that aggregates all of the relevant /hystrix.stream endpoints into a combined /turbine.stream for use in the Hystrix Dashboard. Individual instances are located via Eureka. Running Turbine is as simple as annotating your main class with the @EnableTurbine annotation.

    -

    Configuration key turbine.appConfig is a list of eureka serviceId’s that turbine will use to lookup instances. And turbine.aggregator.clusterConfig is used to group instances together (from the eureka InstanceInfo). The clusterName is a SPEL expression evaluated against the InstanceInfo. The default clusterNameExpression is appName. The turbine stream is then used in the Hystrix dashboard using a url that looks like: http://my.turbine.sever:8080/turbine.stream?cluster=CUSTOMERS

    -
    -
    -

    The cluster parameter must match an entry in turbine.aggregator.clusterConfig.

    -
    -
    -

    Value returned from eureka are uppercase, thus the examples of all uppercase CUSTOMERS

    +

    Configuration key turbine.appConfig is a list of eureka serviceId’s that turbine will use to lookup instances. The turbine stream is then used in the Hystrix dashboard using a url that looks like: http://my.turbine.sever:8080/turbine.stream?cluster=<CLUSTERNAME>; (the cluster parameter can be omitted if the name is "default"). The cluster parameter must match an entry in turbine.aggregator.clusterConfig. Value returned from eureka are uppercase, thus we expect this example to work if there is an app registered with Eureka called "customers":

    @@ -2057,7 +2087,14 @@ for details on the properties available.

    -

    The clusterName can be customized by a SPEL expression in turbine.clusterNameExpression. For example, turbine.clusterNameExpression=aSGName would get the cluster name from the AWS ASG name.

    +

    The clusterName can be customized by a SPEL expression in turbine.clusterNameExpression. For example, turbine.clusterNameExpression=aSGName would get the cluster name from the AWS ASG name. To use the "default" cluster for all apps you need a string literal expression (with single quotes):

    +
    +
    +
    +
    turbine:
    +  appConfig: customers,stores
    +  clusterNameExpression: 'default'
    +

    Spring Cloud provides a spring-cloud-starter-turbine that has all the dependencies you need to get a Turbine server running. Just create a Spring Boot application and annotate it with @EnableTurbine.

    @@ -2078,72 +2115,6 @@ for details on the properties available.

    -

    Declarative REST Client: Feign

    -
    -
    -

    Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

    -
    -
    -

    Example spring boot app

    -
    -
    -
    -
    @Configuration
    -@ComponentScan
    -@EnableAutoConfiguration
    -@EnableEurekaClient
    -@FeignClientScan
    -public class Application {
    -
    -    public static void main(String[] args) {
    -        SpringApplication.run(Application.class, args);
    -    }
    -
    -}
    -
    -
    -
    -
    StoreClient.java
    -
    -
    @FeignClient("stores")
    -public interface StoreClient {
    -    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    -    List<Store> getStores();
    -
    -    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    -    Store update(@PathParameter("storeId") Long storeId, Store store);
    -}
    -
    -
    -
    -

    In the @FeignClient annotation the String value ("stores" above) is -the arbitrary name of the client, used to create a configuration -prefix (see below for details of Ribbon -support).

    -
    -
    -

    Example: How to Use Feign Without Eureka

    -
    -

    Eureka is a convenient way to abstract the discovery of remote servers -so you don’t have to hard code their URLs in clients, but if you -prefer not to use it, Ribbon and Feign are still quite -amenable. Suppose you have declared a Feign client as above for -"stores", and Eureka is not in use (and not even on the -classpath). You should find that the Ribbon client defaults to a -configured server list, and you can supply the configuration like this

    -
    -
    -
    application.yml
    -
    -
    stores:
    -  ribbon:
    -    listOfClients: example.com,google.com
    -
    -
    -
    -
    -
    -

    Client Side Load Balancer: Ribbon

    @@ -2167,8 +2138,7 @@ annotation). Spring Cloud creates a new ensemble as an

    You can configure some bits of a Ribbon client using external properties in <client>.ribbon.*, which is no different than using the Netflix APIs natively, except that you can use Spring Boot -configuration files (example -above). The native options can +configuration files. The native options can be inspected as static fields in CommonClientConfigKey (part of ribbon-core).

    @@ -2190,6 +2160,92 @@ public class TestConfiguration { RibbonClientConfiguration together with any in FooConfiguration (where the latter generally will override the former).

    +
    +

    Spring Cloud Netflix provides the following beans by default for ribbon +(BeanType beanName: ClassName):

    +
    +
    +
      +
    • +

      IClientConfig ribbonClientConfig: DefaultClientConfigImpl

      +
    • +
    • +

      IRule ribbonRule: ZoneAvoidanceRule

      +
    • +
    • +

      IPing ribbonPing: NoOpPing

      +
    • +
    • +

      ServerList<Server> ribbonServerList: `ConfigurationBasedServerList

      +
    • +
    • +

      ServerListFilter<Server> ribbonServerListFilter: ZonePreferenceServerListFilter

      +
    • +
    • +

      ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer

      +
    • +
    +
    +
    +

    Creating a bean of one of those type and placing it in a @RibbonClient +configuration (such as FooConfiguration above) allows you to override each +one of the beans described. Example:

    +
    +
    +
    +
    @Configuration
    +public class FooConfiguration {
    +    @Bean
    +    public IPing ribbonPing(IClientConfig config) {
    +        return new PingUrl();
    +    }
    +}
    +
    +
    +
    +

    This replaces the NoOpPing with PingUrl.

    +
    +
    +
    +

    Using the Ribbon with Eureka

    +
    +

    When Eureka is used in conjunction with Ribbon the ribbonServerList +is overridden with an extension of DiscoveryEnabledNIWSServerList +which populates the list of servers from Eureka. It also replaces the +IPing interface with NIWSDiscoveryPing which delegates to Eureka +to determine if a server is up. The ServerList that is installed by +default is a DomainExtractingServerList and the purpose of this is +to make physical metadata available to the load balancer without using +AWS AMI metadata (which is what Netflix relies on). By default the +server list will be constructed with "zone" information as provided in +the instance metadata (so on the client set +eureka.instance.metadataMap.zone), and if that is missing it can use +the domain name from the server hostname as a proxy for zone (if the +flag approximateZoneFromDomain is set). Once the zone information is +available it can be used in a ServerListFilter (by default it will +be used to locate a server in the same zone as the client because the +default is a ZonePreferenceServerListFilter).

    +
    +
    +
    +

    Example: How to Use Ribbon Without Eureka

    +
    +

    Eureka is a convenient way to abstract the discovery of remote servers +so you don’t have to hard code their URLs in clients, but if you +prefer not to use it, Ribbon and Feign are still quite +amenable. Suppose you have declared a @RibbonClient for "stores", +and Eureka is not in use (and not even on the classpath). The Ribbon +client defaults to a configured server list, and you can supply the +configuration like this

    +
    +
    +
    application.yml
    +
    +
    stores:
    +  ribbon:
    +    listOfServers: example.com,google.com
    +
    +

    Using the Ribbon API Directly

    @@ -2241,6 +2297,61 @@ for details of how the RestTemplate is set up.

    +

    Declarative REST Client: Feign

    +
    +
    +

    Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

    +
    +
    +

    Example spring boot app

    +
    +
    +
    +
    @Configuration
    +@ComponentScan
    +@EnableAutoConfiguration
    +@EnableEurekaClient
    +@EnableFeignClients
    +public class Application {
    +
    +    public static void main(String[] args) {
    +        SpringApplication.run(Application.class, args);
    +    }
    +
    +}
    +
    +
    +
    +
    StoreClient.java
    +
    +
    @FeignClient("stores")
    +public interface StoreClient {
    +    @RequestMapping(method = RequestMethod.GET, value = "/stores")
    +    List<Store> getStores();
    +
    +    @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
    +    Store update(@PathParameter("storeId") Long storeId, Store store);
    +}
    +
    +
    +
    +

    In the @FeignClient annotation the String value ("stores" above) is +an arbitrary client name, which is used to create a Ribbon load +balancer (see below for details of Ribbon +support). You can also specify a URL using the url attribute +(absolute value or just a hostname).

    +
    +
    +

    The Ribbon client above will want to discover the physical addresses +for the "stores" service. If your application is a Eureka client then +it will resolve the service in the Eureka service registry. If you +don’t want to use Eureka, you can simply configure a list of servers +in your external configuration (see +above for example).

    +
    +
    +
    +

    External Configuration: Archaius

    @@ -2333,7 +2444,24 @@ the proxy will not try to contact the service.

    To skip having a service automatically added, set -zuul.ignored-services to a list of service ids. To augment or change +zuul.ignored-services to a list of service id patterns. If a service +matches a pattern that is ignored, but also included in the explicitly +configured routes map, then it will be unignored. Example:

    +
    +
    +
    application.yml
    +
    +
     zuul:
    +  ignoredServices: *
    +  routes:
    +    users: /myusers/**
    +
    +
    +
    +

    In this example, all services are ignored except "users".

    +
    +
    +

    To augment or change the proxy routes, you can add external configuration like the following:

    @@ -2404,6 +2532,13 @@ the service-specific prefix from individual routes, e.g.

    In this example requests to "/myusers/101" will be forwarded to "/myusers/101" on the "users" service.

    +

    The zuul.routes entries actually bind to an object of type ProxyRouteLocator. If you +look at the properties of that object you will see that it also has a "retryable" flag. +Set that flag to "true" to have the Ribbon client automatically retry failed requests +(and if you need to you can modify the parameters of the retry operations using +the Ribbon client configuration).

    +
    +

    The X-Forwarded-Host header added to the forwarded requests by default. To turn it off set zuul.addProxyHeaders = false. The prefix path is stripped by default, and the request to the backend @@ -2484,12 +2619,12 @@ Spring Boot command line features for

    To install, make sure you have Spring Boot CLI -(1.2.0.RC1 or better):

    +(1.2.0 or better):

    $ spring version
    -Spring CLI v1.2.0.RELEASE
    +Spring CLI v1.2.1.RELEASE
    @@ -2497,8 +2632,8 @@ Spring CLI v1.2.0.RELEASE
    -
    $ gvm install springboot 1.2.0.RELEASE
    -$ gvm use springboot 1.2.0.RELEASE
    +
    $ gvm install springboot 1.2.1.RELEASE
    +$ gvm use springboot 1.2.1.RELEASE
    @@ -2510,6 +2645,25 @@ $ gvm use springboot 1.2.0.RELEASE $ spring install org.springframework.cloud:spring-cloud-cli:1.0.0.BUILD-SNAPSHOT
    +
    +

    Encryption and Decryption

    +
    + + + + + +
    +
    Important
    +
    +Prerequisites: to use the encryption and decryption features +you need the full-strength JCE installed in your JVM (it’s not there by default). +You can download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files" +from Oracle, and follow instructions for installation (essentially replace the 2 policy files +in the JRE lib/security directory with the ones that you downloaded). +
    +
    +

    Spring Cloud Security

    @@ -2987,186 +3141,10 @@ ProxyAuthenticationProperties for full details.

    -

    Spring Cloud for Cloud Foundry

    -
    -
    -
    -

    Spring Cloud for Cloudfoundry makes it easy to run -Spring Cloud apps in -Cloud Foundry (the Platform as a -Service). Cloud Foundry has the notion of a "service", which is -middlware that you "bind" to an app, essentially providing it with an -environment variable containing credentials (e.g. the location and -username to use for the service).

    -
    -
    -

    Add this project as a dependency to any Spring Cloud UI app or REST -service and deploy to Cloudfoundry. If you use Spring Cloud Security -OAuth2 features this will make them bindable to Cloud Foundry services -instead of enironment properties in spring.oauth2.*. For a UI app you can -declare @EnableOAuth2Sso and bind to a service called "sso", and for -a service you can add @EnableOAuth2Resource and bind to a service -called "resource" (see below for how to change the names).

    -
    -
    -
    -
    -

    Quickstart

    -
    -
    -

    Here’s a Spring Cloud app with OAuth2 SSO:

    -
    -
    -
    app.groovy
    -
    -
    @Controller
    -@EnableOAuth2Sso
    -class Application {
    -
    -  @RequestMapping('/')
    -  String home() {
    -    'Hello World'
    -  }
    -
    -}
    -
    -
    -
    -

    If you run it without any service bindings:

    -
    -
    -
    -
    $ spring jar app.jar app.groovy
    -$ cf push -p app.jar
    -
    -
    -
    -

    it will be secure with (Spring Boot default) Basic authentication, -i.e. the password will be in the logs (or set it with -security.user.password as normal). To turn on OAuth2 SSO all you -need to do is bind the app to a service with the right -credentials. For example, a -user-provided -service can be created like this on PWS:

    -
    -
    -
    -
    $ cf create-user-provided-service sso -p '{clientId:"<my-client>",clientSecret:"<my-secret>",userInfoUri:"https://uaa.run.pivotal.io/userinfo",tokenUri: "https://login.run.pivotal.io/oauth/token",authorizationUri:"https://login.run.pivotal.io/oauth/authorize"}
    -
    -
    -
    -

    Then bind and restart the app:

    -
    -
    -
    -
    $ cf bind app sso
    -$ cf restart app
    -
    -
    -
    -

    and visit it in a browser. It will redirect to the Cloud Foundry (PWS) -login server instead of challenging for Basic authentication. The -clientId and clientSecret are credentials of a registered client -in Cloud Foundry. To get a Cloud Foundry client registration for -testing please ask your local platform administrator if it’s a private -instance).

    -
    -
    -
    -
    -

    How Does it Work?

    -
    -
    -

    OAuth2 Single Sign On

    -
    -

    Spring Cloud Security provides the @EnableOAuth2Sso annotation and -binds the app to environment properties in spring.oauth2.*. Spring Cloud -for Cloud Foundry just sets up default environment properties so that -it all just works if you bind to a Cloud Foundry service instance -called "sso". The service credentials are mapped to the SSO -properties, i.e. (from spring.oauth2.client.*) clientId, clientSecret, -tokenUri, authorizationUri, (and from spring.oauth2.resource.*) -userInfoUri, tokenInfoUri, keyValue, keyUri. Refer to the -Spring Cloud Security documentation for details of which combinations -will work together. The main thing is that in Cloud Foundry you only -need one service to cover all the necessary credentials.

    -
    -
    -

    To use a different service instance name (i.e. not "sso") just set -spring.oauth2.sso.serviceId to your custom name.

    -
    -
    -
    -

    JWT Tokens

    -
    -

    Spring Cloud Security already has support for decoding JWT tokens if -you just provide the verification key (as an environment property). In -Cloud Foundry you can pick that property up from a service binding -(keyValue or keyUri).

    -
    -
    -

    For example the keyUri in PWS is -"https://uaa.run.pivotal.io/token_key":

    -
    -
    -
    -
    $ curl https://uaa.run.pivotal.io/token_key
    -{"alg":"SHA256withRSA","value":"-----BEGIN PUBLIC KEY-----\nMIIBI...\n-----END PUBLIC KEY-----\n"}d
    -
    -
    -
    -
    -

    OAuth2 Resource Server

    -
    -

    Similarly, the @EnableOAuth2Resource annotation will protect your -API endpoints if you bind to a service instance called "resource". -The "sso" service above will work for a resource server as well (so -just bind to that if it’s there). If the OAuth2 tokens are JWTs (as in -Cloud Foundry), it is common to use a separate service for resources -to avoid a network round trip decoding the token on every access. A -user-provided-service for an OAuth2 resource can be created like this -on PWS:

    -
    -
    -
    -
    $ cf create-user-provided-service resource -p '{keyUri:"https://uaa.run.pivotal.io/token_key"}
    -
    -
    -
    -

    To use JWT you need to add the verification key as either -keyValue or keyUri (these could be added to the "sso" -service or the "resource" service if you have one).

    -
    -
    -

    To use a different sercice instance name (i.e. not "resource" or -"sso") just set spring.oauth2.resource.serviceId to your custom name.

    -
    -
    -
    -

    Default Environment Keys

    -
    -

    The precise mapppings are as follows:

    -
    -
    -
      -
    • -

      spring.oauth2.sso.* to vcap.services.${spring.oauth2.sso.serviceId:sso}.credentials.*

      -
    • -
    • -

      spring.oauth2.client.* to vcap.services.${spring.oauth2.sso.serviceId:sso}.credentials.tokenUri:${vcap.services.${spring.oauth2.resource.serviceId:resource}.credentials.*

      -
    • -
    • -

      spring.oauth2.resource.(jwt).* to vcap.services.${spring.oauth2.resource.serviceId:resource}.credentials.tokenUri:${vcap.services.${spring.oauth2.sso.serviceId:sso}.credentials.*

      -
    • -
    -
    -
    -
    -