On this blog post I will be going through all the process from creating a MicroServices application with JHipster to run the application into a KIND Kubernetes cluster.
KIND AND JHIPSTER LOGOS HERE
- JHipster CLI (Java, Maven)
- Docker
- You need to make sure that you allow Docker enough CPUs and memory to run the Applications (Docker -> Preferences -> Advanced). I've set up 4 CPUs and 8 GB RAM.
- kubectl
- KIND
We will generate an Application form a JHipster JDL DSL, which describes a JHipster Application using the MicroServices approach. This application is composed by:
- A Gateway that also hosts the User Internface
- Invoice Service (which hosts three entities: Shipment, Order, Invoice)
- Review Service (which doesn't have any entity but will be in charge of reviewing the Invoice Service Entities)
You can find the app.jdl file in this repository.
In order to create the source code for this application we need to import our JDL file by calling (you can find the app.jdl file inside the example-app/ directory):
> jhipster import-jdl app.jdl
By running this command we will generate 3 maven projects:
- gateway
- invoice
- review
Some details about these services:
- Gateway will run by default in port 8080
- Invoice and Review will use 8081
In order to run your application (microservices) in Kubernetes you need to generate Kubernetes Manifests, which are basically files that describe how Kubernetes will deploy and manage your services.
In general to work with JHipster into Kubernetes you will follow these steps:
Today, there are three ways in which you can create the K8s manifests:
- You create your own manifests
- You can use jhipster kubernetes generator
- You can use jhipster kubernetes-helm generator
Let's use the second option for simplicity (but I encourage you to try the HELM approach as well):
> mkdir kubernetes/
> cd kubernetes/
> jhipster kubernetes
Note: The generated manifest can be found inside example-app/kubernetes/. These manifests points to public docker images, if you want to use your locally generated images in KIND, you will need to modify the deployment manifests.
Then choose:
- Microservice application + Enter
- root directory ../ + Enter
- select the three services (gateway, invoice, review) with space and the arrows and then Enter
- Monitoring -> No
- Admin password (admin) Enter
- namespace: I will use "jhipster" + Enter
- name for the docker repository name (if you are planning to push your images to hub.docker.com) you should use your user name, I will use a local docker registry, so just Enter
- docker push (default value) + Enter
- No Istio for now
- Service Type for your edge services (in this case the gateway), I will choose LoadBalancer + Enter
An example of these manifests can be found here
After this all the Kubernetes Manifest to run your services are generated. The only missing step is to generate your docker images that are going to be used by these manifest to run your services in the cluster.
The output of the generation shows how to create these docker images for each service. Everytime that you make a change in the service, you should generate a new docker image to contain those changes:
To generate the missing Docker image(s), please run:
./mvnw -Pprod verify jib:dockerBuild in /gateway
./mvnw -Pprod verify jib:dockerBuild in /invoice
./mvnw -Pprod verify jib:dockerBuild in /review
You will also see in the output:
WARNING! You will need to push your image to a registry. If you have not done so, use the following commands to tag and push the images:
docker push gateway
docker push invoice
docker push review
This last step (of pushing the docker images) is only required if the Cluster is remote and you have no other way to make the images available to the cluster.
Now all you need is a cluster to run these services, welcome Kubernetes KIND.
KIND stands for Kubernetes in Docker and based on their own description:
kind is a tool for running local Kubernetes clusters using Docker container "nodes".
kind is primarily designed for testing Kubernetes 1.11+, initially targeting the conformance tests.
This is a great tool because it allows us to run a multi node cluster only depending on Docker. We don't need any VM tooling such as Vagrant used in projects like Minikube, for example. Also the fact that KIND is targeting conformance tests, means that we have an hermetic environment where we can run our tests against a cluster that looks (from the API and topology prespective) pretty much as our production environments.
KIND allows us to create and delete clusters in an automated fashion, then we can automate deploying our services into it. This becomes really important when we have services or Operators which needs to interact with the cluster, due we don't want to mock those interactions, we want to test the real cluster behaviour for our components.
With KIND installed just run:
> kind create cluster
Once the cluster is up, you can try it out with
> kubectl get pods
This should return
No resources found.
Before moving forward we need to generate the docker images for our services, let's run what was suggested by the "jhipster kubernetes"
To generate the missing Docker image(s), please run:
./mvnw -Pprod verify jib:dockerBuild in /gateway
./mvnw -Pprod verify jib:dockerBuild in /invoice
./mvnw -Pprod verify jib:dockerBuild in /review
Once this is done, we now should have 3 docker images loaded in our local Docker Deamon. Now we need to make these images available to KIND. Which we can do with:
> kind load docker-image gateway
> kind load docker-image invoice
> kind load docker-image review
Before running the services, we need to adapt some of the Manifests to make sure that the Docker Images are not downloaded from a remote docker registry. This is KIND specific. And this is only required if you want to run with your own custom images. If you want to run this application in a remote cluster the docker images for these services are published in Docker Hub:
- salaboy/gateway:jhipster
- salaboy/invoice:jhipster
- salaboy/review:jhipster
We need to change the following files inside the kubernetes (manifest directory, generated by jhipster kubernetes.):
- gateway/gateway-deployment.yml
- invoice/invoice-deployment.yml
- review/review-deployment.yml You need to locate the section:
containers:
- name: gateway-app
image: gateway
add
imagePullPolicy: Never
like:
containers:
- name: gateway-app
image: gateway
imagePullPolicy: Never
Also suggested by the generator to deploy all the services into K8s:
> bash kubectl-apply.sh
The output should look like:
namespace/jhipster created
configmap/application-config created
secret/registry-secret created
service/jhipster-registry created
statefulset.apps/jhipster-registry created
deployment.apps/gateway created
deployment.apps/gateway-mysql created
service/gateway-mysql created
service/gateway created
deployment.apps/invoice created
deployment.apps/invoice-mysql created
service/invoice-mysql created
service/invoice created
deployment.apps/review created
deployment.apps/review-mysql created
service/review-mysql created
service/review created
Notice that this created in the first line a new namespace called jhipster as it was instructred in the generator wizard. Also notice that we are creating 3 pods which will run MySQL, and KIND will need to fetch from Docker Hub the MySQL docker image the first time that you run these commands.
In order to change the current namespace (so we can get resources without specifying the namespace everytime) we can switch to the jhipster one by running:
> kubectl config set-context $(kubectl config current-context) --namespace=jhipster
Once this is done we can check that our services are running:
> kubectl get pods
We should see all the Pods up and running:
gateway-9ffdb4796-jf2j2 1/1 Running 0 6m17s
gateway-mysql-6dc7d6dcf8-glgmz 1/1 Running 0 6m17s
invoice-6c8cb9f459-6m99n 1/1 Running 0 6m17s
invoice-mysql-7fbbbb77b6-kx5jr 1/1 Running 0 6m17s
jhipster-registry-0 1/1 Running 0 6m17s
jhipster-registry-1 1/1 Running 0 5m38s
review-7b9b756d95-txctz 1/1 Running 0 6m16s
review-mysql-6db96464bd-scvsw 1/1 Running 0 6m16s
Then to access the service, because we are running
> kubectl port-forward svc/gateway 8080:8080 -n jhipster
Now you should be able to access your JHipster Application by pointing your browser to http://localhost:8080
Now you can run your JHipster Applications using KIND, which enable you to have a repeatable environment which is really close to what a production environment will look like. Future work might include use KIND for integration testing of our JHipster Applications. If you have questions feel free to drop me a message here on in Twitter: @salaboy.