The main objective in this lab is to deploy our system under test to Pivotal Cloud Foundry (PCF).
This task is facilitated by a product called Spring Cloud Services. This product is implemented as a PCF Tile which has the ability to provision service registries, config servers, and hystrix dashboards in the cloud.
Review the projects you’ve created so far:
-
config-server
-
eureka-server
-
fortune-sevice
-
greeting-app
-
hystrix-dashboard
Of the five services on that list, three are infrastructure services, provided by Spring Cloud. Only two are services specific to the business domain. With Spring Cloud Services in PCF, we deploy only those two: the fortune service and greeting application. Everything else is created with Spring Cloud Services. In other words, config server, eureka server, and the hystrix dashboard are managed services.
1. Cloud Foundry Setup
Make sure you have the cf
client installed and that you’re targeting a Pivotal Cloud Foundry instance that has the Spring Cloud Services tile installed.
-
Verify that the cf client is installed with the command:
$ cf version
-
Log in to your Cloud Foundry instance with the
cf login
command.There is a known bug with the cf cli and the git bash shell having to do with capturing passwords from standard input. If you’re on a windows machine using git bash, you’ll have to switch to using the default windows cmd
shell instead, for thecf login
command to work. -
Verify whether the Spring Cloud Services are available by looking in the marketplace:
$ cf marketplace
The response from the above command is a list of service types. Make sure that the following three services are showing on that list:
-
p-service-registry
-
p-config-server
-
p-circuit-breaker-dashboard
-
2. The Process
Pivotal Cloud Foundry has the notion of applications and services. We deploy applications with the cf push
command, and we create services with the cf create-service
command. Finally, services are attached to applications via a process known as binding, using the cf bind
command.
The general process of deploying our system to Cloud Foundry involves:
-
creating and configuring the backing Spring Cloud Services that our applications depend on
-
deploying, or pushing fortune and greeting to Cloud Foundry
-
binding our applications to the backing services, either explicitly using
cf bind
or implicitly by listing the services in the application’s deployment manifest
The instructions shown below reference marketplace services found on Pivotal Web Services (aka PWS), Pivotal’s public instance of Cloud Foundry. You may have to substitute the names of services and plans to match the ones available in your PCF foundation’s marketplace. |
3. Create the Service Registry
To orient ourselves to the syntax for creating our first service, invoke the command:
$ cf help create-service
If you recall from the marketplace listing above, the name of the service type is p-service-registry, and it sports two plans. Select the one named "trial".
⇒ Create the service:
$ cf create-service p-service-registry trial service-registry
Here’s the response:
Creating service instance service-registry in org eitan-org / space eitan-space as esuez@pivotal.io...
OK
Create in progress. Use 'cf services' or 'cf service service-registry' to check operation status.
Notice the message create in progress. At this point, Spring Cloud Services (which from now on I’ll abbreviate as SCS) begins the work of standing up a eureka server on our behalf. This process is asynchronous and can take a couple of minutes.
Check on the status of your service creation with the cf services
command:
$ cf services
Getting services in org eitan-org / space eitan-space as esuez@pivotal.io...
OK
name service plan bound apps last operation
service-registry p-service-registry trial create in progress
Within a short time, the "last operation" value will change to create succeeded.
At this point, it’s worth jumping over to the Apps Manager, the Graphical User Interface for PCF (in PWS, the url is http://console.run.pivotal.io/). Log in to the apps manager and navigate to the org and space that matches your cf target
. In the service tab, you should see the service that was just created, as shown here:
Click on the service registry, and in the upper right-hand corner, you’ll see a link titled Manage. This is standard for many managed services in cloud foundry: they expose some kind of management dashboard. For the service registry, the dashboard is essentially the same eureka dashboard we’ve been working with all along, only styled with a different color scheme.
Of course, we have no registered applications at this time. Let’s move on to creating a configuration server in PCF.
4. Create the Config Server
The process here is very similar, but with one major difference: we must configure our config server with our git repository.
4.1. Push the local git repository to github
Up until now, we’ve been using a git repository on the local file system. We need to make this repository accessible from PCF. One simple solution is to push the repository to github, or perhaps an enterprise github or bitbucket, accessible from your PCF instance.
That’s simple enough to do, though these instructions may vary depending on the git system you’re using. Here are the instructions for github:
-
Head over to your github account, create a repository, name it
config-repo
, and click Create repository. Here’s a screenshot: -
Github makes the next step very convenient: it displays the instructions for synchronizing our local git repository to it, under the heading …or push an existing repository from the command line as shown below:
So, follow those instructions (not the ones in the above screenshot, the git URL’s are unique to each repository). In a local shell,
cd
over to your config-repo, add the remote and invoke the git push command as instructed. At this point, you can refresh your config-repo github page in your web browser, which should now look something like this: -
Finally, copy the URL to this newly-created repository to your clipboard. Use the https URL as it’s usually more convenient and accessible. Click on the "Clone or Download" green button, select "Use HTTPS", and click on the "Copy to clipboard" button:
Ok, we’re all set for the next step: creating the service.
4.2. Create the Config Service
This time around, we must provide some configuration information to the create-service
command, in order to configure the config server with the github repository URL we just created.
-
Create a simple json file, name it "config.json". Its contents should resemble this:
{ "git": { "uri": "https://github.com/eitansuez/config-repo.git" } }
The above git URL is just an example. You must substitute your git repository URL in its place. -
Now, invoke the command to create the service, like this:
$ cf create-service p-config-server trial config-server -c config.json
For a thorough documentation on creating and configuring a config server in PCF with SCS, consult the SCS documentation here.
As before, the service creation should now be in progress:
$ cf services
Getting services in org eitan-org / space eitan-space as esuez@pivotal.io...
OK
name service plan bound apps last operation
config-server p-config-server trial create in progress
service-registry p-service-registry trial create succeeded
Once created, we should now have a running config server, configured with the proper git repository. Verify this by visiting the Apps Manager once more: navigate to the config-server service, click on the Manage link as before, and you’ll see the dashboard page for the config server:
It’s important to note that, in PCF, there’s little to no value in having the config server register with eureka in order to make it discoverable. PCF has its own mechanism of relating the config server URL to bound applications via environment variables.
5. Push the Apps
The services that both fortune and greeting depend on are now running.
There’s a difference between the way these services are configured locally and the way they’re configured in PCF:
⇒ The PCF services are secured with an OAuth2 server
This means that clients cannot just connect to these services without authenticating (i.e. providing credentials). SCS boils this task down to modifying the client applications' build dependencies.
5.1. Revise dependencies
Replace the spring cloud "starter" dependencies with SCS-specific verisons:
-
spring-cloud-starter-eureka
becomesspring-cloud-services-starter-service-registry
-
spring-cloud-starter-config
becomesspring-cloud-services-stater-config-client
@@ -22,6 +22,7 @@ repositories {
}
ext {
+ springCloudServicesVersion = '1.6.3.RELEASE'
springCloudVersion = 'Edgware.SR2'
}
@@ -31,9 +32,10 @@ dependencies {
compile 'org.springframework.boot:spring-boot-starter-freemarker'
compile 'org.springframework.cloud:spring-cloud-starter-hystrix'
- compile 'org.springframework.cloud:spring-cloud-starter-eureka'
compile 'org.springframework.cloud:spring-cloud-starter-feign'
- compile 'org.springframework.cloud:spring-cloud-starter-config'
+
+ compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry'
+ compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-config-client'
runtime 'org.springframework.boot:spring-boot-devtools'
@@ -45,6 +47,7 @@ dependencies {
dependencyManagement {
imports {
+ mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
⇒ Apply the above change to both the greeting application and the fortune service’s build files.
The principal difference when using the SCS dependencies is that we transitively pull in Spring Security OAuth2.
For good measure, re-run the tests for each project and make sure they still pass.
5.2. Turn off Security
One side-effect of adding security libraries to our clients is that Spring Security defaults to turning on basic authentication. Meaning that we can’t access fortunes without authenticating.
Let’s turn this off, by committing a change to config-repo’s application.yml
:
@@ -2,6 +2,10 @@ management:
security:
enabled: false
+security:
+ basic:
+ enabled: false
+
logging:
level:
io:
Make sure to:
$ git add application.yml
$ git commit -m "turn off basic auth"
$ git push origin master
5.3. Write the CF Deployment Manifest
Let’s start with the fortune service.
First, build the project to produce the jar artifact:
$ cd fortune-service
$ gradle assemble
This will produce a jar file in the build/libs/
folder. Note the name of the jar file.
The simplest way to deploy to cloudfoundry is by writing a manifest file. Name the file manifest.yml
and place it in the base directory of the fortune project. Let’s analyze its contents:
---
applications:
- name: fortune
path: build/libs/fortune-service-0.0.1-SNAPSHOT.jar (1)
host: eitan-fortune-service (2)
memory: 768M
services: (3)
- config-server
- service-registry
env:
SPRING_CLOUD_CONFIG_DISCOVERY_ENABLED: false (4)
1 | The path to the jar file we’re deploying |
2 | Customize the host name to make it unique, as a precaution against other deployed applications with a similar URL (may not be necessary) |
3 | Cite the services to bind to the application |
4 | Turn off obtaining the config server URL via discovery; in CloudFoundry, this information is communicated via environment variables |
5.4. Deploy fortune
We’re now ready to deploy fortune. From the fortune directory invoke:
$ cf push
As you push the application, it’s a good idea to monitor the application’s log for exceptions, and to observe and follow the startup sequence of the application. In a separate terminal, invoke:
$ cf logs fortune
For example, you should see log messages confirming that the application is fetching configuration from the config server:
c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: https://config-b8bb6736-900b-456f-b3ee-ab7cb4b7a76f.cfapps.io
Similarly, you should see messages indicating that the application is registering with the discovery server:
o.s.c.n.e.s.EurekaServiceRegistry : Registering application fortune with eureka with status UP
com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [timestamp=1504804631510, current=UP, previous=STARTING]
com.netflix.discovery.DiscoveryClient : DiscoveryClient_FORTUNE/eitan-fortune-service.cfapps.io:da3cbcd2-aeb8-4515-61c9-8e1c: registering service...
com.netflix.discovery.DiscoveryClient : DiscoveryClient_FORTUNE/eitan-fortune-service.cfapps.io:da3cbcd2-aeb8-4515-61c9-8e1c - registration status: 204
-
Visit the PCF eureka dashboard: do you see the fortune service on the list of registered instances?
-
Visit the application’s URL: do you see fortunes?
-
Can you access the application’s management endpoints? For example, the
env/
endpoint?
How did fortune know the URL of the config server? ..of the discovery sever?
To answer that question, we need to look at the value of a special environment variable VCAP_SERVICES, associated with the fortune application, which was set as a consequence of binding the application to the two services. Invoke:
$ cf env fortune
Here is the output:
"VCAP_SERVICES": {
"p-config-server": [
{
"credentials": {
"access_token_uri": "https://p-spring-cloud-services.uaa.run.pivotal.io/oauth/token",
"client_id": "p-config-server-c3064cb2-dd1d-40ff-9ccd-84c149194197",
"client_secret": "******",
"uri": "https://config-b8bb6736-900b-456f-b3ee-ab7cb4b7a76f.cfapps.io"
},
"label": "p-config-server",
"name": "config-server",
"plan": "trial",
"provider": null,
"syslog_drain_url": null,
"tags": [ "configuration", "spring-cloud" ],
"volume_mounts": []
}
],
"p-service-registry": [
{
"credentials": {
"access_token_uri": "https://p-spring-cloud-services.uaa.run.pivotal.io/oauth/token",
"client_id": "p-service-registry-7e3db5a8-546f-4b40-a8fd-d8874d316ae0",
"client_secret": "******",
"uri": "https://eureka-cd62d1f9-2e56-4a95-9c0c-68cc2f38d691.cfapps.io"
},
"label": "p-service-registry",
"name": "service-registry",
"plan": "trial",
"provider": null,
"syslog_drain_url": null,
"tags": [ "eureka", "discovery", "registry", "spring-cloud" ],
"volume_mounts": []
}
]
}
For each service, not only do we have its URL, but also the credentials necessary to access it, and the oauth server’s uri for obtaining tokens using these credentials. All of this is done on our behalf by SCS.
5.5. Deploy greeting
The task here is very similar: build the jar file, write the manifest, and push the application to cloud foundry:
$ cd greeting-app
$ gradle assemble
$ vi manifest.yml ...
$ cf push
And here’s the manifest file:
---
applications:
- name: greeting
path: build/libs/greeting-app-0.0.1-SNAPSHOT.jar
host: eitan-greeting
memory: 768M
services:
- config-server
- service-registry
env:
SPRING_CLOUD_CONFIG_DISCOVERY_ENABLED: false
Our system is now functioning in the cloud. Both applications are deployed, running. Both are registered with Eureka, and both obtain their configuration from the Config Server.
6. Spring Cloud Bus
Let’s, once more, run through the scenario of modifying the feature toggle greeting.displayFortune
, pushing that change to the github repository, and submitting an HTTP post to the /refresh
endpoint of the greeting application in PCF, and observing that the application reloads the configuration and alters its behavior correspondingly.
However, before we do that, consider the following question:
⇒ If greeting were scaled to, say 100 instances, how would we go about refreshing the configuration from every single instance?
I suppose we could script submitting a "/refresh" command in a for loop. There’s a better way.
The Spring team offers a project named Spring Cloud Bus designed to solve this very problem, via messaging.
The idea is for all application instances to communicate over a message bus. Sending a /bus/refresh
signal (an http POST) to any instance will have the side effect of having that instance broadcast the message to all other running instances.
To add this capability to an application requires:
-
creating and binding an AMQP-compatible message broker service to the application
-
adding the dependency
spring-cloud-starter-bus-amqp
to the application’s build file
Do this for greeting:
-
Add the dependency:
greeting-app/build.gradle@@ -37,6 +37,8 @@ dependencies { compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry' compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-config-client' + compile 'org.springframework.cloud:spring-cloud-starter-bus-amqp' + runtime 'org.springframework.boot:spring-boot-devtools' compileOnly 'org.projectlombok:lombok'
-
Rebuild the jar file:
$ gradle assemble
-
Create a rabbitmq service. Pivotal Web Services offers a service named
cloudamqp
to provision rabbitmq instances:$ cf create-service cloudamqp lemur thecloudbus
Your PCF instance’s marketplace may have a service named p-rabbitmq
instead of cloudamqp. -
Add the service to
manifest.yml
:greeting-app/manifest.yml@@ -7,6 +7,7 @@ applications: services: - config-server - service-registry + - thecloudbus env: SPRING_CLOUD_CONFIG_DISCOVERY_ENABLED: false
-
Finally, redeploy the application:
$ cf push
6.1. Testing Refreshing Multiple Instances
-
Scale greeting to 3 instances:
$ cf scale -i 3 greeting
-
In a browser, visit the greeting application, and note that no fortune is displayed:
-
In
config-repo
, modify the configuration ofgreeting.yml
by toggling the property displayFortune:config-repo/greeting.yml@@ -1,5 +1,5 @@ greeting: - displayFortune: false + displayFortune: true fortune: ribbon:
-
Commit and push the change
Before sending the refresh signal, tail the logs for the greeting application, so we can observe what happens when the signal is received:
$ cf logs greeting
Now, in a separate terminal, or tab, send the http POST request:
$ http post https://eitan-greeting.cfapps.io/bus/refresh
In the logs you should see messages relating to a "remote refresh request", similar to this:
[APP/PROC/WEB/1] : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@61a6d658: startup date [Thu Sep 07 19:01:43 UTC 2017]; root of context hierarchy
[APP/PROC/WEB/1] : Fetching config from server at: https://config-b8bb6736-900b-456f-b3ee-ab7cb4b7a76f.cfapps.io
[APP/PROC/WEB/1] : Located property source: CompositePropertySource [name='configService', propertySources=[MapPropertySource [name='configClient'], MapPropertySource [name='https://github.com/eitansuez/config-repo.git/greeting.yml'], MapPropertySource [name='https://github.com/eitansuez/config-repo.git/application.yml']]]
[APP/PROC/WEB/1] : Located environment: name=greeting, profiles=[cloud], label=null, version=508b14a26415f4581884395594fdc57acf4aed9c, state=null
[APP/PROC/WEB/1] : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@37d5d92d: startup date [Thu Sep 07 19:01:44 UTC 2017]; parent: org.springframework.context.annotation.AnnotationConfigApplicationContext@61a6d658
[APP/PROC/WEB/1] : Received remote refresh request. Keys refreshed [config.client.version, greeting.displayFortune]
The above messages should display three times: once for each application instance. i.e. the messages should be prefixed with [APP/PROC/WEB/0]
, [APP/PROC/WEB/1]
, and [APP/PROC/WEB/2]
.
Refresh the greeting page, fortunes should now display. And each time you visit the greeting page, the fortune application’s log should output a message similar to this:
i.p.training.fortune.FortuneController : retrieving fortune 'You can always find happiness at work on Friday'
7. Load Balancing
In CloudFoundry, all application instances have the same URL, handled by a component known as the Gorouter, which fronts and load-balances requests across application instances.
So the task of load balancing can be left up to the platform, and we don’t need to use Ribbon. It’s not harmful to leave Ribbon in place, but the work that Ribbon does, of selecting an instance from among multiple candidates is for naught, since each service instance resolves to the same URL.
We can glean that this is so by inspecting the eureka dashboard:
Here we see three instances of GREETING. It happens that each serviceId is composed of multiple pieces of information, the first element being the instance’s hostname. The hostname is clearly the same value, for all three instances.
There is however a use case, and a good reason for using Ribbon instead of the Gorouter. In PCF, we can enable a feature called container-to-container networking, giving applications the permission to contact each other directly (i.e. without going through the Gorouter).
In this configuration, client-side load-balancing with Ribbon becomes meaningful. In fact this configuration is more secure.
In CloudFoundry, when an application is given a route, it becomes directly accessible to the outside world. If some of our services, for example the fortune service, are strictly backing services, not meant to be accessed directly by clients, then we can make them only accessible to the services within PCF that need to talk to them. We can remove the route from fortune altogether, and let greeting contact it directly via its internal IP address.
-
Allow greeting to access fortune directly:
$ cf add-network-policy greeting --destination-app fortune --protocol tcp --port 8080
-
Verify the above succeeded, with this command:
$ cf network-policies Listing policies as esuez@pivotal.io... OK Source Destination Protocol Port greeting fortune tcp 8080
-
Configure Spring Cloud Services such that all eureka instances register with their direct ip address, instead of their url. We do this via a configuration property. So, head over to
config-repo
and editapplication.yml
as follows:config-repo/application.yml@@ -6,6 +6,11 @@ security: basic: enabled: false +spring: + cloud: + services: + registrationMethod: direct + logging: level: io:
-
Commit and push this change to the github repository.
-
Remove the route from the fortune service so that it cannot be accessed directly from outside PCF:
$ cf unmap-route fortune cfapps.io --hostname eitan-fortune-service
-
Verify that fortune no longer has a URL:
$ cf apps Getting apps in org eitan-org / space eitan-space as esuez@pivotal.io... OK name requested state instances memory disk urls fortune started 1/1 768M 1G greeting started 3/3 768M 1G eitan-greeting.cfapps.io
Also, visit the fortune url directly and see that you now get a 404 (not found) response.
-
Restart the fortune service and watch its registration serviceId change in the eureka dashboard, to something resembling
10.251.219.116:d9ebf80e-081f-4ceb-735c-63ce
-
Scale greeting back to one instance, and fortune to three instances:
$ cf scale -i 1 greeting
$ cf scale -i 3 fortune
You may need to wait a minute or so, for the new instances to come up, for their registrations to show up in eureka, and for the greeting application’s cache of the service registry to expire. Afterwards, greeting should be using ribbon to communicate with fortune directly, not only doing so more securely, but also eliminating an extra network "hop".
Tail the logs for fortune and visit the greeting page multiple times. The output should reveal two things:
-
HTTP requests no longer go through the Gorouter on behalf of fortune application instances. There should be no log messages prefixed with [RTR], and
-
Requests should be load-balanced across all three fortune instances, according to the WeightedResponseTime rule
$ cf logs fortune
[APP/PROC/WEB/0] FortuneController : retrieving fortune 'You learn from your mistakes... You will learn a lot today.'
[APP/PROC/WEB/2] FortuneController : retrieving fortune 'You can always find happiness at work on Friday'
[APP/PROC/WEB/0] FortuneController : retrieving fortune 'You can always find happiness at work on Friday'
[APP/PROC/WEB/2] FortuneController : retrieving fortune 'You will be hungry again in one hour.'
[APP/PROC/WEB/1] FortuneController : retrieving fortune 'You can always find happiness at work on Friday'
[APP/PROC/WEB/1] FortuneController : retrieving fortune 'You learn from your mistakes... You will learn a lot today.'
[APP/PROC/WEB/0] FortuneController : retrieving fortune 'Today will be an awesome day!'
[APP/PROC/WEB/2] FortuneController : retrieving fortune 'You can always find happiness at work on Friday'
[APP/PROC/WEB/1] FortuneController : retrieving fortune 'Today will be an awesome day!'
[APP/PROC/WEB/2] FortuneController : retrieving fortune 'You will be hungry again in one hour.'
[APP/PROC/WEB/0] FortuneController : retrieving fortune 'Today will be an awesome day!'
[APP/PROC/WEB/1] FortuneController : retrieving fortune 'You can always find happiness at work on Friday'
[APP/PROC/WEB/0] FortuneController : retrieving fortune 'You learn from your mistakes... You will learn a lot today.'
8. Hystrix
The goal here is to be able to monitor the greeting application’s circuit breaker in Cloud Foundry. Again, SCS does all of the hard work for us. We simply need to:
-
create a hystrix-dashboard service
-
bind the service to the greeting application
-
visit the hystrix dashboard in cloud foundry
In this scenario, we’ll also scale greeting back up to three instances and observe that Spring Cloud Services automatically aggregates metrics from all application instances into a single dashboard, courtesy of the Netflix Turbine project, and Spring Cloud’s Turbine Stream.
-
Replace greeting’s hystrix dependency with the spring cloud services version (like we did previously for config and service registry):
greeting-app/build.gradle@@ -31,11 +31,11 @@ dependencies { compile 'org.springframework.boot:spring-boot-starter-actuator' compile 'org.springframework.boot:spring-boot-starter-freemarker' - compile 'org.springframework.cloud:spring-cloud-starter-hystrix' compile 'org.springframework.cloud:spring-cloud-starter-feign' compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry' compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-config-client' + compile 'io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker' compile 'org.springframework.cloud:spring-cloud-starter-bus-amqp'
-
Rebuild the jar artifact for greeting:
$ cd greeting-app $ gradle assemble
-
Create the hystrix dashboard service:
$ cf create-service p-circuit-breaker-dashboard trial hystrix-dashboard
-
Add the service to the manifest file for the greeting application:
greeting-app/manifest.yml@@ -8,6 +8,7 @@ applications: - config-server - service-registry - thecloudbus + - hystrix-dashboard env: SPRING_CLOUD_CONFIG_DISCOVERY_ENABLED: false
-
Redeploy the application:
$ cd greeting-app $ cf push
-
Scale greeting back up to three instances
$ cf scale -i 3 greeting
-
Make sure all three instances are running:
$ cf app greeting Showing health and status for app greeting in org eitan-org / space eitan-space as esuez@pivotal.io... name: greeting requested state: started instances: 3/3 usage: 768M x 3 instances routes: eitan-greeting.cfapps.io last uploaded: Thu 07 Sep 15:21:13 CDT 2017 stack: cflinuxfs2 buildpack: ... state since cpu memory disk details #0 running 2017-09-07T20:22:41Z 296.2% 288.8M of 768M 172.5M of 1G #1 running 2017-09-07T20:22:59Z 0.0% 0 of 768M 0 of 1G #2 running 2017-09-07T20:23:36Z 0.0% 0 of 768M 0 of 1G
-
Visit the greeting application a few times (refresh or reload the page and see fortunes come through)
-
Next, visit the hystrix dashboard: using the apps manager, navigate to the Services tab, select Circuit Breaker, and click the Manage link from the top right-hand corner of the page.
In the above screenshot, notice that the graph for the circuit breaker represents aggregate metrics across three instances of greeting. As we did in the circuit breakers lab, at this point, we can experiment by simulating requests against greeting, stopping the fortune application, and seeing the circuit open. In the reverse direction, we can restart fortune, and watch the circuit close once more.
9. Congratulations
Spring Cloud Services helps make Spring Cloud-based microservice applications first-class citizens on Cloud Foundry. It provides a production-grade implementation of a Cloud Foundry service broker that can stand up secure instances of the Spring Cloud services on demand. The product’s documentation goes deeper into more sophisticated configurations, such as standing up discovery services as a cluster with multiple peers.
Congratulations for making it through this course!