Советы и решение типовых проблем

Что-то обязательно пойдёт не так — это нормально, так все учатся. На этой странице собраны самые частые проблемы домашнего кластера: как их распознать, как диагностировать и как починить. Плюс резервное копирование и шпаргалка по kubectl.

Содержание

Узел в статусе NotReady

Симптом: kubectl get nodes показывает NotReady, поды на этом узле в Pending или Unknown.

Шаг 1. Спросите кластер, что случилось

kubectl describe node k8s-node1

Листайте до раздела Conditions — там список состояний узла. Ищите условие, которое не в порядке:

ConditionО чём говоритЧастая причина
Ready = FalseУзел нездоровkubelet упал, нет связи с сетью подов
MemoryPressure = TrueКончается ОЗУСлишком много подов без limits
DiskPressure = TrueКончается дискОбразы, логи, локальные тома съели место
PIDPressure = TrueКончаются PID'ыРедко; утечка процессов
NetworkUnavailable = TrueНе работает сеть подовCNI-плагин не запустился

Там же, внизу вывода, раздел Events — последние события узла, часто прямо называющие виновника.

Шаг 2. Посмотрите журналы на самом узле

Зайдите по SSH на проблемную машину и проверьте главного агента:

# k3s (сервер или агент):
sudo journalctl -u k3s -n 100 --no-pager
sudo journalctl -u k3s-agent -n 100 --no-pager

# kubeadm (kubelet):
sudo journalctl -u kubelet -n 100 --no-pager

# следить в реальном времени:
sudo journalctl -u k3s -f

Частые строки и их значения:

Шаг 3. Проверьте системные поды сети

Если kubelet жив, но поды не стартуют — часто виноват CNI:

# flannel (kubeadm):
kubectl get pods -n kube-flannel

# логи проблемного пода flannel:
kubectl logs -n kube-flannel имя-пода
Универсальное лечение половины болезней Перезапуск агента: sudo systemctl restart k3s (или k3s-agent, или kubelet). Если после этого узел Ready — читайте журналы и ищите первопричину в спокойной обстановке. Но если узел «отваливается» регулярно — это уже симптом: ищите, кто съедает память или диск.

Не хватает памяти: OOMKilled и Evicted

Симптомы: поды перезапускаются с причиной OOMKilled, либо зависают в статусе Evicted, либо узел показывает MemoryPressure.

Шаг 4. Найдите, кто ест память

# потребление по подам (нужен metrics-server; в k3s встроен)
kubectl top nodes
kubectl top pods -A --sort-by=memory

# почему перезапустился конкретный под
kubectl describe pod имя-пода | grep -A3 "Last State"
# Reason: OOMKilled — ядро убило процесс за превышение лимита

Шаг 5. Разберитесь с requests и limits

Ключ к стабильности — правильные значения у каждого контейнера:

Практический подход: запустите приложение без жёстких ограничений, дайте поработать пару дней, посмотрите реальное потребление (kubectl top pods) и выставьте requests чуть выше среднего, limits — выше пикового. Для домашних сервисов ориентиры есть в таблице на странице «Требования».

Шаг 6. Почистите «зависшие» Evicted-поды

Evicted-поды не удаляются сами и засоряют вывод:

# найти все Evicted во всех namespace
kubectl get pods -A --field-selector=status.phase=Failed

# удалить их разом
kubectl delete pods -A --field-selector=status.phase=Failed
Если память кончается хронически Варианты: убавить число реплик тяжёлых приложений; развести прожорливые сервисы по разным узлам; докупить память (серверная ECC REG дешёвая — см. «Железо»); и худший сценарий — включать swap нельзя, Kubernetes этого не прощает.

Пода не стартует: CrashLoopBackOff и ImagePullBackOff

Два самых частых статуса проблемных подов.

ImagePullBackOff — образ не скачивается

Кластер не может получить образ контейнера. Диагностика:

kubectl describe pod имя-пода | tail -20
# в Events будет причина, типичные:
# - "not found" — опечатка в имени или теге образа
# - "unauthorized" — приватный реестр, а imagePullSecrets не задан
# - таймауты — нет интернета на узле или DNS не работает

Решения по порядку: проверьте написание image: в манифесте (точное имя и тег); проверьте с узла curl -I https://registry-1.docker.io/v2/; для своих образов, загруженных вручную через k3s ctr images import, обязательно поставьте imagePullPolicy: IfNotPresent, иначе кластер будет пытаться скачать образ из интернета и честно упадёт с ImagePullBackOff.

