Как увеличить скорость реакции Kubernetes на отказ узлов кластера?

от автора

Kubernetes спроектирован так, чтобы быть надежным и устойчивым к сбоям, а также иметь возможность автоматически восстанавливаться. И он отлично справляется со всем этим! Однако рабочие узлы могут по разным причинам терять подключение к кластеру или выходить из строя. В этих случаях необходимо, чтобы Kubernetes быстро среагировал на инцидент.

Когда узел выходит из строя, pods сломанного узла все еще работают в течение некоторого времени. При этом они продолжают получать запросы, и эти запросы фейлятся. Скорее всего, совсем не то поведение, которое вы ожидали от Kubernetes, верно?

Чтобы разобраться, как Kubernetes реагирует на выход узла из строя, сначала рассмотрим взаимодействие между Kubelet и Controller Manager:

  1. Kubelet периодически уведомляет kube-apiserver о своём статусе с интервалом, заданным в параметре --node-status-update-frequency. Значение по умолчанию 10 секунд.

  2. Controller manager проверяет статус Kubelet каждые –-node-monitor-period. Значение по умолчанию 5 секунд.

  3. Если от Kubelet получена информация в пределах --node-monitor-grace-period, Controller manager считает Kubelet исправным. Значение по умолчанию 40 секунд.

В случае отказа узла кластера происходит следующий алгоритм:

  1. Kubelet отправляет свой статус kube-apiserver, используя — node-status-update-frequency = 10 сек.

  2. Узел выходит из строя.

  3. Controller manager будет пытаться проверять статус узла, сообщаемый Kubelet, каждые --node-monitor-period = 5 сек.

  4. Controller manager увидит, что узел не отвечает, и даст ему тайм-аут --node-monitor-grace-period в 40 сек. Если за это время Controller manager не сочтет узел исправным, он установит статус NotReady.

  5. Kube Proxy удалит endpoints, указывающие на pods внутри этого узла из всех сервисов, поэтому pods сбойного узла больше не будут доступны.

В этом сценарии будет возможны ошибки при обращении в pods, работающим на этом узле, потому что модули будут продолжать получать трафик до тех пор, пока узел не будет считаться неработающим (NotReady) через 45 сек.

Есть множество параметров для настройки в Kubelet и Controller Manager.

Быстрое обновление и быстрая реакция

Чтобы увеличить скорость реакции Kubernetes на отказ узлов кластера, вы можете изменить эти параметры:

-–node-status-update-frequency установить значение 1 сек (по умолчанию 10 сек)

--node-monitor-period установить значение 1 сек (по умолчанию 5 сек )

--node-monitor-grace-period установить значение 4 сек (по умолчанию 40 сек)

Протестируем изменения

Чтобы проверить изменения в тестовой среде, мы можем создать кластер Kubernetes с помощью Kind или любого другого инструмента. Мы создали конфигурационный файл для Kind Cluster с параметрами, указанными в предыдущем разделе, чтобы протестировать поведение кластера.

kind: Cluster apiVersion: kind.x-k8s.io/v1alpha4 kubeadmConfigPatches: - |   apiVersion: kubelet.config.k8s.io/v1beta1   kind: KubeletConfiguration   nodeStatusUpdateFrequency: 1s nodes: - role: control-plane   kubeadmConfigPatches:   - |     kind: ClusterConfiguration     controllerManager:         extraArgs:           node-monitor-period: 1s           node-monitor-grace-period: 4s - role: worker

Затем мы устанавливаем deployment с двумя репликами Nginx, размещенными в control-plane и на worker. Также мы дополнительно создали на control-plane pod с Ubuntu, чтобы проверить доступность Nginx, когда worker станет недоступен.

#!/bin/bash  # create a K8S cluster with Kind kind create cluster --config kind.yaml  # create a Ubuntu pod in control-plane Node kubectl run ubuntu --wait=true --image ubuntu --overrides='{"spec": { "nodeName": "kind-control-plane"}}' sleep 30d # untaint control-plane node in order to schedule pods on it kubectl taint node kind-control-plane node-role.kubernetes.io/master- # create Nginx deployment with 2 replicas, one on each node kubectl create deploy ng --image nginx sleep 30 kubectl scale deployment ng --replicas 2 # expose Nginx deployment so that is reachable on port 80 kubectl expose deploy ng --port 80  --type ClusterIP # install curl in Ubuntu pod kubectl exec ubuntu -- bash -c "apt update && apt install -y curl"

