Build End-to-End .NET Core API And Angular Application Using Kubernetes

Introduction

Today we are going to build an end-to-end application using .NET Core API 6 and Angular 14

Prerequisites

  1. Understanding of Docker
  2. Basic understanding of Kubernetes
  3. Basic Understanding of .NET Core
  4. Understanding of Angular
  5. Docker Desktop with Kubernetes enabled over there.

For all the above topics you can visit my following blogs which are helpful to you to understand things easily that we are going to discuss in this blog.

Creating .NET Core API 6 Application

Step 1

Create .NET Core API 6 Application using VS Code for that use following command

First, create one directory on your local machine where we put both backend and frontend applications.

mkdir Product

cd Product

Next, create another folder ProductWebAPI

mkdir ProductWebAPI

cd ProductWebAPI

Later on, create a new .NET solution in the ProductWebAPI folder

dotnet new sln

Next, create the new web API project inside that which named ProductWebAPI

dotnet new ProductWebAPI -o

Finally, add the csproj file of ProductWebAPI into the sln file using following command

dotnet sln ADD ProductWebAPI.csproj

this way we create new .NET Core API project using Visual Studio 2022 in .NET version 6

Step 2

Now we create ProductController and create one simple endpoint which returns a list of products as shown below

using Microsoft.AspNetCore.Mvc;

namespace ProductWebAPI.Controllers;

[ApiController]
[Route("product")]
public class ProductController : ControllerBase
{
    private readonly ILogger<ProductController> _logger;

    public ProductController(ILogger<ProductController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    [Route("list")]
    public IDictionary<int,string> Get()
    {
        IDictionary<int, string> list = new Dictionary<int, string>();

            list.Add(1, "IPhone");
            list.Add(2, "Laptop");
            list.Add(3, "Samsung TV");

            return list;
    }
}

Here you can see we create one endpoint named as list and that will return a dictionary of a list of products that we are going to display using the Angular 14 application.

Step 3

Next, we are going to add CORS Policy into the Program class that is used in .NET Core 6

CORS Support

The full form of CORS is Cross-Origin Resource Sharing. It is a W3C standard that allows a server to make cross-domain calls from the specified domains while rejecting others By default due to browser security it prevents a web page from making one domain Ajax request to another domain.

But so many times we are using multiple domain applications which are required to call from one domain to another domain; in this case, we need to allow a cross-origin policy.

builder.Services.AddCors();
app.UseCors(builder =>
    {
        builder
        .AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader();
    });

So here you can see we put some code which is set CORS policy and we required that for the Angular application to fetch the data from the backend application.

Step 4