CrashLoopBackOff — приложение падает сразу после старта

Под стартует, приложение внутри падает, Kubernetes перезапускает, цикл повторяется с нарастающей паузой (отсюда BackOff). Порядок действий:

# логи текущего и ПРЕДЫДУЩЕГО запуска — ключевая команда
kubectl logs имя-пода
kubectl logs имя-пода --previous

# история рестартов и причина выхода
kubectl describe pod имя-пода | grep -A5 "Last State"

Типовые причины:

Под в Pending и не назначается на узел

kubectl describe pod имя-пода | grep -A5 Events

Частые причины из Events: Insufficient memory/cpu (на узлах нет свободных requests — уменьшите их или освободите узел), pod has unbound immediate PersistentVolumeClaims (PVC не привязался — смотрите kubectl describe pvc, обычно provisioner не запущен или кончилось место), node(s) had taint (на узле запрещающий taint, например control-plane без снятого ограничения — см. шаг 5 на странице «Установка»).

Заполнение диска и etcd

Симптомы: поды не создаются (FailedCreatePodSandBox), в журналах no space left on device, узел в DiskPressure, а в тяжёлых случаях — apiserver вообще не отвечает, потому что etcd не может писать на диск.

Шаг 7. Найдите, что заняло место

# общая картина
df -h

# самые тяжёлые каталоги (обычно /var/lib — образы, тома, etcd)
sudo du -h -d1 /var/lib 2>/dev/null | sort -rh | head
sudo du -h -d1 /var/lib/rancher 2>/dev/null | sort -rh | head   # для k3s

Типовые «толстяки» в домашнем кластере:

Шаг 8. Почистите образы и логи

# неиспользуемые образы (k3s / containerd):
sudo k3s crictl rmi --prune

