Руководство по реагированию на сбои узлов KubeEdge

Руководство по реагированию на сбои узлов KubeEdge

1. Фон

В процессе работы программы на последнем проекте я сталкивался с различными проблемами, такими как статус ‘NotReady’ в ‘kubectl get nodes’, зависание ‘kubectl exec’ или внезапная смена состояния Pod на Evicted. В связи с этим я подготовил руководство по реагированию на проблемы в среде KubeEdge, основываясь на реально встреченных четырех типах сбоев.

2. Введение

В отличие от обычного кластера на базе Kubernetes, в KubeEdge между облаком и узлами на краю существует дополнительный CloudCore ↔ EdgeCore туннель. Благодаря этому, даже в условиях нестабильной сети на местах можно управлять узлами на краю, но это также делает причины сбоев ещё более сложными.

3. Типы сбоев

Тип сбоя 1

Неудача ‘kubectl exec’ — "unexpected EOF"

(1) Симптомы

$ kubectl exec -it my-app-6jf2m -n iot-edge -- /bin/bash
error: Internal error occurred: error sending request:
Post "https://192.168.1.3:10351/exec/...": unexpected EOF

Выполнение ‘kubectl exec’ приводит к разрыву соединения, в результате чего ничего не происходит. Хотя другие Pod на том же узле могут показывать статус Running, exec может не работать.

(2) Анализ причин

Для того чтобы ‘kubectl exec’ работал в KubeEdge, необходимо, чтобы была активирована функция EdgeStream. Если эта функция отключена, туннель exec, соединяющий API Server → CloudCore → EdgeCore, не будет установлен.

Обычный Kubernetes напрямую обращается к API-серверу на 10250 порту kubelet для обработки exec, но у KubeEdge этого пути нет. Без EdgeStream exec, логи и port-forward не работают.

[kubectl exec flow in KubeEdge]
API Server
    ↓
CloudCore (streamPort: 10003)
    ↓ ← without this tunnel, unexpected EOF occurs
EdgeCore (edgeStream.server)
    ↓
컨테이너

(3) Способы решения

Проверка и активация настроек CloudCore:

# cloudcore.yaml
cloudStream:
  enable: true
  streamPort: 10003
  tlsTunnelCAFile: /etc/kubeedge/ca/rootCA.crt
  tlsTunnelCertFile: /etc/kubeedge/certs/server.crt
  tlsTunnelPrivateKeyFile: /etc/kubeedge/certs/server.key

Проверка и активация настроек EdgeCore:

# edgecore.yaml
edgeStream:
  enable: true
  handshakeTimeout: 30
  readDeadline: 15
  server: <CloudCore_IP>:10004
  tlsTunnelCAFile: /etc/kubeedge/ca/rootCA.crt
  tlsTunnelCertFile: /etc/kubeedge/certs/server.crt
  tlsTunnelPrivateKeyFile: /etc/kubeedge/certs/server.key
  writeDeadline: 15

После изменения настроек необходимо перезапустить обе стороны:

# On the master node where CloudCore is running
systemctl restart cloudcore.

# On the edge node
systemctl restart edgecore

Тип неисправности 2

Выталкивание Pod из-за DiskPressure

(1) Симптомы

$ kubectl get po -A -o wide | grep <NodeName>
iot-edge chronograf-xxxxx 0/1 Evicted 0 2m
iot-edge influxdb-xxxxx 0/1 Evicted 0 9m
iot-edge my-app-xxxxx 0/1 Evicted 0 14m

Pod, находящиеся на конкретном узле, становятся в состоянии Evicted все сразу. Если не один или два, а все Pod на данном узле были исключены, это может указывать на проблему с ресурсами на уровне узла.

(2) Анализ причин

Eviction — это механизм принудительного завершения Pod, который срабатывает, когда kubelet (в KubeEdge это edgecore) обнаруживает нехватку ресурсов на узле. Причину можно напрямую проверить через ‘kubectl describe node’:

