问题背景: 当node重启或node上docker服务stop时,由于k8s不会快速将该Pod的endpoint从service上摘除,此时需要ingress能快速发现问题,否则请求流量会被nginx转发到故障的Pod上。

nginx-ingress的解决方法: 当前nginx-ingress支持后端服务的重试,例如下面的upstream,当请求到来时,将对server进行重试: max_fails为在fail_timeout 时间内重试的最大次数;当达到max_fails后,将该server的状态置为不可用 fail_timeout时间,在fail_timeout时间内的请求都不会再走该server;之后会再将server状态置为可用,再次重试。

        upstream xxx-hellobaby-80 {
                least_conn;
                keepalive 32;
                server 10.244.2.122:80 max_fails=3 fail_timeout=5;
                server 10.244.3.30:80 max_fails=3 fail_timeout=5;
        }

默认创建的ingress的ingress是没有做任何重试的,需要在创建时设置annotation,配置见最后。

当前nginx-ingress的功能能够一定程度上快速发现后端服务不可用时将其摘掉,但存在下面的缺点: 1)重试是由请求触发,而不是nginx主动探测,因此部分请求会被延迟(最终nginx会将流量从正常的路径转发出去) 2)fail_timeout时间后,会再次尝试重试,造成抖动。

更好的:nginx有第三方插件 nginx_http_upstream_check_module ,它可以提供健康检测的功能:

check interval=2000 rise=2 fall=3 timeout=1000; 即,每隔2秒探测1次,如果连续探测2次成功则认为该服务正常;若连续探测3次,则认为该服务不正常;每次探测的超时时间为1秒。

后期我们可以将这个功能整合进来,提供更好的健康检测。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/upstream-fail-timeout: "5"
    nginx.ingress.kubernetes.io/upstream-max-fails: "3"
  creationTimestamp: 2018-08-01T08:37:17Z
  generation: 1
  name: hellobaby-0
  namespace: ningliguang
spec:
  rules:
  - host: hellobaby.80.example.com
    http:
      paths:
      - backend:
          serviceName: hellobaby
          servicePort: 80