Deploying ASP.NET Core App Using Kubernetes

In this blog post, we’ll guide you through building a Weather Forecast API using Kubernetes and MongoDB. We’ll start by explaining the code structure of the API, followed by setting up a Kubernetes cluster with deployments and services to host the API and MongoDB. Additionally, we’ll provide YAML configurations for Kubernetes deployments and services. To help you visualize the architecture, we’ve included an architecture diagram.

The Weather Forecast API

Our Weather Forecast API is built using ASP.NET Core and MongoDB. It provides weather forecasts with temperature and summaries. Let’s dive into the code structure:

using Microsoft.AspNetCore.Mvc;
using MongoDB.Driver;

namespace Weather.API.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;
        private readonly IMongoCollection<WeatherForecast> _weatherCollection;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, IMongoClient mongoClient)
        {
            _logger = logger;
            _weatherCollection = mongoClient.GetDatabase("weather").GetCollection<WeatherForecast>("weather");

            // Seed data during application startup
            SeedData();
        }

        private void SeedData()
        {
            // Check if the collection exists, and if not, create it
            if (!_weatherCollection.Database.ListCollectionNames().ToList().Contains("weather"))
            {
                _weatherCollection.Database.CreateCollection("weather");
            }

            // Check if the collection is empty before seeding data
            if (_weatherCollection.CountDocuments(FilterDefinition<WeatherForecast>.Empty) == 0)
            {
                var seedData = new List<WeatherForecast>();

                // Add seed data
                for (int i = 0; i < 10; i++)
                {
                    var weather = new WeatherForecast
                    {
                        Date = DateOnly.FromDateTime(DateTime.Now.AddDays(i)),
                        TemperatureC = Random.Shared.Next(-20, 55),
                        Summary = Summaries[Random.Shared.Next(Summaries.Length)]
                    };

                    seedData.Add(weather);
                }

                // Insert seed data into MongoDB
                _weatherCollection.InsertMany(seedData);
            }
        }

        [HttpGet("weather")]
        public IEnumerable<WeatherForecast> Get()
        {
            return _weatherCollection.AsQueryable().ToList();
        }

        [HttpPost]
        public IActionResult Post()
        {
            // Generate a random weather forecast
            var newWeather = new WeatherForecast
            {
                Date = DateOnly.FromDateTime(DateTime.Now),
                TemperatureC = Random.Shared.Next(-20, 55),
                Summary = Summaries[Random.Shared.Next(Summaries.Length)]
            };

            // Insert the new weather forecast into MongoDB
            _weatherCollection.InsertOne(newWeather);

            return Ok("Weather forecast added successfully.");
        }
    }
}

Program.cs

using MongoDB.Driver;

namespace Weather.API
{
    public static class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.

            builder.Services.AddControllers();
            string mongoConnectionString = "mongodb://mongodb-service:27017";

            // Register IMongoClient in the DI container
            builder.Services.AddSingleton<IMongoClient>(new MongoClient(mongoConnectionString));


            var app = builder.Build();

            // Configure the HTTP request pipeline.

            app.UseAuthorization();


            app.MapControllers();

            app.Run();
        }
    }
}

In this code, we initialize a MongoDB collection during controller construction and seed it with initial data. The Get method retrieves weather data from MongoDB, and the Post method adds new weather forecasts.

Setting up Kubernetes

Now, let’s set up a Kubernetes cluster to deploy our Weather Forecast API and MongoDB. We’ll provide the YAML configurations for deployments and services. To illustrate the architecture, here’s an architecture diagram:

Setting up Kubernetes

Now, let’s set up a Kubernetes cluster to deploy our Weather Forecast API and MongoDB. We’ll provide the YAML configurations for deployments and services.

Deployment for Weather Forecast API

