ASP.NET Core's cross-platform webserver Kestrel is the obvious choice, when running containerized .NET applications in a Kubernetes cluster.

As described in the article Graceful shutdown and zero downtime deployments in Kubernetes, Kestrel should be able to handle the SIGTERM signal from the Pod, so that incoming traffic is still processed when the application is being shut down.

Unfortunately, this is not how it works. Without further configuration, Kestrel-based applications in Kubernetes will have a small downtime when deploying a newer version in the Kubernetes cluster.

To have zero downtime deployment, the application's Pod configuration must use Kubernetes' preStop hook in the Pod definition:

apiVersion: v1
kind: Pod
metadata:
  name: my-dotnet-pod
spec:
  containers:
    - name: dotnet-web
      image: kestrel-based-app
      ports:
        - name: dotnet-web
          containerPort: 80
      lifecycle:
        preStop:
          exec:
            command: ["sleep", "15"]

With the preStop hook, the container waits for 15 seconds and still operates normal. Kestrel is able to handle incoming traffic. In this time, the endpoint removal to kube-proxy, Ingress controller and other service should be propagated. The old Kestrel instance receives less and less traffic. If 15 seconds are not enough, you can increse the value.

!! Please note, that the process will be forcefully killed by Kubernetes after 30 seconds. !! You have to change terminationGracePeriodSeconds setting if you need to wait longer than 30 seconds.