Microservices with Kotlin, Kubernetes, and Linkerd
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 Linkerd CLI and deploy Linkerd in Kubernetes cluster
- Deploy ingress controller in Kubernetes
- Deploy applications in Kubernetes cluster
- Configure traffic to application
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 Linkerd 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 false
kubernetesNamespace khipster
kubernetesServiceType Ingress
}
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 Linkerd
for service discovery). KHipster provides istio
out of the box, since we are going to use Linkerd
for that. 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.
We need
ingress-controller
to expose services via ingress IP, we will set up ingress-controller below.
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>
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 Linkerd CLI and deploy Linkerd in Kubernetes cluster
Linkerd is a
service mesh
for Kubernetes. Linkerd makes running services easier and safer by giving you runtime debugging, observability, reliability, and security—all without requiring any changes to your code. - Linkerd website
Install the CLI manually in your system and set up the path, run:
λ curl -sL https://run.linkerd.io/install | sh
Linkerd stable-2.9.0 was successfully installed 🎉
λ export PATH=$PATH:$HOME/.linkerd2/bin
Check the installation by running:
λ linkerd version
Client version: stable-2.9.0
Server version: unavailable
Once the installation is completed. Before installing the Linkerd in the Kubernetes cluster, we wil check whether the Kubernetes cluster is configured correctly. We run:
λ linkerd check --pre
....
Status check results are √
The above command checks whether the kubernetes cluster is configured correctly and ready to install the Linkerd control plane.
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 Linkerd on the Kubernetes cluster, run the following:
λ linkerd install | kubectl apply -f -
The linkerd install
command creates the kubernetes configuration files. We pipe the configuration files using kubectl apply -f
command on those generated files. This will create the complete linkerd
in the kubernetes cluster. Once the installation is complete refer the installation is complete using
λ linkerd check
Deploy ingress controller in Kubernetes
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. We will install a vanilla version Nginx ingress controller:
λ kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.41.2/deploy/static/provider/cloud/deploy.yaml
Once the ingress-controller is installed in the Kubernetes cluster. Get the IP address by running the following command:
λ kubectl get svc ingress-nginx-controller -n ingress-nginx -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
To deploy applications in to the Kubernetes cluster, go into the Kubernetes folder and run the following command:
λ ./kubectl-apply.sh apply -f
All the deployments and services will be installed in the K8s cluster. Now we need to auto inject Linkerd into the khipster
namespace for all the services in that particular namespace.
Next, let's add Linkerd to khipster
namespace by running:
λ kubectl get -n khipster deploy -o yaml \
| linkerd inject - \
| kubectl apply -f -
You can also inject proxy automatically. Refer here for more information.
Now the Kubernetes cluster is ready with all the necessary configuration.
Configure traffic to application
Now the final step is to map the ingress service to the services. Note the annotation
in the metadata
section, the Nginx uses the proxy header to proxy the HTTP traffic. Refer here for more information.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
namespace: khipster
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header l5d-dst-override $service_name.$namespace.svc.cluster.local:$service_port;
spec:
rules:
- host: <ip-address>.nip.io
http:
paths:
- path: /
backend:
serviceName: gateway
servicePort: 80
- path: /service
backend:
serviceName: service
servicePort: 8081
.nip.io refer the nip.io at the end. nip.io helps to redirect check here
We have also defined the spec
section. The spec section provides the rules for redirection. We provide the host and map the path to the service with their name. Viola! Now the application is ready! Go to <ip-address>.nip.io
to check your microservices running.
Linkerd comes with dashboard
& grafana
to monitor the services, traffic, and everything. You can check them out using linkerd dashboard
.