Tunnel local services in STS via ngrok to Spring Cloud Services on PCF

The Spring Boot Dashboard in the Spring Tool Suite provides an easy way to start up a local Spring Boot project and connect it to a running microservice system that is running on Cloud Foundry. This is done by tunneling the local application via ngrok to the outside world and register the URL of the tunnel with the remote Eureka service registry on CF. This feature of the Spring Boot dashboard is described in more detail in the second part of our blog series about the Spring Boot Dashboard in STS.


This feature was designed to be used and is working with a remote Eureka service registry that you deployed yourself as a Spring Boot app. It doesn't work yet with Eureka service registries that you get when using the Spring Cloud Services on PCF. While the direct support of this feature for SCS will be part of a future release of the Spring Tool Suite, this document describes in detail how to tunnel a local application via ngrok manually when using Spring Cloud Services.


As an example for this tech note I will use the SCS demo application that consists out of a service called "camelboy" that uses another service called "expedition". The expedition service will be the one that I am going to run locally. The camelboy service will keep running on PCF.

Setup

You need to have ngrok installed on your local machine. You can download it from the officla ngrok download page.


Once you have ngrok installed on your local machine, you can startup a tunnel manually from the command line via:


> ngrok http 8080


The 8080 is the port on your local machine that you would like to tunnel to the outside world. In our case it is the port that is used by the local Spring Boot app that we would like to run locally and connect to the other microservices that are running on PCF.


As a result ngrok will display the temporary ngrok URLs of the created tunnel. It looks like this:

Configure your local service - application.yml

As a next step we need to configure the launch configuration of the local Spring Boot app in a way that it registers itself with the remote service registry that is coming from Spring Cloud Services. This gets a little more complicated because the remote service registry is running in a secure mode and protected via OAuth.


First, we take a look at the application.yml. There are three things that need to be configured as properties:

First, we need to set a name for the application. This name is being used to register the application with the remote eureka and has to be the same that you use when deploying the service to PCF and the same that you use when looking up the service in your code.


Second, we configure the eureka registration in order to be able to deal with the secure ports on PCF. The "-1" as the secure port looks a bit strange, but it will cause the spring cloud implementation to use the standard port for https (which is also the one that is being exposed by ngrok for the https tunnel).


Third, we disable the basic security that gets enabled by default otherwise. This helps us to test the local app with a browser without the need to login.

There is nothing mentioned about the ngrok tunnel URL yet. So how does the local app know how to register with the remote Eureka?


Configure your local service - environment variables

The next step is to configure certain environment variables for your local Spring Boot application. Therefore open the launch config dialog, select the launch configuration you would like to use and switch to the "Environment" tab.


We need to set six different environment variables in here:


The first four environment variables are easy to set and straight forward. The latter two are more complicated. In the end the environment variable configuration should look like this:

The VCAP environment variables consist out of JSON strings that are (on PCF) set by the PCF environment in order to pass important service information to the application. The best thing to obtain those two JSON documents is to open the web console of your PCF environment, go to the deployed version of your local service and take a look at the environment. It contains a single JSON string which contains the VCAP_SERVICES definitions as well as the VCAP_APPLICATION section. We need to cut those sections out into individual JSON strings.


The VCAP_SERVICES environment variable JSON value can be used in exactly the way we copy that out of the environment variables on PCF. It contains the remote Eureka specs, including the necessary service keys. In our example it might look like this:


{
	"p-service-registry": [
		{
			"name": "eureka-registry",
			"label": "p-service-registry",
			"tags": [
				"eureka",
				"discovery",
				"registry",
				"spring-cloud"
			],
			"plan": "standard",
			"credentials": {
				"uri": "https://eureka-somehash.tan.springapps.io",
				"client_id": "p-service-registry-somehash",
				"client_secret": "theclientsecret",
				"access_token_uri": "https://p-spring-cloud-services.uaa.tan.springapps.io/oauth/token"
			}
		}
	]
}

The VCAP_APPLICATION environment variable value needs some editing after cutting that portion out into its own document. The application URL needs to be replaced with the ngrok tunnel URL. In the end this JSON doc might look like this (in our example):


{
	"limits": {
		"mem": 512,
		"disk": 1024,
		"fds": 16384
	},
	"application_id": "somehash-for-the-app",
	"application_version": "somehash-for-the-app-version",
	"application_name": "expedition-ml",
	"application_uris": [
		"011c747a.ngrok.io"
	],
	"version": "somehash-again-for-the-version",
	"name": "expedition-ml",
	"space_name": "the name of the space on PCF",
	"space_id": "somehash-ID-for-the-space",
	"uris": [
		"011c747a.ngrok.io"
	],
	"users": null
}

Both JSON strings can be copied into the environment variable configuration of the launch configuration editor that we opened a while ago.


The final step is to run the local Spring Boot app (maybe even in debug mode) using the special launch configuration that we configured. It starts up as a regular Spring Boot app. After while (it might take a few seconds or minutes), it registers itself with the remote Eureka instance. You can observe this in the console output of the local app:


DiscoveryClient_EXPEDITION-ML/011c747a.ngrok.io:e645d5b618dc6c22f4b398530aa74122 - Re-registering apps/EXPEDITION-ML

DiscoveryClient_EXPEDITION-ML/011c747a.ngrok.io:e645d5b618dc6c22f4b398530aa74122: registering service...

DiscoveryClient_EXPEDITION-ML/011c747a.ngrok.io:e645d5b618dc6c22f4b398530aa74122 - registration status: 204


The remote Eureka registry will start to list the local service, too:

Working with the local service

Whereas the setup and configuration steps above are somewhat cumbersome, working with the once registered boot app locally is a pleasure. You can debug the app locally on your machine and restart it as any other local app. This can save a lot of time, compared to re-deploying a changed app to your CF environment.

This whole setup process will be a whole lot simpler when STS can do many of the steps for you.


Useful Links

Download STS: https://spring.io/tools/sts/all

STS Issue tracker: https://issuetracker.springsource.com/browse/STS

Spring Cloud Services: https://docs.pivotal.io/spring-cloud-services/