Чтобы проверить доступность Nginx, мы обратились к сервису с помощью curl из pod с Ubuntu, размещенного в control-plane, а также наблюдали за endpoints, принадлежащими сервису Nginx из терминала.

# test Nginx service access from Ubuntu pod kubectl exec ubuntu -- bash -c 'while true ; do echo "$(date +"%T.%3N") - Status: $(curl -s -o /dev/null -w "%{http_code}" -m 0.2 -i ng)" ; done'  # show Nginx service endpoints while true; do  gdate +"%T.%3N"; kubectl get endpoints ng -o json | jq '.subsets' | jq '.[] | .addresses' | jq '.[] | .nodeName'; echo "------";done 

Наконец, чтобы смоделировать сбой узла, мы остановили контейнер Kind, в котором запущен рабочий узел. Мы также добавили отметки времени, чтобы узнать когда узел был отключен и когда узел был обнаружен как NotReady.

#!/bin/bash  # kill Kind worker node echo "Worker down at $(gdate +"%T.%3N")" docker stop kind-worker > /dev/null sleep 15 # show when the node was detected to be down echo "Worker detected in down state by Control Plane at " kubectl get event --field-selector reason=NodeNotReady --sort-by='.lastTimestamp' -oyaml | grep time | tail -n1 # start worker node again docker start kind-worker > /dev/null 

После запуска теста мы заметили, что узел отключился в 12:50:22, а Controller manager обнаружил, что он отключился в 12:50:26, что и следовало ожидать через 4 секунды.

Worker down at 12:50:22.285 Worker detected in down state by Control Plane at       time: "12:50:26Z"

Аналогичный результат при тестировании с терминала. Служба начала возвращать сообщения об ошибках в 12:50:23, потому что трафик был направлен на отказавший узел. А в 12:50:26.744 Kube Proxy удалил endpoint, указывающую на отказавший узел, и доступность службы была полностью восстановлена.

... 12:50:23.115 - Status: 200 12:50:23.141 - Status: 200 12:50:23.161 - Status: 200 12:50:23.190 - Status: 000 12:50:23.245 - Status: 200 12:50:23.269 - Status: 200 12:50:23.291 - Status: 000 12:50:23.503 - Status: 200 12:50:23.520 - Status: 000 12:50:23.738 - Status: 000 12:50:23.954 - Status: 000 12:50:24.166 - Status: 000 12:50:24.385 - Status: 200 12:50:24.407 - Status: 000 12:50:24.623 - Status: 000 12:50:24.839 - Status: 000 12:50:25.053 - Status: 000 12:50:25.276 - Status: 200 12:50:25.294 - Status: 000 12:50:25.509 - Status: 200 12:50:25.525 - Status: 200 12:50:25.541 - Status: 200 12:50:25.556 - Status: 200 12:50:25.575 - Status: 000 12:50:25.793 - Status: 200 12:50:25.809 - Status: 200 12:50:25.826 - Status: 200 12:50:25.847 - Status: 200 12:50:25.867 - Status: 200 12:50:25.890 - Status: 000 12:50:26.110 - Status: 000 12:50:26.325 - Status: 000 12:50:26.549 - Status: 000 12:50:26.604 - Status: 200 12:50:26.669 - Status: 000 12:50:27.108 - Status: 200 12:50:27.135 - Status: 200 12:50:27.162 - Status: 200 12:50:27.188 - Status: 200 ... ... ------ 12:50:26.523 "kind-control-plane" "kind-worker" ------ 12:50:26.618 "kind-control-plane" "kind-worker" ------ 12:50:26.744 "kind-control-plane" ------ 12:50:26.878 "kind-control-plane" ------ ...

Заключение

Мы убедились, что скорость реакции Kubernetes на инцидент значительно возросла. Возможны разные комбинации параметров для конкретных случаев, и у вас может возникнуть соблазн снизить значения, чтобы система Kubernetes реагировала быстрее, но примите во внимание, что этот сценарий создает накладные расходы на etcd, поскольку каждый узел будет постоянно пытаться обновлять свой статус через 1 секунду. Например, если в кластере 1000 узлов, будет происходить 60000 обновлений узлов в минуту, что может потребовать увеличения ресурсов контейнеров etcd или даже выделенных узлов для etcd.

Кроме того, если вы установите значения параметров слишком маленькими, возникнут некоторые риски. Например, временный сбой сети на короткий период может привести к ложному срабатыванию.

ссылка на оригинал статьи https://habr.com/ru/company/timeweb/blog/561084/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *