title: Implementing C#/.NET gRPC Healthcheck in kubernetes
body: <h1>Goal</h1>
  <p>I want to add a healthcheck to a .NET microservice using the gRPC <a href="https://github.com/grpc-ecosystem/grpc-health-probe" rel="nofollow noreferrer">health probe protocol</a>.</p>
  <p>The microservice is nothing more than the <code>Greeter</code> service created with the <code>dotnet new grpc</code> template. I've gotten this to run and build locally, directly with Docker, and finally on my development K8s cluster.</p>
  <h1>Problem</h1>
  <p>Following <a href="https://codevalue.com/grpc-health-checks-with-net-core-kubernetes/" rel="nofollow noreferrer">this post</a> and others, I have added the NuGet package to the project, and mapped the endpoint just like with the greeter service; however, the liveness/readiness probes fail due to timeout. I'm new to C#/.NET, so I expect that i've made a mistake in that area, but it is possible that the problem is in the kubernetes resources, too.</p>
  <h1>Code</h1>
  <h2>Startup.cs</h2>
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading.Tasks;
  using Microsoft.AspNetCore.Builder;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.Http;
  using Microsoft.Extensions.DependencyInjection;
  using Microsoft.Extensions.Hosting;
  using Grpc.HealthCheck;
  
  namespace Company.Project.GRPC
  {
      public class Startup
      {
          // This method gets called by the runtime. Use this method to add services to the container.
          // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
          public void ConfigureServices(IServiceCollection services)
          {
              services.AddGrpc();
              services.AddSingleton&lt;HealthServiceImpl&gt;(); // &lt;-- makes sense to me generally though the details are hazy 
          }
  
          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
          {
              if (env.IsDevelopment())
              {
                  app.UseDeveloperExceptionPage();
              }
  
              app.UseRouting();
  
              app.UseEndpoints(endpoints =&gt;
              {
                  // Healthcheck services
                  endpoints.MapGrpcService&lt;HealthServiceImpl&gt;(); // &lt;-- what besides this is needed?
                  
                  // App gRPC services
                  endpoints.MapGrpcService&lt;GreeterService&gt;();
  
                  endpoints.MapGet(&quot;/&quot;, async context =&gt;
                  {
                      await context.Response.WriteAsync(&quot;Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909&quot;);
                  });
              });
  
          }
      }
  }
  </code></pre>
  <h2>Program.cs</h2>
  <pre><code>using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Threading.Tasks;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.Extensions.Hosting;
  using Microsoft.AspNetCore.Server.Kestrel.Core;
  
  namespace Company.Project.GRPC
  {
      public class Program
      {
          public static void Main(string[] args)
          {
              CreateHostBuilder(args).Build().Run();
              
          }
  
          // Additional configuration is required to successfully run gRPC on macOS.
          // For instructions on how to configure Kestrel and gRPC clients on macOS, visit https://go.microsoft.com/fwlink/?linkid=2099682
         public static IHostBuilder CreateHostBuilder(string[] args) =&gt;
          Host.CreateDefaultBuilder(args)
              .ConfigureWebHostDefaults(webBuilder =&gt;
              {
                  webBuilder.ConfigureKestrel(options =&gt;
                  {
                      // Setup a HTTP/2 endpoint without TLS.
                      // TODO: Review security. May in fact be ok as an internal-only service
                      // options.ListenLocalhost(5000, o =&gt; o.Protocols = 
                      //     HttpProtocols.Http2);
                      options.Listen( System.Net.IPAddress.Parse(&quot;0.0.0.0&quot;), 5000);
                      options.Listen( System.Net.IPAddress.Parse(&quot;0.0.0.0&quot;), 50051);
                  });
                  webBuilder.UseStartup&lt;Startup&gt;();
  
              });
      }
  }
  </code></pre>
  <h2>Deployment.yaml</h2>
  <pre class="lang-yaml prettyprint-override"><code>...
            ports:
              - containerPort: 5000
              - containerPort: 50051
            readinessProbe:
              exec:
                command:
                  - /bin/grpc_health_probe
                  - -addr=:50051
              initialDelaySeconds: 15
              periodSeconds: 5
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 1
            livenessProbe:
              exec:
                command:
                  - /bin/grpc_health_probe
                  - -addr=:50051   # &lt;-- doesn't matter which port I use
              initialDelaySeconds: 15
              periodSeconds: 5
              timeoutSeconds: 5
              successThreshold: 1
              failureThreshold: 1
  </code></pre>
  <h1>Behavior</h1>
  <p>When I tail the logs for this pod, I see the server start up just fine, but then get killed after the liveness probe fails. The pod Events shows: <code>Container myservice failed liveness probe, will be restarted</code></p>
  <p>The probe client is the official one distributed from the link at the top. I've checked that the file is there, and that it can be executed as instructed.</p>
  <p>I don't need any functionality beyond the basic <code>Check</code> that the server is reachable and running, so I <em>believe</em> that the step of subclassing <code>HealthCheckImpl</code> that is included in the post I referenced is superfluous.</p>
  <p>What do I need to do/understand to get a working healthcheck on this simple service?</p>