Kubernetes: Host Multi-Container ASP.NET Core app to Multiple Pods

Kubernetes: Host Multi-Container ASP.NET Core app to Multiple Pods

Suppose you have a Multi-Container ASP.NET Core app and you want to host it on Kubernetes Pods. Then you may ask how to do this? The answer is – host the containers on different k8s Pods then add a Service to expose a pod. Then second Pod will then access this service to communicate with first Pod.

Multi Pods and communication between Pods with Service

MyASP.NET Core app has 2 projects, one is Razor pages type and the other is of type Web API. The razor pages project will call the Web API project to get a random Joke which it then displays on the browser. I will be creating 2 Docker containers for containing these 2 projects. Then I will host these 2 containers on 2 Separate Kubernetes Pods. Finally, I will create a Service which will expose the Web API project running on a Pod. This will help the other project to call the web api through this service. I have tried to explain this concept by the below image.

multi pod communication kubernetes

In this image the Service 2 is exposing the Web API running on Container 2 (container 2 is running web api project). The app running on container 1 (container 1 is running razor pages project) will call this service 2 to access the web API. There is also another service, which is service 1, and it exposes the app on container 1 to the host i.e. to the web browser.

The Multi-Container App

The app is very simple. It’s a multi-project ASP.NET Core app. I build this app from start in my previous tutorial. If you want to go into the creation part then visit – Kubernetes: Host Multi-Container ASP.NET Core app to Single Pod.

If you want to skip the development part of the app then just download the app (link given at the bottom of this tutorial).

Now open the app and go inside the to the MultiApp project folder. There you will find the Pages folder, inside this folder find the Index.cshtml.cs file. Here on the OnGet() method the call to the web api is made. You have to change the URL of the Web API to:

http://service-2:8080/api/Joke 

This is done because the Web API will be running from a Docker container hosted on a Kubernetes Pod and this Kubernetes pod is exposed by this service.

Here service-2 is the name of the service and 8080 is the exposed port of the service.

I have shown this change in the highlighted way, see below code:

public async Task OnGet()
{
    using (var client = new System.Net.Http.HttpClient())
    {
        var request = new System.Net.Http.HttpRequestMessage();
        request.RequestUri = new Uri("http://service-2:8080/api/Joke");
        var response = await client.SendAsync(request);
        var joke = await response.Content.ReadAsStringAsync();

        var details = JObject.Parse(joke);
        ViewData["Joke"] = details["name"] + ";;" + details["text"] + ";;" + details["category"];
    }
}

Also check the below image where I have explained the port mappings of the service and the container running inside the Pod.

kubernetes service pod networking

I will build this “service-2” in just a moment so kindly be with me.

Building the Docker Images of the ASP.NET Core app

So, open your command prompt window and enter the minikube vm. The command is:

minikube docker-env

Then it will show you some list of texts, copy the last line, paste it and press enter:

@FOR /f "tokens=*" %i IN ('minikube -p minikube docker-env') DO @%i

You will enter minikube vm.

In the ASP.NET Core app there is a docker-compose.yml given on the root folder. So from your command prompt, navigate to this folder and build it by running the build command:

docker-compose build

Two images of the 2 projects will be created which you can see by running the docker images command on the command prompt. The images names are:

  • 1. multiapp
  • 2. multiapi
docker images created

Create Kubernetes Deployments and Services

Now I will create 2 Kubernetes Deployments that will create 2 Pods. Inside these Pods, 1 container each will run. As already discussed multiple times these containers will contain one project each of the ASP.NET Core app.

So, these are the 2 deployments configuration files. One file is named as “mydep1.yaml” while the other is “mydep2.yaml”. On downloading the source code you will find all the deployments and services inside the k8s Objects folder.

Deployment 1 – file “mydep1.yaml”
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep1
  labels:
    app: s1
spec:
  replicas: 1
  selector: 
    matchLabels:
      app: mc-app1
  template:
    metadata: 
      labels:
        app: mc-app1
    spec:
      containers:
        - name: mc1
          image: multiapp
          imagePullPolicy: Never
          ports:
            - containerPort: 80

The deployment 1 creates a deployment by the name of dep1. It also specifies to create a pod which should contain a docker container by the name of mc1. The image for the docker container (as you might have guessed) is specified as multiapp.

Also, container port 80 is exposed.

Deployment 2 – file “mydep2.yaml”
apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep2
  labels:
    app: s2
spec:
  replicas: 1
  selector: 
    matchLabels:
      app: mc-app2
  template:
    metadata: 
      labels:
        app: mc-app2
    spec:
      containers:
        - name: mc2
          image: multiapi
          imagePullPolicy: Never
          ports:
            - containerPort: 80

In the deployment the following things are specified:

  • Deployment by the name of dep2 is created.
  • Container by the name of mc2 is created. This container contains the image multiapi.
  • Container Port 80 is exposed containerPort: 80.

Next, in the command prompt window, go to the directory of these deployment files and apply them with kubectl apply. The command will be:

