Deploying JHipster Microservices on AWS EKS (Elastic Container Service for Kubernetes )
This is my first blog on medium, as a software entrepreneur and enthusiastic developer, I love JHIPSTER. So obviously I’m writing the blog about JHIPSTER. This blog is largely based on the blog of Deepu k Sasidharan the JHIPSTER co-lead.
Creating the microservice application
In a post of one of my fellow JHIPSTER enthusiasts, they showcased how to create a full stack microservice architecture using JHipster and JDL, read the post here if you want to learn more details about it. For this exercise, we will use the same application.
Let us recap the steps required.
Create a JDL file, let’s say app.jdl
, and copy the below content into it.
Now create a directory called ecommerce and navigate into it. Run the JHipster import-jdl command. It could take a few minutes, especially the NPM install step.
$ mkdir ecommerce && cd ecommerce
$ jhipster import-jdl app.jdl
Once the JHipster process is complete, you will see that we have our store gateway, invoice service and notification service created and ready for us. The process until this is explained in more detail in my previous post here and you can deploy the application locally using Docker as explained in that post. If you haven’t done that before I strongly suggest that step so that you get an idea of the application and you also can make sure it works locally on your machine.
Generating the Kubernetes configuration
Now that our application is ready, let us create the required configurations for Kubernetes using JHipster.
In the ecommerce folder, we created earlier, create a new directory, let’s call in k8s so that we get the below structure.
├── app.jdl
├── invoice
├── k8s
├── notification
└── store
Create the k8s directory and navigate to it. Now run the JHipster Kubernetes command there.
$ mkdir k8s && cd k8s
$ jhipster kubernetes
The generator will ask you a few questions and choose the answers as highlighted below, as you can see the questions are very similar to the ones asked by jhipster docker-compose
command. For the “base Docker repository name” provide your own docker hub account id(For example, my Docker Hub id is vrecon). For real-world use cases, you could also use a private image repository like the Amazon Elastic Container Registry or Azure Container Registry or and in that case, you would have to provide the AECR or ACR login server name here. For now, let us keep it simple.
⎈ Welcome to the JHipster Kubernetes Generator ⎈
Files will be generated in folder: /home/vrecon/workspace/temp/ecommerce/k8s
✔ Docker is installed? Which *type* of application would you like to deploy? Microservice application? Enter the root directory where your gateway(s) and microservices are located ../3 applications found at /home/deepu/workspace/temp/ecommerce/
? Which applications do you want to include in your configuration? invoice, notification, store? Do you want to setup monitoring for your applications ? No? Which applications do you want to use with clustered databases (only available with MongoDB and Couchbase)?JHipster registry detected as the service discovery and configuration provider used by your apps? Enter the admin password used to secure the JHipster Registry admin? What should we use for the Kubernetes namespace? default? What should we use for the base Docker repository name? <your Docker hub account id>? What command should we use for push Docker image to repository? docker push? Do you want to configure Istio? Not required? Choose the kubernetes service type for your edge services LoadBalancer - Let a kubernetes cloud provider automatically assign an IP
The generator will go to work with this and will create the following files and output.
create invoice/invoice-deployment.yml
create invoice/invoice-service.yml
create invoice/invoice-mysql.yml
create notification/notification-deployment.yml
create notification/notification-service.yml
create notification/notification-mongodb.yml
create store/store-deployment.yml
create store/store-service.yml
create store/store-mysql.yml
create README.md
create registry/jhipster-registry.yml
create registry/application-configmap.yml
create kubectl-apply.shWARNING! Kubernetes configuration generated with missing images!To generate the missing Docker image(s), please run:./gradlew -Pprod bootWar buildDocker in /home/vrecon/workspace/temp/ecommerce/invoice./gradlew -Pprod bootWar buildDocker in /home/vrecon/workspace/temp/ecommerce/notification./gradlew -Pprod bootWar buildDocker in /home/vrecon/workspace/temp/ecommerce/storeWARNING! 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 image tag invoice vrecon/invoice
docker push vrecon/invoicedocker image tag notification vrecon/notification
docker push vrecon/notificationdocker image tag store vrecon/store
docker push vrecon/storeYou can deploy all your apps by running the following script:
./kubectl-apply.shUse these commands to find your application's IP addresses:
kubectl get svc storeCongratulations, JHipster execution is complete!
As you can see the generator creates all the required Kubernetes configuration files and prints out useful information to proceed further (Note that the docker hub id you provided will be in the instructions in place of vrecon here). Go through the generated k8s files and familiarize yourself.
Let us build and push the docker images for our application. Follow the instructions above and build docker images in each of the application folders and then tag and push the images to your Docker hub account.
Preparing the AWS Cluster
Now that our applications are built and pushed its time for us to deploy them to AWS EKS. But before that let’s make sure we have all the prerequisites ready. You will need the below tools.
- kubectl: The command line tool to interact with Kubernetes. Install and configure it.
- AWS cli: Install the Latest AWS Command Line Interface
- eksctl: a CLI for Amazon EKS. Install and read this tutorial on how to get started.
Configure Your AWS CLI Credentials
Both eksctl
and the AWS CLI require that you have AWS credentials configured in your environment. The aws configure command is the fastest way to set up your AWS CLI installation for general use.
$ aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: us-west-2
Default output format [None]: json
Once the tools are ready let us prepare our Kubernetes cluster.
First, let us create the cluster. Run the below command. This will create a cluster named eCommerceCluster in US west location(You can use other AWS Regions as well).
eksctl create cluster --name eCommerceCluster
This would take several minutes to complete, and with several I mean a lot of minutes.
The output will look something like this:
[ℹ] using region us-west-2
[ℹ] setting availability zones to [us-west-2b us-west-2c us-west-2d]
[ℹ] subnets for us-west-2b - public:192.168.0.0/19 private:192.168.96.0/19
[ℹ] subnets for us-west-2c - public:192.168.32.0/19 private:192.168.128.0/19
[ℹ] subnets for us-west-2d - public:192.168.64.0/19 private:192.168.160.0/19
[ℹ] nodegroup "standard-workers" will use "ami-0923e4b35a30a5f53" [AmazonLinux2/1.12]
[ℹ] creating EKS cluster "ecommercecluster" in "us-west-2" region
[ℹ] will create 2 separate CloudFormation stacks for cluster itself and the initial nodegroup
[ℹ] if you encounter any issues, check CloudFormation console or try 'eksctl utils describe-stacks --region=us-west-2 --name=ecommercecluster'
[ℹ] building cluster stack "eksctl-ecommercecluster-cluster"
[ℹ] creating nodegroup stack "eksctl-ecommercecluster-nodegroup-standard-workers"
[✔] all EKS cluster resource for "ecommercecluster" had been created
[✔] saved kubeconfig as "/Users/ericn/.kube/config"
[ℹ] adding role "arn:aws:iam::111122223333:role/eksctl-prod-nodegroup-standard-wo-NodeInstanceRole-IJP4S12W3020" to auth ConfigMap
[ℹ] nodegroup "standard-workers" has 0 node(s)
[ℹ] waiting for at least 1 node(s) to become ready in "standard-workers"
[ℹ] nodegroup "standard-workers" has 2 node(s)
[ℹ] node "ip-192-168-22-17.us-west-2.compute.internal" is not ready
[ℹ] node "ip-192-168-32-184.us-west-2.compute.internal" is ready
[ℹ] kubectl command should work with "/Users/ericn/.kube/config", try 'kubectl get nodes'
[✔] EKS cluster "ecommercecluster" in "us-west-2" region is ready
Verify that we are able to connect to the cluster by running kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192–168–28–143.us-west-2.compute.internal Ready <none> 18h v1.12.7
ip-192–168–72–37.us-west-2.compute.internal Ready <none> 18h v1.12.7
Deploying the application to AWS EKS
Now that our cluster is ready, let us deploy our microservice stack to this cluster.
We can deploy our application using the kubectl apply
command for this we have to navigate to the k8s folder we created earlier and run the below commands in the same order
$ kubectl apply -f registry$ kubectl apply -f invoice$ kubectl apply -f notification$ kubectl apply -f store
Or you could also just run the handy kubectl-apply.sh
script generated which runs the above.
So we are deploying the JHipster Registry first as it is required for other services, followed by the microservices and finally our gateway(store).
If you get a timeout during any of these, as I did, just try the command again.
Though the services get created fast, the actual applications might not be up and running yet, give the entire thing a minute or two to start.
Now run kubectl get pods
to see the status of our containers.
$ kubectl get pods -wNAME READY STATUS
invoice-5ffb46d944-h8x42 1/1 Running
invoice-mysql-66bc4b7874-p7ghk 1/1 Running
jhipster-registry-0 1/1 Running
jhipster-registry-1 1/1 Running
notification-76847b7667-d7xjb 1/1 Running
notification-mongodb-6db986b556-8bw8z 1/1 Running
store-8dc5cd6f7-s2dpx 1/1 Running
store-mysql-779d66685d-tmkqd 1/1 Running
Wait until all the containers are in Running status. Once the containers are running we can run the kubectl get service
command to get the external IP for the application.
$ kubectl get service storeNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
store LoadBalancer 10.100.20.215 a317424b3765211e9831306d9c07d674-1390706390.us-west-2.elb.amazonaws.com 8080:32307/TCP 18h
In this case, the external IP for our gateway application is a317424b3765211e9831306d9c07d674–1390706390.us-west-2.elb.amazonaws.com running on port 8080. Opening this in the browser will give you the following result.
The JHipster registry is deployed as a headless service by default. If we need to access the registry we need to create a secondary service with a Load Balancer. Run the below command to expose the second service.
$ kubectl expose service jhipster-registry --type=LoadBalancer --name=exposed-registry
Now run the kubectl get service
command to get the IP.
$ kubectl get service exposed-registryNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
exposed-registry LoadBalancer 10.100.194.130 af86bcd7c765211e9831306d9c07d674-372126431.us-west-2.elb.amazonaws.com 8761:31185/TCP 18h
Visit the URL in a browser to see the registry in action
Conclusion
Kubernetes is definitely the best way to deploy microservice applications to production but creating and managing Kubernetes clusters itself is not an easy task, but Kubernetes services like EKSCTL make it a bit easier.
JHipster provides a great Kubernetes setup to start with which you can further tweak as per your needs and platform. Using AWS EKS is working great and scaling up and down instances' can be done quite easily.