 Create the Dockerfile to create the Docker Image which we are going to use in the Kubernetes.

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app

# copy project csproj file and restore it in docker directory
COPY ./*.csproj ./
RUN dotnet restore

# Copy everything into the docker directory and build
COPY . .
RUN dotnet publish -c Release -o out

# Build runtime final image
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "ProductWebAPI.dll"]

So here you can see

  • First, we take .NET Core SDK and set the working directory for our application
  • Then copy our project csproj file into the docker directory
  • Later on, copy all remaining content from local to Docker Directory and create publish for that.
  • In the last section, we take aspnet image and copy our build content into their directory after set the working directory, and then lastly create the application endpoint.

Step 5

Now, if you want to see output then, run the application using the following .NET CLI command

dotnet run

Step 6

Let’s create a docker image and then check that will be working fine or not using the following command

(Note: make sure Docker Desktop is running fine and Kubernetes is enabled on that)

docker build -t productapi:v1 .

then run this image into the docker container

docker run -p 3000:80 productapi:v1

finally, you can see the output after hitting the URL http://localhost:3000/product/list

So, this is all about docker and we saw how we create the docker image and run it into the container. Now stop the container and follow next steps

Now we are going to create the manifest file for our backend application

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapi
  labels:
    app: product-app
spec:
  replicas: 2
  selector:
    matchLabels:
      service: webapi
  template:
    metadata:
      labels:
        app: product-app
        service: webapi
    spec:
      containers:
        - name: webapicontainer
          image: productapi:v1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
          env:
            - name: ASPNETCORE_URLS
              value: http://+:80
---
apiVersion: v1
kind: Service
metadata:
  name: webapiservice
  labels:
    app: product-app
    service: webapi
spec:
  type: NodePort
  ports:
    - port: 8080
      targetPort : 80
      protocol: TCP
  selector:
    service: webapi

Here you can see we create the deployment, pod, and services and then mentioned all details of our docker image, container, policy, and number of replicas of our application

Next, we apply this manifest file and create Deployment, Pods, Services, and Endpoints to manage Kubernetes Cluster and access the application

kubectl apply -f manifest.yml

This command will create Pods and Services inside Kubernetes you can see that using the following command

kubectl get pods

kubectl get services

kubectl get endpoints

kubectl get deployment

Here in the services section, you see endpoints to access the application, you can now access the application using the URL http://localhost:32224/product/list and you see below the output

So, this is all about the backend application.

Let’s start with the Angular Application which we are going to create using Angular 14 and use for the display data after fetching from the Backend Application.

Creating Angular 14 Application

Step 1

Create a new project inside the Project folder

ng new ProductWebAPP

Go inside ProductWebAPP directory

cd ProductWebAPP

Step 2

Create a new service to fetch data from backend application using HTTP Client module

ng g service demo

import { Injectable } from '@angular/core';
import configurl from '../assets/config/config.json';
import { Observable, Subject } from 'rxjs';
import { HttpClient } from '@angular/common/http';
import { Product } from './Model/Product';
@Injectable({
providedIn: 'root'
})
export class DemoService {
config = {
ApiUrl: configurl.apiServer.url,
};
constructor(private http: HttpClient) {
this.getJSON().subscribe((data) => {
this.config.ApiUrl = data.apiServer.url;
});
}
public getJSON(): Observable<any> {
return this.http.get('./assets/config/config.json');
}
getData(): Observable<any> {
return this.http.get(this.config.ApiUrl + '/product/list');
}
}

Step 3

Import the HTTP Client module into app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Step 4

Add the following code inside app.component.ts

import { Component } from '@angular/core';
import configurl from '../assets/config/config.json'
import { DemoService } from './demo.service';
import { Product } from './Model/Product';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
config = {
ApiUrl: configurl.apiServer.url,
};
title = 'Product App';
response: any = [];
constructor(private sharedService: DemoService)
{
}
ngOnInit(): void {
setTimeout(() => {
this.refreshProductList();
}, 1000);
}
refreshProductList() {
this.sharedService.getData().subscribe(data =>{
this.response = data;
console.log(this.response);
});
}
}

Step 5

Next, add the following HTML snippet to display the data which we are going to fetch from the backend application

<div>
  <h2>Data loaded from the Web API:</h2>
  <li *ngFor="let item of response | keyvalue"> 
    ID : {{item.key}}, Name: {{item.value}}
  </li>  
  </div>

Step 6

Create appEntryPoint.sh file which is use for set the dynamic port configuration

#!/bin/bash
envsubst < /usr/share/nginx/html/assets/config/config.template.json > /usr/share/nginx/html/assets/config/config.json && exec nginx -g 'daemon off;'

Step 7

Next, create nginx-custom.conf file which set some default Nginx server configuration

server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
}

Step 8

Create Dockerfile inside the root directory

### STAGE 1: Build ###
FROM node:16.10-alpine AS build
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build
### STAGE 2: Run ###
FROM nginx:1.17.1-alpine
COPY /nginx-custom.conf /etc/nginx/conf.d/default.conf
COPY --from=build /usr/src/app/dist/product-web-app /usr/share/nginx/html

# Copy the EntryPoint
COPY ./appEntryPoint.sh /
RUN chmod +x appEntryPoint.sh
ENTRYPOINT ["sh","/appEntryPoint.sh"]
CMD ["nginx", "-g", "daemon off;"]

So, here you can see,

  • First, we take the node image for our application and set the docker directory, and then copy package.json file and the remaining data inside the docker directory
  • In the second section, we take the Nginx server image and set the default configuration to that
  • Lastly, we set the entry point of our application and file which use to set the dynamic port at runtime.

Step 9

Also, Create config.json and config.template.json files inside the assets folder and config directory which use to set the backend API URL

{
    "apiServer": {
    "url": "http://localhost:3000",
    "version": "v1"
    }
}
{
    "apiServer": {
        "url": "${API_LINK}",
        "version": "v1"
    }
}

Step 10

Now, we are going to create docker image and run into the container using following command inside the root directory where your Dockerfile is present.

docker build -t productapi:v1

docker run -p 3002:80 productapi:v1

Finally, you can see the output which we get from the backend application using URL http://localhost:3002/, Now Stop the container and follow the next steps

Step 11

Let’s create manifest.yml file and apply it on Kubernetes to create cluster

apiVersion: apps/v1
kind: Deployment
metadata:
  name: webapp
  labels:
    app: product-app
spec:
  replicas: 2
  selector:
    matchLabels:
      service: webapp
  template:
    metadata:
      labels:
        app: product-app
        service: webapp
    spec:
      containers:
        - name: webappcontainer
          image: productapp:v1
          imagePullPolicy: IfNotPresent
          ports:
            - containerPort: 80
              protocol: TCP
          env:
            - name: API_LINK
              value: http://localhost:32224
---
apiVersion: v1
kind: Service
metadata:
  name: webappservice
  labels:
    app: product-app
    service: webapp
spec:
  type: NodePort
  ports:
    - port: 8080
      targetPort : 80
      protocol: TCP
  selector:
    service: webapp

kubectl apply -f manifest.yml

This command will create Pods and Services inside Kubernetes you can see that using following command

kubectl get pods

kubectl get services

kubectl get endpoints

kubectl get deployment

Here in the services section, you see endpoints to access the application, you can now access the application using the URL http://localhost:30055/  and you see below the output

Conclusion

We discussed how to create .NET Core API 6 and Angular 14 web applications and then containerize that step by step using Kubernetes.

I hope you understood everything we discussed in this blog

Happy Coding!