Docker系列(五):.Net Core实现k8s健康探测机制

        k8s通过liveness来探测微服务的存活性,判断什么时候该重启容器实现自愈。比如访问 Web 服务器时显示 500 内部错误,可能是系统超载,也可能是资源死锁,此时 httpd 进程并没有异常退出,在这种情况下重启容器可能是最直接最有效的解决方案。

        k8s通过liveness来探测微服务的存活性,判断什么时候该重启容器实现自愈。比如访问 Web 服务器时显示 500 内部错误,可能是系统超载,也可能是资源死锁,此时 httpd 进程并没有异常退出,在这种情况下重启容器可能是最直接最有效的解决方案。

       k8s通过readiness来探测微服务的什么时候准备就绪(例如初始化时,连接数据库,加载缓存数据等等,可能需要一段时间),然后将容器加入到server的负载均衡池中,对外提供服务。

       k8s默认健康检查机制:

              每个容器启动时都会执行一个进程,此进程由 Dockerfile 的 CMD 或 ENTRYPOINT 指定。如果进程退出时返回码非零,则认为容器发生故障,Kubernetes 就会根据 restartPolicy 重启容器。如果不特意配置,Kubernetes 将对两种探测采取相同的默认行为。

OK,那我们就来实现一下,新建.Net Core Api项目 k8s-healthcheck,新增Heathchecks控制器:

    [Route("/api/v1/heathchecks")]
    public class HeathchecksController : Controller
    {
        private readonly static DateTime _beginUtc = DateTime.Now;

        [HttpGet]
        [Route("test")]
        public ActionResult<IEnumerable<string>> Test()
        {
            return new string[] { "value1", "value2" };
        }

        [HttpGet]
        [ProducesResponseType((int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.ServiceUnavailable)]
        [Route("liveness")]
        public async Task<IActionResult> Liveness()
        {
            return await Task.Run<IActionResult>(() =>
            {
                if(DateTime.UtcNow.Subtract(_beginUtc).TotalSeconds>60*10)
                {
                    Console.WriteLine("{0} HealthChecks.Api is dead start restarting...",DateTime.Now);
                    return this.NotFound();
                }
                else
                {
                    Console.WriteLine("{0} HealthChecks.Api is alive.",DateTime.Now);
                    return this.Ok();
                }
            });
        }

        [HttpGet]
        [ProducesResponseType((int)HttpStatusCode.OK)]
        [ProducesResponseType((int)HttpStatusCode.ServiceUnavailable)]
        [Route("readiness")]
        public async Task<IActionResult> Readiness()
        {
            return await Task.Run<IActionResult>(() =>
            {
                if(DateTime.UtcNow.Subtract(_beginUtc).TotalSeconds<30)
                {
                    Console.WriteLine("{0} HealthChecks.Api is not ready...",DateTime.Now);
                    return this.NotFound();
                }
                else
                {
                    Console.WriteLine("{0} HealthChecks is ready,start accepting traffic...", DateTime.Now);
                    return this.Ok();
                }
            });
        }
    }

解释一下我们这里自定义的 liveness 和 readiness检查机制:

liveness:存活10分钟,如果当前时间超过服务启动时间10分钟,则探测失败,否则探测成功。Kubernetes 如果连续执行 3 次 Liveness 探测均失败,就会杀掉并重启容器。

readiness:准备就绪30秒,30秒后,如果连续 3 次 Readiness 探测均失败后,容器将被重置为不可用,不接收 service 转发的请求。

从上面可以看到,我们可以根据自身的需求来实现这两种机制,然后,提供给k8s进行探测。

        k8s默认是根据命令进行探测的,由于我们需要与微服务结合,所以需要在yml文件中指定为http方式(备注:k8s提供了三种container probes方式:command、TCP check、HTTP Get,其他的方式希望大家下去自己实践),k8s对于http方式探测成功的判断条件是请求的返回代码在 200-400 之间。

该项目的 deploy.yaml 内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: k8s-ecoysystem-apps
  name: k8s-healthcheck
  labels:
    app: k8s-healthcheck
spec:
  replicas: 3
  selector:
    matchLabels:
      app: k8s-healthcheck
  template:
    metadata:
      namespace: k8s-ecoysystem-apps
      labels:
        app: k8s-healthcheck
    spec:
      containers:
      - name: k8s-healthcheck
        imagePullPolicy: Always
        image: 1151322093/k8s-healthcheck
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /api/v1/heathchecks/readiness
            port: 80
            scheme: HTTP 
          initialDelaySeconds: 30
          periodSeconds: 60 
        livenessProbe:
          httpGet:
            path: /api/v1/heathchecks/liveness
            port: 80
            scheme: HTTP 
          initialDelaySeconds: 120
          periodSeconds: 60

运行:kubectl apply -f deploy.yaml,然后通过 kubectl get pod -n k8s-ecoysystem-apps查看当前运行的pod,可以看到创建开始是不可以的,Ready状态数量是0。

稍等等待一会发现都可以用了:

然后我们通过 kubectl describe pod k8s-healthcheck-5c85bdcb69-f9zk9 -n k8s-ecoysystem-apps 命令可以查看更具体的信息:

刚开始readiness返回404不可用状态,不过我们设置的是30秒检查一次,所以很快状态就消除了,通过dashboard界面我们也可以看到更直观的信息:

等待10分钟过后,Liveness检测将会返回失败,pod处于不可用状态:

 

继续等待一会,集群就会自愈完成,前面说过,Liveness检测3次失败就会删除pod,并重启,重启之后就一轮新的检测:

从上面图中可以看到集群已经重启过1次,继续等待一段时间,如图:

 Liveness 探测和 Readiness 探测是独立执行的,二者之间没有依赖,可以单独使用,也可以同时使用。用 Liveness 探测判断容器是否需要重启以实现自愈;用 Readiness 探测判断容器是否已经准备好对外提供服务

OK,大功告成!!

猜你喜欢

转载自www.cnblogs.com/weiBlog/p/10056281.html