kubectl describe node <NodeName> | grep -A5 "Conditions"

В реальных случаях появлялось сообщение следующего вида:

DiskPressure True ...
Message: The node was low on resource: ephemeral-storage.
  Threshold: 37556267476 (~35GB)
  Available: 36674584Ki (~34.9GB)

В момент, когда доступное место на диске падает ниже порога, kubelet принудительно вытаскивает Pod с данного узла.

Проверка использования диска
Подключитесь к узлу Edge по SSH и узнайте, где используется диск:

df -h
du -sh /* 2>/dev/null | sort -rh | head -15

В реальных случаях одна из директорий логов конкретного приложения занимала 89% всего диска.

$ du -sh /var/app/logs/*/
166G /var/app/logs/device-001.ASSET/

(3) Решение

Очистка старых логов(Обязательно проверьте необходимость сохранения перед удалением!)

# Delete files older than N days
find /var/app/logs -mtime +7 -type f -delete

Очистка неиспользуемых образов контейнеров

crictl rmi --prune

Перезапуск edgecore для переоценки DiskPressure

systemctl restart edgecore

Очистка и перераспределение Evicted Pod

# On the master node
kubectl get pods -A | grep Evicted | awk '{print "kubectl delete pod " $2 " -n " $1}' | sh

Тип ошибки 3

Init Container ImagePullBackOff — сбой DNS

(1) Симптомы

$ kubectl describe pod my-app-qn6r8 -n iot-edge
Init Containers:
  init-snapshot:
    State: Waiting
      Reason: ImagePullBackOff
    Image: registry.company.internal:5000/infra/busybox:latest

Сбой извлечения изображения происходит не в основном контейнере, а в Init Container. Если Init Container терпит неудачу, основной контейнер даже не запускается.

В этом случае, если посмотреть на предыдущее состояние завершения основного контейнера, оно будет следующим:

Last State: Terminated
  Reason: Unknown
  Exit Code: 255

Код завершения 255 означает, что контейнерная среда выполнения принудительно завершила процесс, что в большинстве случаев является результатом проблем на уровне узла (предыдущий DiskPressure, обрывы сети и т. д.).

(2) Анализ причин — сбой DNS частного реестра

Причины ImagePullBackOff разнообразны, но в IoT-средах с использованием корпоративного частного реестраПроблема с DNSпроисходит особенно часто.

Способ проверки:

# On the edge node
nslookup registry.company.internal

Если появляется DNS SERVFAIL, это означает, что домен не может быть разрешён.

server can't find registry.company.internal: SERVFAIL

(3) Способы решения

Быстрое временное решение — регистрация в /etc/hosts
После проверки IP на другом нормальном узле зарегистрируйте его непосредственно в ‘/etc/hosts’:

# Resolve IP from a healthy node
nslookup registry.company.internal
# Add entry to /etc/hosts on the affected node
echo "<IP> registry.company.internal" >> /etc/hosts
# Test image pull
crictl pull registry.company.internal:5000/infra/busybox:latest

Устранение коренной причины DNS

После временных мер проверьте состояние ‘systemd-resolved’ и перезапустите его:

systemctl status systemd-resolved
systemctl restart systemd-resolved

# Verify DNS resolution is restored
nslookup registry.company.internal

Перезапуск Pod после восстановления DNS

# Force delete and recreate the Pod from the master node
kubectl delete pod my-app-qn6r8 -n iot-edge --force --grace-period=0

# Watch Pod status
kubectl get pod -n iot-edge -w | grep my-app

4. Итоги

- Если ‘kubectl exec’ не работает, это может быть не проблема kubelet, а проблема конфигурации EdgeStream.

- Если Pod массово вытесняются, сначала проверьте использование дискового пространства на узле.

- ImagePullBackOff может указывать не на проблему с образом, а на сбой DNS.

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

Jsia

Site footer