Thursday, May 16, 2019

Kubernetes multi-service deployment and leveraging mounted volumes


How to deploy multiple services in a Kubernetes cluster and how to inject environment configuration settings on deployment time.


Introduction

The purpose of this article is to show how we can create a companion application to support the API and for the most part how to use mounted volume feature in Kubernetes to allow configuration information that needs to be passed to an application deployed on Kubernetes cluster. This article also services as the last part of the series of articles talking about leveraging the Kubernetes, docker and ASP.NET core to create a truly cloud native application.

Why

An obvious question is that why we care about mounted volume. The reason we care about mounted volume is because this how we can pass environment and configuration information to an application that is hosted by Kubernetes cluster. When creating an ASP.NET core application or any application that has configuration, we come across the question of configuration and how to handle it. We live in a world where application does not need to know which environment it is being hosted in. It just need to focus on what that application is designed for (creating value). The configuration information should be stay in the environment and the application when it is being provisioned should pick those configuration information and run with it. Mounted volume allows us to store environment specific information that the applications can use.

Solution

So far we have been successful in creating a Kubernetes cluster that is hosted an ASPNET Core Api. The next logical step is to add a front end application that will use the Api. We can host that frontend application anywhere but since we are using Kubernetes then why don’t we leverage Kubernetes and use the same cluster that we had created before.  So what this article will detail is how we go from single service Api deployed on a Kubernetes cluster to multi service (Api and Web App) deployed on Kubernetes cluster.
The following image shows the transition from initial state to the final state.


Source code for the API app can be found at: https://github.com/mnabeel/mac-api
Source code for the Web app can be found at: https://github.com/mnabeel/mac-app
Once we deploy the API app and Web and we query the services on the Kubernetes cluster by running “kubectl get services” command, we get the following:

The API app and deploying it to Kubernetes is pretty straight forward. It has self-contained database and now external dependencies. The case is different for the Web App as it needs to know the reference (endpoint url) to the API app. Since we are using Kubernetes to deploy the API app and Web App, we run into the issue that the URL of the API app can change whenever Kubernetes restarts the pod or we have to resurrect the Kubernetes cluster or services.
One solution could be that every time we see a change in the API endpoint, we update the source code for the Web App, recreate the docker image, push the docker image to the docker hub and then recreate Kubernetes deployment and expose the service.
The other solution is to use mount volume as secret to supply the url of the API app whenever there is a change in the API endpoint. And that is the purpose of this article.  To accomplish this will need to create a store in our web app that will carry the base URL of the API app. This is done be creating a folder called “secrets” and the creating a file called “appsettings.secrets.json” as shown below:

You can see that the ConnectionString element is pointing to a “localhost”.  When it is time to deploy will create “appsettings.secrets.json” as a secret and use it when we are creating a deployment for the Web app.  Let us take a look at the Deployment.yaml which is also part of the github repo for the web app mentioned above.

As mentioned above in the highlighted red square we have information about the volumeMounts and secrets. This is who we are declaring where the secrets will be mounted on the deployed service by Kubernetes. Important thing to note here is the secretName field. It is important to use the same value for secretName field that we will use in the step to create a secret in Kubernetes cluster. The value for secretName is : “secret-appsettings”
In order for us to deploy the Web App service in Kubernetes, we also need to create a Service.yaml file. Here is the screenshot:

We have the source code for the WebApp (github link provided in previous sections), we have the Deployment.yaml that tells us how the deployment will be created, and we also have the service.yaml that will tell the Kubernetes how to create the service from the deployment. That completes the prerequisites for deploying Web app to Kubernetes. We can now proceed to deploy. Here are the steps.
1.     Create secret:
“kubectl create secret generic secret-appsettings --from-file=./appsettings.secrets.json”
Running the above kubectl command will create the secret. One thing to note here is that we are using the same name for secret as we have in the Deployment.yaml which is “secret-appsettings”.
2.     Confirm that new secret has been created by running the following command:
“kubectl get secrets”

3.  Create Kubernetes deployment by running the following command:
“kubectl create –f deployment.yaml”
4.  Create Kubernetes service by running the following command:
“kubectl create –f service.yaml
That will deploy the web app in your Kubernetes cluster.


How to change the secret

Follow the following steps:
1.     Update the appsettings.secrets.json file from the runtime location of your command.
2.     Delete the old secret by running the following command
5.     Recreate the new secret (which will carry the new endpoint as it will reference the updated “appsettings.secrets.json” file) by running the following command:
“kubectl create secret generic secret-appsettings --from-file=./appsettings.secrets.json”

6.  Update the Web App deployment which will automatically push the change in the URL to Web App. This can be done many ways. What I have found easy to follow is to first delete the old deployment and then running the creating of deployment again as shown in the following command that was mentioned in the previous section:
“kubectl create –f deployment.yaml”

Here is how the application looks like:



This is basically a simple front end that displays the member information from the api and allows the user to enter a new member.  On the above screenshot, you will notice that I am printing some information about the host, environment, and the endpoint url to the API that the frontend app is using. This way I know what endpoint app is hitting for data. Notice that URL value is not showing http://localhost:8000 but it is showing this value as http://35.202.95.20 . This means our secret injecting on deployment time using mounted volume worked.

Conclusion

In this article we have seen how we can deploy two different applications in the same Kubernetes cluster and how we can use mounted volume to inject configuration information to an application that is deployed on a Kubernetes cluster. This article is the last part of the series articles that talk about deploy ASP.NET Core app using containerization technology and then leveraging Kubernetes as a container orchestration engine.


2 comments: