# Node 重伤之后

很多人都知道 Kubernetes 能自动维护失效 Pod、防止服务中断、剔除故障节点 BLABLA 的一堆高大上功能。但节点故障之后，会对运行在故障节点上的容器、以及依赖容器的服务造成什么影响，是应该了解的，这样才能有针对性的进行监控设置、部署安排、故障处理等工作。

水平有限，这里不谈原理，只说说症状和一些相关的调整。

## 测试环境

- Kubernetes 1.7.10，三节点，其中 Master 节点被 Taint.
  - 10.211.55.11(Master)
  - 10.211.55.12
  - 10.211.55.13
- CentOS 7
- Docker 1.12.3

## 实验设计

Docker、Kubelet 以及 Kube-Proxy 是 Node 的标准组件，我们准备一个 2 Replicas 的 Deployment 作为测试目标，使用 NodePort 方式暴露 HTTP 端口。具体代码见附录。

使用 `systemctl` 关停目标服务，使用 `watch -n5 kubectl get pods,nodes,deploy` 以及 `watch -n5 kubectl "describe svc httpbin | grep -i endp"` 命令持续检查相关工作负载的情况。同时可以使用 `curl` 命令检查服务是否存活。

## Kube-Proxy

选择登录一个节点，例如 `10.211.55.12`，使用 `kubectl stop kube-proxy` 关闭之后可以看到，各个 `kubectl get` 命令返回结果都正常，似乎未受影响；然而使用 `curl` 进行逐个节点的 NodePort 进行验证的时候，会发现停掉 Proxy 的地址是无法提供服务的。

### 监控

除了监控进程/服务之外，Kube-Proxy 还提供了几个可以用于监控的参数

- `--healthz-bind-address`：健康检测地址和端口，缺省为 0.0.0.0:10256
- `--healthz-port`：健康检测端口，缺省 10256，设置为 0 则关闭。

`curl http://127.0.0.1:10256/healthz | jq` 会看到返回的健康数据：

~~~json
{
  "lastUpdated": "2017-12-19 16:05:27.333531431 +0800 CST",
  "currentTime": "2017-12-19 16:05:33.73732624 +0800 CST"
}
~~~

--- `--metrics-bind-address` 用于提供监控指标的地址和端口，缺省为 127.0.0.1:10249，返回内容可用于 Prometheus。例如：`curl -s  http://127.0.0.1:10249/metrics  | more`会看到：

    ......
    # HELP http_request_size_bytes The HTTP request sizes in bytes.
    # TYPE http_request_size_bytes summary
    http_request_size_bytes{handler="prometheus",quantile="0.5"} 64
    http_request_size_bytes{handler="prometheus",quantile="0.9"} 64
    http_request_size_bytes{handler="prometheus",quantile="0.99"} 64
    http_request_size_bytes_sum{handler="prometheus"} 192
    http_request_size_bytes_count{handler="prometheus"} 3
    ......

## Kubelet

Kubelet 情况比 kube-proxy 复杂一些。

1. 首先使用`kubectl get po -o wide`，确认 Pod 所在节点。
2. 使用`systemctl stop kubelet`停止 kubelet 服务。
3. 观察

首先我们会看到，经过约半分钟以后，该节点变为`NotReady`状态。Deploy 对象的 Available 字段数字会减 1，服务的`Endpoints`列表减少一个。；但是 Pod 状态保持在`Running`，

五分钟左右，Pod 进入`Unknown`状态，开始尝试启动新 Pod。

### 存活检测和就绪检测

测试中我们使用的 yaml 中并没有设置这两个内容，事实上，这两个检测是由 kubelet 执行的，对上述行为并无影响。

### 参数调整

真正影响上面的行为的是`kube-controller-manager`的两个参数：

- `--pod-eviction-timeout`：缺省为 5m，五分钟，在 Pod 驱逐行为的超时时间。
- `--node-monitor-grace-period`：缺省为 40s，也就是 40 秒，无响应 Node 在标记为 NotReady 之前的等候时间。

### 监控

- `--healthz-bind-address`：健康监测地址，缺省为`127.0.0.1`。
- `--healthz-port`：健康检测端口，缺省为 10248。

curl 访问该地址，会得到响应：`ok`。

另外如果使用`kube-metrics exporter`进行集群监控，可以关注 RC、Deploy 等对象的可用实例数量。

## Docker

Docker 的情况其实跟 Kubelet 类似，但是结果会更严重：在 Endpoint 被排除之前，路由到故障节点的流量会发生故障。

## 测试之外

1. 多 Pod 不仅对性能有好处，在极端情况下能降低故障节点对服务整体效果的影响。
2. 建议采用节点互斥的方式进行部署。
3. 对关键组件的监控，应该建立从进程到指标的多级监控，减小服务故障的时间窗口。
4. Pod 的存活和健康监测，对于容器内的应用是有效的，应该推荐。

## 附录

### workload.yaml

```yaml

apiVersion: v1
kind: Service
metadata:
  name: httpbin
  labels:
    app: httpbin
spec:
  ports:
  - name: http
    port: 80
    nodePort: 30080
  selector:
    app: httpbin
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: httpbin-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: httpbin
        version: v1
    spec:
      containers:
      - image: httpd
        imagePullPolicy: IfNotPresent
        name: httpbin
        ports:
        - containerPort: 80
```
