The life of a .NET application in Kubernetes

Maintaining a given set of containers is one of the main benefits of using Kubernetes .





In this article, I would like to understand this aspect in practice, namely, how to check whether containers are alive and how they are restarted if necessary, as well as how we, application developers, can help the orchestration system in this matter.





To start experimenting, I need a Kubernetes cluster. I will be using the test environment provided by Docker Desktop. To do this, you just need to activate Kubernetes in the settings.





How to install Docker Desktop on Windows 10 can be found in the first part of this article .





Building a Web API

For further experimentation, I'll create a simple web service based on the ASP.NET Core Web API template.





New project called WebApiLiveness
New project called WebApiLiveness

I will add through the Package Manager a package for generating random text with the command Install-Package Lorem.Universal.Net -Version 3.0.69







Change the Program.cs file





using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using System;

namespace WebApiLiveness
{
    public class Program
    {
        private static int _port = 80;
        private static TimeSpan _kaTimeout = TimeSpan.FromSeconds(1);

        public static void Main(string[] args)
        {
            CreateAndRunHost(args);
        }

        public static void CreateAndRunHost(string[] args)
        {
            var host = Host
                .CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder
                        .UseKestrel(options => 
                        {
                            options.ListenAnyIP(_port);
                            options.Limits.KeepAliveTimeout = _kaTimeout;
                        })
                        .UseStartup<Startup>();
                })
                .Build();

            host.Run();
        }
    }
}
      
      



I will add the LoremService class to the project , which will return a randomly generated text





using LoremNET;

namespace WebApiLiveness.Services
{
    public class LoremService
    {
        private int _wordCountMin = 7;
        private int _wordCountMax = 12;

        public string GetSentence()
        {
            var sentence = Lorem.Sentence(_wordCountMin, _wordCountMax);
            return sentence;
        }
    }
}
      
      



In the Startup class I will register the created service





public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<LoremService>();
    services.AddControllers();
}
      
      



LoremController





using Microsoft.AspNetCore.Mvc;
using System;
using System.Net;
using WebApiLiveness.Services;
using Env = System.Environment;

namespace WebApiLiveness.Controllers
{
  [ApiController]
  [Route("api/[controller]")]
  public class LoremController : ControllerBase
  {
    private readonly LoremService _loremService;

    public LoremController(LoremService loremService)
    {
        _loremService = loremService;
    }

    //GET api/lorem
    [HttpGet]
    public ActionResult<string> Get()
    {
      try
      {
          var localIp = Request.HttpContext.Connection.LocalIpAddress;
          var loremText = _loremService.GetSentence();
          var result =
            $"{Env.MachineName} ({localIp}){Env.NewLine}{loremText}";
          return result;
      }
      catch (Exception)
      {
          return new StatusCodeResult(
            (int)HttpStatusCode.ServiceUnavailable);
      }
    }
  }
}
      
      



, Dockerfile . , ASP.NET .NET 5.





FROM mcr.microsoft.com/dotnet/aspnet:5.0-buster-slim
COPY bin/Release/net5.0/linux-x64/publish/ App/
WORKDIR /App
ENTRYPOINT ["dotnet", "WebApiLiveness.dll"]
      
      







Project structure

dotnet publish -c Release -r linux-x64







, Dockerfile. , docker build -t sasha654/webapiliveness .







, Docker Hub docker push sasha654/webapiliveness







. Docker Hub, , sasha654 Docker ID, .





Kubernetes, , Docker docker run -p 8080:80 -d sasha654/webapiliveness







curl http://localhost:8080/api/lorem







! , , .





Kubernetes

Kubernetes, Pod – , () ( ) .





. Kubernetes – ReplicaSet, .





ReplicaSet 3 sasha654/webapiliveness. api: loremapi.





apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myrs
spec:
  replicas: 3
  selector:
    matchLabels:
      api: loremapi
  template:
    metadata:
      labels:
        api: loremapi
    spec:
      containers:
      - name: webapiliveness
        image: sasha654/webapiliveness
      
      



kubectl create -f kuber-rs.yaml



, kubectl get rs



kubectl get pods --show-labels







, Service LoadBalancer . , , spec.





apiVersion: v1
kind: Service
metadata:
  name: mylb
spec:
  type: LoadBalancer
  selector:
    api: loremapi
  ports:
  - port: 8080
    targetPort: 80
      
      



kubectl get svc







Postman http://localhost:8080/api/lorem



. .





. . , , . , . , , Program.cs KeepAliveTimeout 1 , 2 , . , , , .





- , , - , , Kubernetes . Pod , , - , Kubernetes Pod.





, kubectl delete pod myrs-jqjsp



, , .





kubectl delete all --all







, , Kuberntes .





, , , Kubernetes , . , , , Kubernetes, .





, 3 .





  • exec. 0, .





  • TCP-. , .





  • GET- . , , , .





-, GET-. Docker Hub 1, .. - 2 .





LoremService , API, , Kubernetes .





using LoremNET;
using System;

namespace WebApiLiveness.Services
{
    public class LoremService
    {
        private int _wordCountMin = 7;
        private int _wordCountMax = 12;
        private int _numRequestBeforeError = 5;
        private int _requestCounter = 0;

        public LoremService()
        {
            IsOk = true;
        }

        public bool IsOk { get; private set; }

        public string GetSentence()
        {
            if (_requestCounter < _numRequestBeforeError)
            {
                _requestCounter++;
                var sentence = Lorem.Sentence(
                    _wordCountMin, _wordCountMax);
                return sentence;
            }
            else
            {
                IsOk = false;
                throw new InvalidOperationException(
                    $"{nameof(LoremService)} not available");
            }
        }
    }
}
      
      



HealthController, GET- .





using Microsoft.AspNetCore.Mvc;
using System.Net;
using WebApiLiveness.Services;

namespace WebApiLiveness.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class HealthController
    {
        private readonly LoremService _loremService;

        public HealthController(LoremService loremService)
        {
            _loremService = loremService;
        }

        //GET api/health
        [HttpGet]
        public StatusCodeResult Get()
        {
            if (_loremService.IsOk)
            {
                return new OkResult();
            }
            else
            {
                return new StatusCodeResult(
                    (int)HttpStatusCode.ServiceUnavailable);
            }
        }
    }
}
      
      



, Docker Hub, 2.





ReplicaSet . , , 1 , livenessProbe, Kubernetes .





apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myrs
spec:
  replicas: 1
  selector:
    matchLabels:
      api: loremapi
  template:
    metadata:
      labels:
        api: loremapi
    spec:
      containers:
      - name: webapiliveness
        image: sasha654/webapiliveness:2
        livenessProbe:
          httpGet:
            path: /api/health
            port: 80
          initialDelaySeconds: 10
          periodSeconds: 3
      
      



. , ReplicaSet Service.





5 http://localhost:8080/api/lorem



.





.





, kubectl describe pod myrs-787w2







.





, , Kebernetes - (Readiness). , , . . - . , . , , Kubernetes .





Finally, I will mention that ASP.NET provides Microsoft.AspNetCore.Diagnostics.HealthChecks middleware to make it easy to create test scripts. In particular, there are functions that allow you to check external resources, for example, a SQL Server DBMS or a remote API.





Here is the project repository .








All Articles