# усечь разросшиеся логи конкретного пода:
sudo truncate -s 0 /var/log/pods/*/имя-пода/*.log

Чтобы логи не разрастались в будущем, в k3s можно ограничить их размер при установке: INSTALL_K3S_EXEC="--kubelet-arg container-log-max-size=10Mi --kubelet-arg container-log-max-files=3".

Шаг 9. Присмотрите за etcd

Размер etcd смотрим в k3s так:

sudo k3s etcd-snapshot list
ls -lh /var/lib/rancher/k3s/server/db/

Если база перевалила за гигабайт на пустом кластере — полезно сделать дефрагментацию. Для k3s обычно достаточно того, что он сам периодически компактирует историю; в ванильном kubeadm-кластере дефрагментация делается через etcdctl (тема уже продвинутая — обратитесь к официальной документации kubernetes.io, раздел про etcd maintenance).

Диск переполнен, apiserver мёртв Порядок действий: освободите место (образы, логи) → sudo systemctl restart k3s → проверьте kubectl get nodes. Если etcd не стартует после очистки диска — восстанавливайтесь из снапшота (следующий раздел). Именно поэтому бэкапы нужно настроить до того, как они понадобятся.

Резервное копирование

Бэкап домашнего кластера состоит из трёх слоёв:

  1. etcd — состояние самого кластера (все объекты k8s);
  2. манифесты — ваши YAML и helm values (в идеале — в git);
  3. данные томов — файлы приложений (Nextcloud, медиатека и т.д.).

Шаг 10. Снапшоты etcd в k3s

В k3s это встроено и делается одной командой:

# ручной снапшот прямо сейчас
sudo k3s etcd-snapshot save --name before-upgrade

# список снапшотов
sudo k3s etcd-snapshot list

# файлы лежат здесь:
ls -lh /var/lib/rancher/k3s/server/db/snapshots/

Настройте автоматические снапшоты при установке или добавьте параметры в /etc/systemd/system/k3s.service (после правки: sudo systemctl daemon-reload && sudo systemctl restart k3s):

# флаги запуска k3s server:
--etcd-snapshot-schedule-cron="0 3 * * *"   # каждый день в 03:00
--etcd-snapshot-retention=7                  # хранить 7 последних
Снапшот лежит на том же диске, что и кластер Умрёт диск — умрут и снапшоты. Раз в неделю копируйте каталог /var/lib/rancher/k3s/server/db/snapshots/ на другую машину или NFS-шару. Простейший вариант — запись в crontab: rsync -a /var/lib/rancher/k3s/server/db/snapshots/ /mnt/nfs-backup/etcd/.

Шаг 11. Восстановление из снапшота (порядок действий)

# остановить k3s
sudo systemctl stop k3s

# восстановить кластер из выбранного снапшота
sudo k3s server --cluster-reset \
  --cluster-reset-restore-path=/var/lib/rancher/k3s/server/db/snapshots/имя-снапшота

# после успешного восстановления снять режим reset
sudo systemctl start k3s
# проверить: kubectl get nodes, kubectl get pods -A

Потренируйтесь на свежем кластере: сделайте снапшот, создайте под, восстановитесь из снапшота — под должен исчезнуть. Опыт восстановления до того, как всё сгорело, бесценен.

Шаг 12. Бэкап манифестов и данных

Обновление кластера

Kubernetes развивается быстро, и раз в несколько месяцев кластер стоит обновлять. Общий безопасный порядок одинаков для любого дистрибутива:

Шаг 1. Сделайте бэкап перед обновлением

# снапшот etcd (k3s)
sudo k3s etcd-snapshot save --name before-upgrade

Убедитесь, что бэкапы данных томов свежие. Обновление без бэкапа — русская рулетка.

Шаг 2. Обновите control-plane

В k3s — просто повторный запуск установочного скрипта с новой версией:

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.31.4+k3s1 sh -

В kubeadm-кластере — штатная процедура: снять hold с пакетов, обновить kubeadm, выполнить kubeadm upgrade plan и kubeadm upgrade apply, затем обновить kubelet и kubectl. Подробный порядок зависит от версии — сверяйтесь с официальной документацией kubernetes.io.

Шаг 3. Обновите рабочие узлы по одному

# выгнать поды с узла
kubectl drain k8s-node2 --ignore-daemonsets --delete-emptydir-data

# обновить k3s-agent на узле (тот же скрипт с той же версией)
# ... или пакеты в kubeadm

# вернуть узел в строй
kubectl uncordon k8s-node2

Правило: версии узлов не должны отличаться от control-plane больше чем на два минорных релиза, а лучше держать всех на одной версии.

Шпаргалка по kubectl

ЗадачаКоманда
Список узловkubectl get nodes -o wide
Все поды кластераkubectl get pods -A
Поды в конкретном namespacekubectl get pods -n media
Подробности об объекте (события!)kubectl describe pod имя -n namespace
Логи подаkubectl logs имя-пода -n namespace
Логи в реальном времениkubectl logs -f имя-пода
Логи прошлого (упавшего) контейнераkubectl logs имя-пода --previous
Зайти внутрь контейнераkubectl exec -it имя-пода -- /bin/sh
Применить манифестkubectl apply -f файл.yaml
Удалить по манифестуkubectl delete -f файл.yaml
Перезапустить deploymentkubectl rollout restart deployment/имя
Статус обновленияkubectl rollout status deployment/имя
Откат обновленияkubectl rollout undo deployment/имя
Потребление ресурсовkubectl top nodes / kubectl top pods -A
Всё про хранилищеkubectl get pv,pvc,sc
Сервисы и их типыkubectl get svc -A
События кластера (кто что сломал)kubectl get events -A --sort-by=.lastTimestamp
Endpoints сервиса (есть ли живые поды за ним)kubectl get endpoints имя-сервиса
Быстрый тестовый под для отладки сетиkubectl run tmp --rm -it --image=busybox -- sh
Проброс порта на локальную машинуkubectl port-forward svc/имя 8080:80
Поды на конкретном узлеkubectl get pods -A --field-selector spec.nodeName=k8s-node1
Выгнать поды с узла (перед обслуживанием)kubectl drain k8s-node1 --ignore-daemonsets --delete-emptydir-data
Вернуть узел в стройkubectl uncordon k8s-node1

Шаг 13. Золотое правило диагностики

Когда «ничего не работает», идите по цепочке снизу вверх и проверяйте каждое звено одной командой:

  1. Узел жив? → kubectl get nodes
  2. Под запущен? → kubectl get pods -o wide
  3. Что говорит сам под? → kubectl describe pod + kubectl logs
  4. Есть ли за сервисом живые поды? → kubectl get endpoints
  5. Работает ли сервис изнутри кластера? → kubectl run tmp --rm -it --image=busybox -- wget -qO- http://имя-сервиса
  6. Работает ли Ingress? → kubectl describe ingress и логи контроллера

90% домашних проблем находится на первых трёх шагах этой цепочки.

Источники для дальнейшего чтения Официальная документация: kubernetes.io (есть русский перевод) и docs.k3s.io. По Debian — debian.org/doc.