apiVersion: apps/v1
kind: Deployment
metadata:
  name: weather-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: weather-app
  template:
    metadata:
      labels:
        app: weather-app
    spec:
      containers:
        - name: weather-app
          image: weather-api:1.0
          imagePullPolicy: Never
          ports:
            - containerPort: 80
          env:
            - name: MONGODB_CONNECTION_STRING
              value: "mongodb-service:27017"
---
apiVersion: v1
kind: Service
metadata:
  name: weather-app-service
spec:
  selector:
    app: weather-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  type: NodePort
  • apiVersion: Specifies the version of the Kubernetes API to use.
  • kind: Specifies the type of resource, which is a Deployment in this case.
  • metadata: Contains metadata for the Deployment, including its name.
  • spec: Defines the desired state for the Deployment.
    • replicas: Specifies the number of pod replicas to run. In this case, it’s set to 1, meaning one pod.
    • selector: Defines how to select which pods are controlled by this Deployment. It matches pods with the label app: weather-app.
    • template: Specifies the pod template.
      • metadata: Contains metadata specific to pods created from this template.
      • labels: Assigns the label app: weather-app to pods created from this template.
      • spec: Defines the specification for the pod.
        • containers: Specifies the containers to run in the pod.
          • name: The name of the container.
          • image: The Docker image to use for this container.
          • imagePullPolicy: Specifies the image pull policy, which is set to Never in this case, indicating that the image should not be pulled from a registry (useful for local development).
          • ports: Specifies the ports to expose within the pod.
          • env: Defines environment variables, including the MONGODB_CONNECTION_STRING required for connecting to MongoDB.

Deployment for MongoDB

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongodb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo
        ports:
        - containerPort: 27017
---
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
spec:
  selector:
    app: mongodb
  ports:
    - protocol: TCP
      port: 27017
      targetPort: 27017

These Kubernetes configurations deploy the Weather Forecast API and MongoDB, ensuring they communicate with each other.

These Kubernetes configurations deploy the Weather Forecast API and MongoDB, ensuring they communicate with each other.

Building the Docker Image

To run the Weather Forecast API in a Kubernetes cluster, we need to build a Docker image for it. Below is the Dockerfile for the Weather Forecast API:

# Dockerfile
# Use the ASP.NET Core runtime as the base image
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base
WORKDIR /app
EXPOSE 80
# Use the SDK image for building
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
WORKDIR /src
COPY ["Weather.API.csproj", "."]
RUN dotnet restore "./Weather.API.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "Weather.API.csproj" -c Release -o /app/build

# Publish the application
FROM build AS publish
RUN dotnet publish "Weather.API.csproj" -c Release -o /app/publish /p:UseAppHost=false

# Set the final base image
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Weather.API.dll"]

To build the Docker image, navigate to the directory containing the Dockerfile and run the following command:

docker build -t weather-api:1.0 .

This command builds a Docker image named weather-api with version 1.0. You can adjust the image name and version according to your preferences.

Deploying to Kubernetes

Now, let’s deploy the Weather Forecast API and MongoDB to your Kubernetes cluster using kubectl commands:

Deploy the Weather Forecast API:

kubectl apply -f weather-api-deployment.yaml

Deploy MongoDB:

kubectl apply -f mongodb-deployment.yaml

Port Forwarding for Development

During development, you can access the Weather Forecast API running in your Kubernetes cluster by setting up port forwarding:

kubectl port-forward service/weather-app-service 8080:80

Now, you can access the API locally at http://localhost:8080.

Conclusion

In this blog post, we’ve covered building a Weather Forecast API using ASP.NET Core and MongoDB and deploying it in a Kubernetes cluster. Kubernetes provides scalability and high availability for your application, while MongoDB serves as a reliable data store. This setup allows you to deliver accurate weather forecasts to your users while maintaining a resilient infrastructure.

By following the provided code, Dockerfile, Kubernetes configurations, and port forwarding instructions, you can create your own weather forecast API and harness the power of container orchestration and database management with Kubernetes and MongoDB.

Next Post Previous Post
No Comment
Add Comment
comment url