Doing microservices with JHipster
- Microservices vs Monolithic architecture
- The JHipster API gateway
- The JHipster Registry
- Creating microservices
- Using Docker Compose
- Monitoring with JHipster Console and the ELK stack
The first question JHipster will ask you is the kind of application you want to generate. You have in fact the choice between two architecture styles:
- A “monolithic” architecture uses a single, one-size-fits-all application, which contains both the front-end AngularJS code, and the back-end Spring Boot code.
- A “microservices” architecture splits the front-end and the back-end, so that it’s easier for your application to scale and survive infrastructure issues.
A “monolithic” application is much easier to work on, so if you don’t have any specific requirements, this is the option we recommend, and our default option.
The rest of this guide is only for people interested in doing a microservices architecture.
The JHipster microservices architecture works in the following way:
- A gateway is a JHipster-generated application (using application type
microservice gatewaywhen you generate it) that handles Web traffic, and serves an Angular application. There can be several different gateways, if you want to follow the Backends for Frontends pattern, but that’s not mandatory.
- The JHipster Registry is a runtime application, using the usual JHipster structure, on which all applications registers and get their configuration from.
- Microservices are JHipster-generated applications (using application type
microservice applicationwhen you generate them), that handle REST requests. They are stateless, and several instances of them can be launched in parallel to handle heavy loads.
- The JHipster Console is a monitoring & alerting console, based on the ELK stack.
In the diagram below, the green components are specific to your application and the blue components provide its underlying infrastructure.
JHipster allows use to generate an API gateway. This gateway is a normal JHipster application, so you can use the usual JHipster options and development workflows on that project, but it also acts as the entrance to your microservices. More specifically, it provides HTTP routing and load balancing, quality of service, security and API documentation for all microservices.
When the gateways and the microservices are launched, they will register themselves in the registry (using the
eureka.client.serviceUrl.defaultZone key in the
The gateway will automatically proxy all requests to the microservices, using their application name: for example, when microservices
app1 is registered, it is available on the gateway on the
For example, if your gateway is running on
localhost:8080, you could point to http://localhost:8080/app1/rest/foos to
foos resource served by microservice
app1. If you’re trying to do this with your Web browser, don’t forget REST resources are secured by default in JHipster, so you need to send the correct JWT header (see the point on security below), or remove the security on those URLs in the microservice’s
If there are several instances of the same service running, the gateway will get those instances from the JHipster Registry, and will:
- Load balance HTTP requests using Netflix Ribbon.
- Provide a circuit breaker using Netflix Hystrix, so that failed instances are quickly and safely removed.
Each gateway has a specific “admin > gateway” menu, where opened HTTP routes and microservices instances can be monitored.
JWT (JSON Web Token)
JWT (JSON Web Token) is an industry standard, easy-to-use method for securing applications in a microservices architecture.
JHipster uses the JJWT library, provided by Stormpath, for implementing JWT.
Tokens are generated by the gateway, and sent to the underlying microservices: as they share a common secret key, microservices are able to validate the token, and authenticate users using that token.
Those tokens are self-sufficient: they have both authentication and authorization information, so microservices do not need to query a database or an external system. This is important in order to ensure a scalable architecture.
For security to work, a JWT secret token must be shared between all applications.
- For each application the default token is unique, and generated by JHipster. It is stored in the
- Tokens are configured with the
jhipster.security.authentication.jwt.secretkey in the
- To share this key between all your applications, copy the key from your gateway to all the microservices, or share it using the JHipster Registry’s Spring Config Server.
- A good practice is to have a different key in development and production.
This feature is currently in BETA and thus its documentation is not yet complete.
JHipster provides the option to generate a “UAA” (User Account and Authentication) server, based on Spring Security. This server provides OAuth2 tokens for securing the gateway.
You will find all UAA-related information on our specific Using UAA for Microservice Security documentation page.
Then, the gateway uses Spring Security’s JWT implementation to send JWT tokens to the microservices.
The gateway exposes the Swagger API definitions of the services it proxifies so you can benefit from all useful tools like Swagger UI and swagger-codegen.
The “admin > API” menu of a gateway has a specific drop-down list, showing the gateway’s API and all the APIs from the registered microservices.
Using this drop-down list, all microservices APIs are automatically documented, and testable from the gateway.
When using a secured API, security tokens are automatically added to the Swagger UI interface, so all requests work out-of-the-box.
This is an advanced feature that requires setting up a Cassandra cluster (which is easy to do with the provided Docker Compose configuration).
Gateways provide rate-limiting features, so the number of REST requests can be limited:
- by IP address (for anonymous users)
- by user login (for logged-in users)
JHipster will then use a Cassandra cluster to store request counts, and will send HTTP 429 (too many requests) errors when the limit is exceeded. The default limit per user is 100,000 API calls per hour.
This is an important feature, to protect a microservice architecture from being flooded by a specific user’s requests.
As the gateway secures the REST endpoints, it has full access to the user’s security information, so it can be easily extended to provide specific rate limits depending on the user’s security roles.
To enable rate limiting, open up the
application-prod.yml file and set
jhipster: gateway: rate-limiting: enabled: true
The Cassandra cluster needs to be set up and configured. If you use JHipster’s Docker Compose configuration (available in
src/main/docker), this should all work automatically, but here are the detailed steps if you want to set up your cluster manually:
- A working Cassandra cluster should be available.
- A schema with the JHipster rate-limiting tables must be configured, using the
create_tables.cqlscripts from the
- That cluster must configured in the
application-*.ymlfiles, using the
spring.data.cassandrakeys (a default configuration is already generated)
If you want to add more rules, or modify the existing rules, you need to code them in the
RateLimitingFilter class. Examples of modifications could be:
- Lowering the limit of HTTP calls
- Adding limits per minute or per day
- Removing all limits for “admin” users
By default all registered microservices are available through the gateway. If you want to exclude a specific API from being exposed through the gateway, you can use the gateway’s specific access control policy filter. It is configurable using the
jhipster.gateway.authorized-microservices-endpoints key in the
jhipster: gateway: authorized-microservices-endpoints: # Access Control Policy, if left empty for a route, all endpoints will be accessible app1: /api,/v2/api-docs # recommended dev configuration
For example, if you only want the
/api/foo endpoint of microservice
bar to be available:
jhipster: gateway: authorized-microservices-endpoints: bar: /api/foo
When generating a microservice, gateway or uaa application, you can choose between two service registry solutions: the JHipster-Registry and Consul. In addition, those two solutions also act as a configuration server that lets you to manage your applications’ configuration in a central place.
The JHipster Registry is a runtime application, provided by the JHipster team. Like the JHipster generator, it is an Open Source, Apache 2-licensed application, and its source code is available on GitHub under the JHipster organization at jhipster/jhipster-registry.
The JHipster Registry can be cloned/forked/downloaded directly from jhipster/jhipster-registry, and we recommend you use the same version tag as the one you use for your JHipster generator. As the JHipster Registry is also a JHipster-generated application, you can run it like any other JHipster application:
- run it with
./mvnwin development, it will use by default the
devprofile and the Eureka Registry will be available at http://127.0.0.1:8761/.
./mvnw -Pprod packageto package it in production, and generate the usual JHipster executable WAR file.
If you’d rather run the JHipster Registry from a Docker image, it is available an Docker Hub at jhipster/jhipster-registry. This image is already pre-configured in the Docker configuration that is provided with each microservice application:
docker-compose -f src/main/docker/jhipster-registry.yml upto start the JHipster Registry. The Eureka Registry will be available on port
8761of your Docker host, so if it runs on your machine it should be at http://127.0.0.1:8761/.
Please read our Docker Compose documentation for more information on using the JHipster Registry with Docker Compose.
The JHipster Registry is secured by default. You can login using the usual “admin/admin” login and password that are used in normal JHipster applications.
Applications also connect to the JHipster Registry using that same “admin” user, but use HTTP Basic authentication. So if your microservices cannot access the registry, and you see some “401 authentication error” messages, it is because you have misconfigured those applications.
In order to secure your JHipster Registry:
- You must change the default “admin” password. This password is set using the standard Spring Boot property
security.user.password, so you can use the usual Spring Boot mechanisms to modify it: you could modify the project’s
application-*.ymlfiles, or add a
SECURITY_USER_PASSWORDenvironment variable. The Docker Compose sub-generator uses the environment variable method.
- As your applications will connect to the registry using HTTP, it is very important to secure that connection channel. There are many ways to do it, and the easiest one is probably to use HTTPS.
The JHipster Registry is a Netflix Eureka server and also a Spring Config Server: when applications are launched they will first connect to the JHipster Registry to get their configuration. This is true for both gateways and microservices.
This configuration is a Spring Boot configuration, like the one found in the JHipster
application-*.yml files, but it is stored in a central server, so it is easier to manage.
On startup, your gateways and microservices app will query the Registry’s config server and overwrite their local properties with the ones defined there.
Two kinds of configurations sources are available:
nativeconfiguration, which is used by default in development (using the JHipster
devprofile), and which uses the local filesystem.
Gitconfiguration, which is used by default in production (using the JHipster
prodprofile), and which stores the configuration in a Git server. This allows to tag, branch or rollback configurations using the usual Git tools, which are very powerful in this use-case.
To manage your centralized configuration you just need to add
appname-profile.yml files in your configuration source where appname and profile correspond to the application’s name and current profile of the service that you want to configure.
For example, adding properties in a
gateway-prod.yml file will set those properties only for the application named gateway started with a prod profile. Moreover, properties defined in
application[-dev|prod].yml will be set for all your applications.
As the Gateway routes are configured using Spring Boot, they can also be managed using the Spring Config Server, for example you could map application
app1-v1 to the
/app1 URL in your
v1 branch, and map application
app1-v2 to the
/app1 URL in your
v2 branch. This is a good way of upgrading microservices without any downtime for end-users.
WARNING! This is a new feature, of BETA quality. Use it at your own risk! Feedback is highly welcome!
As an alternative to the JHipster Registry you can choose to use Consul, a datacenter management solution from Hashicorp. Compared to Eureka it has a number of advantages:
- It is easier to operate in a multi-node cluster than Eureka.
- It favors consistency over availability so changes in the state of your cluster are propagated more quickly.
- Consul service discovery can simply interoperate with existing applications through its DNS interface or HTTP API.
To get started with developping applications that rely on a Consul registry, you can start a Consul instance in a docker container:
docker-compose -f src/main/docker/consul.yml upto start a Consul server in
devmode. Consul will then be available on port
8500of your Docker host, so if it runs on your machine it should be at http://127.0.0.1:8500/.
You can also use the Docker Compose subgenerator to generate a docker configuration for several consul-enabled applications.
If you have chosen the Consul option when generating your JHipster microservice or gateway app, they will be automatically configured to retrieve their configuration from Consul’s Key/Value store.
The Key/Value (K/V) store can be modified using either it’s UI available at http://localhost:8500/v1/kv/ or it’s REST API. However changes made this way are temporary and will be lost on Consul server/cluster shutdown. So, in order to help you interact easily with the Key/Value store and manage your configuration as simple YAML files, the JHipster Team has developed a small tool: the consul-config-loader. The consul-config-loader is automatically configured when starting Consul from the
consul.yml docker-compose file but it can also be run as a standalone tool.
It can be run in two modes:
- a dev mode, where YAML files from the
central-server-configdirectory are automatically loaded into Consul. Moreover any change to this directory will be immediately synchronized with Consul.
- a prod mode, that uses Git2Consul to setup the YAML files contained in a Git repository as a configuration source for the Key/Value store.
Note that as with the JHipster Registry, your configuration files will need to be named
appname-profile.yml where appname and profile correspond to the application’s name and profile of the service that you want to configure. For example, adding properties in a
consulapp-prod.yml file will set those properties only for the application named
consulapp started with a
prod profile. Moreover, properties defined in
application.yml will be set for all your applications.
Microservices are a type of JHipster applications, that have no front-end (the AngularJS front-end must be generated on a gateway), and which work with the JHipster Registry to be configured and discovered.
Using the entity sub-generator works a little bit differently in a microservices architecture, as the front-end and the back-end codes are not located in the same application.
First, generate the entities in the microservices applications: this works as usual, and you can also use JHipster UML or JDL Studio to help you generate complex entities and relationships. As microservices don’t have a front-end, no AngularJS code will be generated.
Then, on the gateway(s), run the entity sub-generator again. A new question will appear at the beginning, which is specific to gateways:
- You will have the choice either to generate an new entity normally (a gateway is also a standard JHipster application, so this would work like for a monolith application), or use an existing JHipster configuration from a microservice.
- If you choose to generate the entity from a microservice, you will need to enter the path to this microservice on your local computer, and then JHipster will generate the front-end code on the gateway.
If your application uses an SQL database, JHipster proposes a different 2nd-level caching solution with microservices:
- JHipster’s default caching solution with microservices is Hazelcast
- You can still choose Ehcache (the default solution with monolith applications) or choose not to use a cache at all
This solution is the default with microservices, as in this architecture the idea is that you will scale your services:
- with a local cache, your service instances won’t have a synchronized cache, resulting in incorrect data
- without any cache, the burden of scaling will be pushed to the database, which won’t be very good at it (unless you use our Cassandra option)
Using Hazelcast with microservices will result in a specific configuration:
- At start-up, your application will connect to the JHipster Registry to find if other instances of the same service are running
- With the
devprofile, JHipster will create a cluster of those instances on localhost (
127.0.0.1), using a different port per instance. By default, the Hazelcast port is
your application's port + 5701(so if your application’s port is
8081, Hazelcast will use port
- With the
prodprofile, JHipster will create a cluster with all the other nodes it finds, using the default Hazelcast port (
Only microservices applications can be created without a database. This is because microservices are small and do not have user-management code.
A microservice without a database is very small, and could be used to connect to a specific back-end like a legacy system.
Working on a microservices architecture means you will need several different services and databases working together, and in that context Docker Compose is a great tool to manage your development, testing and production environments.
A specific section on microservices is included in our Docker Compose documentation, and we highly recommend that you get familiar with it when working on a microservices architecture.
When using the Docker-Compose sub-generator, you will be asked if you want to add monitoring to your infrastructure. This option, will add the JHipster-Console to your
docker-compose.yml file. Once started, it will be available on http://localhost:5601 and start to gather your applications’ logs and metrics. For instructions on how to set up monitoring for your applications please refer to the monitoring documentation.
Compared with monolithic applications, gateways and microservices monitoring configuration provide additional features to help you effectively monitor a microservices cluster. For example logs are enriched with each application’s name, host, port and Eureka ServiceId so that you can trace from which service they are originating from. Moreover the JHipster Console comes with default dashboards that give you a view of all your services at the same time.
As Docker Swarm uses the same API as Docker Machine, deploying your microservices architecture in the cloud is exactly the same as deploying it on your local machine. Follow our Docker Compose documentation to learn more about using Docker Compose with JHipster.
The Cloud Foundry sub-generator works the same with a microservices architecture, the main difference is that you have more applications to deploy:
- Use the sub-generator to deploy first the JHipster Registry (which is a normal JHipster application).
- Note the URL on which your JHipster Registry is deployed. Your applications must all point to that URL:
- In the
spring.cloud.config.urimust point to
- In the
eureka.client.serviceUrl.defaultZonemust point to
- In the
- Deploy your gateway(s) and microservices
- Scale your applications as usual with Cloud Foundry
One important point to remember is that the JHipster Registry isn’t secured by default, and that the microservices are not supposed to be accessible from the outside world, as users are supposed to use the gateway(s) to access your application.
Two solutions are available to solve this issue:
- Secure your Cloud Foundry using specific routes.
- Keep everything public, but use HTTPS everywhere, and secure your JHipster Registry using Spring Security’s basic authentication support
The Heroku sub-generator works nearly the same with a microservices architecture, the main difference is that you have more applications to deploy:
Deploy a JHipster Registry directly with one click:
Please follow the Heroku sub-generator documentation in order to understand how to secure your JHipster Registry.
Note the URL on which your JHipster Registry is deployed. Your applications must all point to that URL in their
application-prod.yml file. Change that configuration to be:
eureka: instance: hostname: https://admin:[password]@[appname].herokuapp.com prefer-ip-address: false
You can now deploy and scale the gateway(s) and microservices. The Heroku sub-generator will ask you a new question, to know the URL of your JHipster Registry: this will allow your applications to fetch their configuration on the Spring Cloud Config server.