kubectl apply -f mydep1.yaml
kubectl apply -f mydep2.yaml
Service 2 – file “service2.yaml”

Now coming to the service which will expose the “myapi” project running on a Pod. The service config file called service2.yaml is given below.

apiVersion: v1
kind: Service
metadata:
  name: service-2
spec:
  type: NodePort
  selector:
    app: mc-app2
  ports:
    - port: 8080
      targetPort: 80

The metadata.name field specifies the name of the service as “service-2”

metadata:
  name: service-2

Note the port 8080 of the service is exposed and the service targets port 80 of the container. The ASP.NET Core app url has a default port of 80 so we don’t need to perform any extra settings here. Had this targetPort been different then we would have to tell asp.net core to expose another port for the url that is expose the port that has been assigned by the targetPort field. This is done by the use of environment variables.

ports:
    - port: 8080
      targetPort: 80

Now notice the selector field of the service.

selector:
    app: mc-app2

It says to apply this service to the deployment having a matchLabels as – app: mc-app2.

If you see the matchLabels field of the deployment 2, you will find the value as app: mc-app2.

matchLabels:
    app: mc-app2

In this way the service targets a particular deployment.

Now apply this service by running the following command

kubectl apply -f service2.yaml

Accessing Web API through the Service with “CURL”

Now I will show how to call Web API from the “service -2”. For this I will go inside the container “mc1” containing the “multiapp” image.

So, run kubectl get pods command which will show you 2 pods are running.

running k8s pods

These pods are dep1-86bb5964fd-bkgw2 and dep2-6668bf576f-9h985.

Next, I get inside the mc1 container contained inside the dep1-86bb5964fd-bkgw2 pod and start a shell. The command to run is given below:

kubectl exec -it dep1-86bb5964fd-bkgw2 -c mc1 -- /bin/bash
docker container shell

Next, I install curl in the container by running the following 2 command:

apt-get update
apt-get install curl

Finally run a curl command to the service-2:

curl http://service-2:8080/api/Joke

You will see a Joke json as a result. This shows the web api is called by the curl command. See below image:

curl k8s service

Exposing the app to the browser

I will not create another Kubernetes Service called service-1 and this will expose the Pod 1. Note that Pod 1 is containing “multiapp” image inside “mc1” container. See the below image which explains this:

multi pod communication kubernetes

The service-1 configuration file is given below. The file name is service1.yaml.

apiVersion: v1
kind: Service
metadata:
  name: service-1
spec:
  type: NodePort
  selector:
    app: mc-app1
  ports:
    - port: 8080
      targetPort: 80

See the selector field of this service:

selector:
    app: mc-app1

And it is same as the value of matchLabels field of the deployment 1.

matchLabels:
    app: mc-app1

Now apply this service by running the following command:

kubectl apply -f service1.yaml

Finally, you can run the following command to open the service-1 on a proxy on the browser:

minikube service service-1

I have shown this in the below image.

opening app on browser with k8s service

Using ASP.NET Core Environment variable

I can use environment variables to pass the “service-2” url (which is used to call the web api) from the deployment configuration yaml file. This will make our code dynamic. Let us see how to do it:

So, add an environment variable called WebApiBaseAddress and provide it the value of the web api in terms of service-2 i.e. http://service-2:8080/api/Joke.

I have shown the updated code in highlighted way.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: dep1
  labels:
    app: s1
spec:
  replicas: 1
  selector: 
    matchLabels:
      app: mc-app1
  template:
    metadata: 
      labels:
        app: mc-app1
    spec:
      containers:
        - name: mc1
          image: multiapp
          imagePullPolicy: Never
          ports:
            - containerPort: 80
          env:
            - name: WebApiBaseAddress
              value: http://service-2:8080/api/Joke

And now in the asp.net core app, change the code which is calling the web api as shown by the highlighted way:

public async Task OnGet()
{
    using (var client = new System.Net.Http.HttpClient())
    {
        var request = new System.Net.Http.HttpRequestMessage();
        
        string url = Environment.GetEnvironmentVariable("WebApiBaseAddress");
        request.RequestUri = new Uri(url);
                
        var response = await client.SendAsync(request);
        var joke = await response.Content.ReadAsStringAsync();

        var details = JObject.Parse(joke);
        ViewData["Joke"] = details["name"] + ";;" + details["text"] + ";;" + details["category"];
    }
}

Download the source code:

Download

Conclusion

In this tutorial I covered the networking between apps running on different pods. I also covered this scenario by creating an example with Multi-container ASP.NET Core app. If you like this tutorial kindly share on fb, twitter and other social community websites.

SHARE THIS ARTICLE

  • linkedin
  • reddit
yogihosting

ABOUT THE AUTHOR

I hope you enjoyed reading this tutorial. If it helped you then consider buying a cup of coffee for me. This will help me in writing more such good tutorials for the readers. Thank you. Buy Me A Coffee donate

Leave a Reply

Your email address will not be published. Required fields are marked *