Deploying to Kubernetes
This sub-generator allows deployment of your JHipster application to Kubernetes.
Limitations
- Cassandra is not supported yet
- Kubernetes v1.9+ is required
Pre-requisites
You have to install:
You must have a Docker registry. If you don’t have one, you can use the official Docker Hub
Minikube
Minikube is a tool that makes it easy to run Kubernetes locally. Minikube runs a single-node Kubernetes cluster inside a VM on your laptop for users looking to try out Kubernetes or develop with it day-to-day.
You can use it to test your application before pushing it to Kubernetes.
Running the sub-generator
To generate config files for Kubernetes, run this command in a new folder:
jhipster kubernetes
Then answer all the questions to deploy your application.
Which type of application would you like to deploy?
Your type of application depends on whether you wish to deploy a microservices architecture or classical applications.
Enter the root directory where your applications are located
Enter the path.
Which applications do you want to include in your Kubernetes configuration?
Select your applications.
Enter the admin password used to secure the JHipster Registry admin
This question is only displayed if you choose microservices architecture.
What should we use for the Kubernetes namespace?
See the documentation on namespace here
What should we use for the base Docker repository name?
If you choose Docker Hub as main registry, it will be your Docker Hub login.
If you choose Google Container Registry, then it’ll be gcr.io/[PROJECT ID]
, or a regional registry, such as eu.grc.io/[PROJECT ID]
, us.gcr.io/[PROJECT ID]
, or asia.gcr.io/[PROJECT ID]
. See Pushing and Pulling Images for more detial.
What command should we use for push Docker image to repository?
The default command to push to Docker Hub is docker image push
If you use Google Container Registry to host your Docker images, it will be: gcloud docker push
Updating your deployed application
Preparing a new deployment
When your application is already deployed, you can re-deploy it by building a new Docker image:
./mvnw package -Pprod -DskipTests dockerfile:build
Or when using Gradle:
./gradlew -Pprod bootWar buildDocker -x test
Pushing to Docker Hub
Tag locally your image:
docker image tag application username/application
Push your image to Docker Hub:
docker image push username/application
Deploying a monolith application
Deploy your application:
kubectl apply -f application/
It will create a Kubernetes deployment for your application and its associated dependent services (database, Elasticsearch…) as well as a Kubernetes service to expose the application to the outside.
Deploying a microservice application
Before deploying your microservices, first deploy the service discovery service (JHipster Registry or Consul). If you selected JHipster Console or Prometheus, it is recommended to deploy them before the microservices. The sub-generator placed a README file with the correct order of execution.
Custom namespaces
It is possible to specify a custom namespace for the entire deployment. To perform custom commands, you have to specify the target namespace, like in this example:
kubectl get pods -n <custom-namespace>
Scaling your deployments
You can scale your applications using
kubectl scale deployment <app-name> --replicas <replica-count>
Zero downtime deployments
The default way to update a running application in Kubernetes is to deploy a new image tag to your Docker registry and then deploy it using:
kubectl set image deployment/<app-name>-app <app-name>=<new-image>
Using livenessProbes and readinessProbe allows you to tell Kubernetes about the state of your applications, in order to ensure availability of your services. You will need a minimum of 2 replicas for every application if you want to have zero downtime deployment. This is because the rolling upgrade strategy first kills a running replica in order to place a new one. Running only one replica will cause a short downtime during upgrades.
Deploying a Service Registry in Kubernetes
Although Kubernetes features its own internal service discovery with Kube-DNS, JHipster rely on Spring Cloud for service discovery, so it depends on a third party service registry like Eureka or Consul. This has the advantage of being platform independent and to work similarly in production and on a local development machine.
Consequently, for microservices applications, the JHipster Kubernetes sub-generator will generate Kubernetes manifest files to deploy service registries like the JHipster-Registry (based on Eureka) or Consul. Moreover, the generated microservices and gateway Kubernetes manifests will contains the appropriate configuration to register themselves to their central registry.
Managing the JHipster Registry or Consul in Kubernetes
For the JHipster Registry and Consul, StatefulSets configurations are provided. Those are a special kind of Kubernetes resources that can handle stateful applications and will let you scale your service registries for high availability. For more information on high-availability for Eureka and Consul refer to their respective documentation.
Centralized configuration in Kubernetes
Centralized configuration is also setup using either Spring Cloud Config Server (when using the JHipster Registry) or the Consul Key/Value store (when using Consul). By default, both configuration servers load their configuration from a Kubernetes ConfigMap which contains property files in this format:
apiVersion: v1
kind: ConfigMap
metadata:
name: application-config
namespace: default
data:
application.yml: |- # global properties shared by all applications
jhipster:
security:
authentication:
jwt:
secret: secret
gateway-prod.yml: |- # gateway application properties for the "prod" profile
foo:
bar: foobar
By default, configuration servers run in development mode, which means that YAML property files are read directly from the filesystem and hot-reloaded on changes. For production it is advised to setup configuration from a Git repository as explained in our microservice documentation for the JHipster-Registry config server and Consul config server.
Exposing headless services
The registry is deployed using a headless service in Kubernetes, so the primary service has no IP address, and cannot get a node port. You can create a secondary service for any type, using:
kubectl expose service jhipster-registry --type=NodePort --name=exposed-registry
and explore the details using
kubectl get svc exposed-registry
For scaling the JHipster Registry, use
kubectl scale statefulset jhipster-registry --replicas 3
Monitoring tools
The sub-generator provides monitoring tools and configuration for usage with your applications.
JHipster Console
Your application logs can be found in JHipster Console (powered by Kibana). You can find its service details by
kubectl get svc jhipster-console
Point your browser to an IP of any of your nodes and use the node port described in the output.
Prometheus metrics
If not already done, install the Prometheus operator by CoreOS. You can quickly deploy the operator using
kubectl create -f https://raw.githubusercontent.com/coreos/prometheus-operator/master/bundle.yaml
hint: you must build your applications with the prometheus
profile active!
The Prometheus instance for your applications can be explored using
kubectl get svc prometheus-appname
Taking Advantage of Kubernetes
Kubernetes offers a number of facilities out-of-the-box to help with Microservices deployments, such as:
- Service Registry - Kubernetes
Service
is a first-class citizen that provides service registry and lookup via DNS name. - Load Balancing - Kubernetes Service acts as a L4 load balancer
- Health Check - Liveness probes and readiness probes help determine the health of the service.
- Configuration - Kubernetes
ConfigMap
can be used to store and apply configuration outside of the application.
There are a number of benefits of using Kubernetes facilities:
- Simplified deployment
- No need for additional Eureka/Consul deployment
- No need for Zuul to proxy/route requests
- No need for Ribbon
At the same time, there are some drawbacks:
- No Application Management through JHipster Registry - This function relies on Spring Cloud’s
DiscoveryClient
. This can be updated in the future to addspring-cloud-kubernetes
- No local Docker Compose support - You must use
minikube
for local development, and use Ingress to route traffic - No request-level load balancing - Kubernetes Service is a L4 load balancer that load balances per connection. Use Istio for request level load balancing (see below).
Using Kubernetes as Service Registry
To avoid relying on Eureka or Consul, you’ll need to disable service discovery altogether
- When asked
Which service discovery server do you want to use?
, simply chooseNo service discovery
A JHipster Gateway usually fronts the API calls and routing these calls using Zuul
. Without a service registry, routing via Zuul
won’t work. You’ll need to use Kubernetes Ingress
to route the traffic to microservices.
- When asked
Choose the kubernetes service type for your edge services
, chooseIngress
.
Istio
You can deploy microservices into Istio-enabled Kubernetes cluster. While Kubernetes manages microservices deployment and configuration, Istio can manage service to service communication, such as request-level load balancing, retries, circuit breakers, traffic routing/splitting, and more.
To enable Istio support:
- When asked
Do you want to configure Istio?
, choose one of the Istio options - When asked
Do you want to generate Istio route files
, chooseYes
to generate default configuration for circuit breaking, etc.
Troubleshooting
My applications don’t get pulled, because of ‘imagePullBackoff’
Check the registry your Kubernetes cluster is accessing. If you are using a private registry, you should add it to your namespace by kubectl create secret docker-registry
(check the docs for more information).
My applications get killed, before they can boot up
This can occur, if your cluster has low resources (e.g. Minikube). Increase the initialDelySeconds
value of livenessProbe of your deployments.
My applications are starting very slow, despite I have a cluster with many resources
The default setting is optimized for middle-scale clusters. You are free to increase the JAVA_OPTS environment variable, resource requests and limits to improve the performance. Be careful!
I have selected Prometheus but no targets are visible
This depends on the setup of Prometheus operator and the access control policies in your cluster. Version 1.6.0+ is needed for the RBAC setup to work.
I have selected Prometheus, but my targets never get scraped
This means your applications are probably not built using the prometheus
profile in Maven/Gradle
My SQL-based microservice are stuck during Liquibase initialization when running multiple replicas
Sometimes the database changelog lock gets corrupted. You will need to connect to the database using kubectl exec -it
and removes all lines of liquibases databasechangeloglock
table.