Microservices with Kotlin, Kubernetes, and Istio
KHipster is a development platform to generate, develop and deploy Spring Boot + Angular/React/Vue Fullstack Web applications and Spring microservices. KHipster is built on top of JHipster.
In this post, we will do the following:
- Generate microservices with KHipster using JHipster Description Language (JDL)
- Generate Kubernetes configuration using JDL
- Generate code using KHipster
- Create a Kubernetes cluster in GCP
- Install Istio CLI and deploy Istio in Kubernetes cluster
- Deploy applications in Kubernetes cluster
Let us get started.
Generate Microservices with KHipster
Step 1: Install KHipster
KHipster is available as an NPM package. To install it run:
λ npm i -g generator-jhipster-kotlin
Do not have Node installed? Check out
nvm
(Node Version Manager) that makes it easy to setup Node - here.
Now, verify the installation by running:
λ khipster
Step 2: Create JDL file
The JDL is a JHipster-specific domain language.
JDL provides a DSL to describe the applications, deployments, entities and their relationships. Applications
refer to the service as a whole, the application can be a monolith or microservice. The deployments
refer to the way to deploy the application it can be kubernetes
. The entities
straightaway maps to the database table in your application. The relationships
refers to the entity relationship one-to-one
, one-to-many
, etc.,. JDL simplifies the process of creating the microservices applications and entities.
// Gateway application
application {
config {
applicationType gateway
authenticationType jwt
baseName gateway
buildTool gradle
clientFramework react
databaseType sql
devDatabaseType h2Disk
prodDatabaseType mysql
packageName com.sendilkumarn
serverPort 8080
serviceDiscoveryType no
}
entities *
}
// Microservice application
application {
config {
applicationType microservice
authenticationType jwt
baseName service
buildTool gradle
databaseType sql
devDatabaseType h2Disk
prodDatabaseType mysql
packageName com.sendilkumarn
serverPort 8081
serviceDiscoveryType no
}
entities product
}
// Product entity
entity product {
name String required
price Long required
}
We have defined 2 applications: gateway
and service
, and an entity: product
. The major difference between gateway
and service
:
gateway
usesclientFramework
asreact
,applicationType
asgateway
service
usesapplicationType
asmicroservice
Refer we have used
serviceDiscoveryType no
, this implies that we are not using serviceDiscovery in the microservices. We will use Istio for servicediscovery.
Did you know? JHipster supports
sql
andnoSql
database and it has many configuration options for generating the applications. Check the entire list of application configuration options here.
Generate Kubernetes configuration
KHipster provides kubernetes
option to generate the Kubernetes configuration file for the JHipster
generated applications. Interested to explore more about Kubernetes check out here. The jdl
accepts deployment
block to define the Kubernetes deployment.
deployment {
deploymentType kubernetes
appsFolders [gateway, service]
dockerRepositoryName "sendilkumarn"
serviceDiscoveryType no
istio true
kubernetesNamespace khipster
kubernetesServiceType Ingress
ingressDomain "<ip-address>.nip.io"
}
Note: It checks whether you have installed Docker since we need Docker for creating and pushing the images and use them later.
The Kubernetes definition is made inside the deployment
block with deploymentType
as kubernetes
. The appsFolders
points to the folders of the generated applications. We define the dockerRepositoryName
, this refers to docker user name here. Similar to applications, we define the serviceDiscoveryType
as no
(since we are going to use Istio
for service discovery). KHipster provides istio
support out of the box, we set the value to true
to use the istio configuration. We define the Kubernetes namespace using kubernetesNamespace
property. All the deployments & services use khipster
namespace to deploy the application.
Finally, We use Ingress
as the KubernetesServiceType
configuration. The smallest deployment unit of Kubernetes is a pod
. A pod is a group of Docker containers. Refer here for more information about the pods. Each pod gets IP address during its creation. If we have to access the application we have to connect to the pod's IP address (with port if applicable). In the Kubernetes cluster, pods are created and destroyed automatically based on various factors. So when a pod spawns newly, IP address referring them might change.In order to connect to running applications in the pods, we use services. Services define a set of pods and a way to access them. The services is like a loadbalancer or service discoverer that helps to identify the pods with a name to it.
Kubernetes provide three types of service type:
- Cluster IP - This exposes service to an cluster internal IP
- Nodeport - This exposes the service to an port
- Load Balancer - This exposes the service to an external IP
With Kube-DNS, Kubernetes also maps the service to an external name. Refer here for more infomration.
Ingress is not a service type, but with Ingress you can expose the service. The ingress acts as an entry point for your cluster. It is ideal for exposing multiple services under the same IP address.
Istio comes with an ingress-controller
and exposes IP, we will use that to access our services. We provide the IP address using ingressDomain
property.
Note:
.nip.io refer the nip.io at the end. nip.io helps to redirect the URL- Refer here for more information.
Generate code using KHipster
The khipster import-jdl
imports the JDL
file and generates the application and the deployment configuration files.
λ khipster import-jdl app.jdl
Gateway application generated successfully.
Service application generated successfully.
Kubernetes configuration generated successfully.
Login the docker using docker login
. Now go and build each services in their respective folders:
λ ./gradlew bootJar -Pprod jib -Djib.to.image=<docker-username>:<app-name>
KHipster also uses
maven
as a build tool.
Create a Kubernetes cluster in GCP
Install gcloud here.
λ gcloud beta container --project <project-name> clusters create "khipster-cluster" --machine-type "c2-standard-4" --num-nodes "2" --zone "us-central1-c"
We create a cluster named khipster-cluster
in the given project. We define the machine-type
with c2-standard-4
with 2 nodes in the us-central1-c
zone. This will take a while to complete, since it has to create a cluster from the scratch.
Explore more about K8s installation in the GCP here.
Install Istio CLI and deploy Istio in Kubernetes cluster
Istio is a
service mesh
for Kubernetes. Istio acts as a service discovery (connect), authenticate and authorize communication between services (secure), apply policies to services (control), collect telemetry and monitor services (observe) - Istio website
To install the CLI manually in your system and set up the path, run:
λ curl -L https://istio.io/downloadIstio | sh -
λ cd istio-1.8.0
λ export PATH=$PWD/bin:$PATH
Note: The bare Kubernetes configuration might not have the required cluster admin role. To create the clusterrolebinding
with cluster-admin
role for the selected account.
λ kubectl create clusterrolebinding cluster-admin-binding \
--clusterrole=cluster-admin \
--user="$(gcloud config get-value core/account)"
clusterrolebinding.rbac.authorization.k8s.io/cluster-admin-binding created
To install the Istio on the Kubernetes cluster, run the following:
λ istioctl install --set profile=demo -y
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
Istio supports various configuration profiles
for installation. Check out their differences here. We are using the demo profile.
Once the installation is complete refer the installation is complete using:
λ kubectl get ns istio-system
Ingress exposes
HTTP
andHTTPS
routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource.
Ingress provides an external IP with which we connect to the services running inside the Kubernetes cluster. The Ingress also provides load balancing, SSL / TLS, and others. Istio comes with an ingress gateway. Get the IP address by running the following command:
λ kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}'
xxx.xxx.xxx.xxx
Our application will be accessible via the above IP address.
Deploy applications in Kubernetes cluster
The KHipster
generates a set of configruation files for different services. They are as follows:
.
├── README.md
├── service
│ ├── service-deployment.yml
│ ├── service-destination-rule.yml
│ ├── service-mysql.yml
│ ├── service-service.yml
│ ├── service-virtual-service.yml
│ └── jwt-secret.yml
├── gateway
│ ├── gateway-deployment.yml
│ ├── gateway-destination-rule.yml
│ ├── gateway-gateway.yml
│ ├── gateway-mysql.yml
│ ├── gateway-service.yml
│ ├── gateway-virtual-service.yml
│ └── jwt-secret.yml
├── istio
│ ├── grafana-gateway.yml
│ ├── jaeger-gateway.yml
│ └── kiali-gateway.yml
└── kubectl-apply.sh
Each service has a separate folder and all the related configurations are placed inside the folder. For example:
The gateway
service has a gateway-deployment.yml
. The deployment
file describes the desired state of the deployment, like where is the actual Docker image, how many replicas to run, when to scale the services, etc.,. The Deployment controller in the Kubernetes takes care of ensuring all the conditions defined in the deployment file is met.
The gateway-destination-rule.yml
contains the network configuration related to Load Balancing, other connection related parameters, detect and evict unhealthy hosts using outlierDetection
.
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: gateway-destinationrule
namespace: default
spec:
host: gateway
trafficPolicy:
loadBalancer:
simple: RANDOM
connectionPool:
tcp:
maxConnections: 30
connectTimeout: 100ms
http:
http1MaxPendingRequests: 10
http2MaxRequests: 100
maxRequestsPerConnection: 10
maxRetries: 5
outlierDetection:
consecutiveErrors: 5
interval: 30s
baseEjectionTime: 60s
subsets:
- name: v1
labels:
version: 'v1'
Inside the yml
file, the spec
contains all the necessary information. The host
is the gateway
service.
Next we define the traffic policy. The traffic polocy starts with the load balancer configuration. The load balancer can either be simple
or consistent
. Simple
consists of a set of pre-configured load balancing configuration. By default simple
supports:
- RoundRobin
- Least Conn
- Random
- Pass through
We have chosen Random
here. The Istio team suggests that Random
is better than the RoundRobin
if we don't have any health configuration. It checks for the services that are healthy and routes the request to it. For more information on this — Check here for more information about these configuration.
Following the load balancer configuration, we have defined the connection pool. The connection pool instructs istio what is the time out, maximum pending requests, maximum number of requests, retries for failures etc.,. Finally we also specify the outlierDetection
, this helps istio to mark a service as unhealthy when it gives 5 errors consecutively in an interval of 30s.
Check out here for various options that you can define inside the destination-rule
here.
The gateway-gateway.yml
contains configuration for Istio’s Ingress gateway here. The gateway sit at the edge of the service mesh created by the Istio. It configures exposed ports and protocols and helps to connect to the underlying services. In our case the gateway exposes port 80
for http
and http2
connections.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway-gateway
namespace: default
labels:
gateway: gateway-gateway
istio: ingressgateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- gateway.khipster.<ingress-ip>.nip.io
- port:
number: 80
name: http2
protocol: HTTP2
hosts:
- gateway.khipster.<ingress-ip>.nip.io
Refer here for more information and options about the gateway configuration.
Note the host name, it consists of the service name, kubernetes namespace where we will deploy them,
followed by nip.io for redirection.
In addition to defining the gateway, we also added in a Virtual Service that exposes the gateway based on the routing.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: gateway-gw-virtualservice
namespace: default
labels:
service: gateway-gw-virtualservice
spec:
hosts:
- gateway.khipster.<ingress-ip>.nip.io
gateways:
- gateway-gateway
http:
- match:
- uri:
prefix: /application1/
route:
- destination:
host: application1
- match:
- uri:
prefix: /
route:
- destination:
host: gateway
Refer here for more information and configuration options available for Virtual Service.
The gateway-mysql.yml
includes all the necessary MySQL
database configuration. The gateway-service.yml
will abstract the gateway
application as a service
. The gateway-virtual-service.yml
as the name indicates, is a virtual
service for the gateway-service
. The jwt-secret.yml
consist of JSON Web Token secret for the application. We will have the same set of configuration for all the services for which we are generating the Kubernetes configuration.
To deploy applications in to the Kubernetes cluster, go into the kubernetes
folder and run the following command:
./kubectl-apply.sh apply -f
.nip.io refer the nip.io at the end. nip.io helps to redirect check here
Viola! Now the application is ready! Go to <ip-address>.nip.io
to check your microservices running.
Istio comes with kiali
, jaeger
& grafana
. Kiali helps to visualize the service mesh refer here for more information about Kiali. Refer here for what you can achieve with Kiali and Istio. Jaeger is the distributed tracing system, that helps to identify the your service architecture and its bottle necks. Refer here for more information. Finally grafana
to visualize everything.