MAATRIX / Блог / k3s на сервере: частые ошибки и решения

k3s на сервере: частые ошибки и решения

k3s на сервере: частые ошибки и решения

MAATRIX

Установка k3s занимает одну строчку, эксплуатация — нет. Сервис падает при старте, воркер не входит в кластер, kubectl стучится в localhost:8080, поды поднялись, но не видят друг друга, а через год кластер встречает просроченным сертификатом. Ниже — разбор ошибок k3s на одиночном сервере и в маленьком кластере: симптом, причина, команда.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Триаж: с чего начинать любой разбор

Первая развилка, на которой теряют время: на сервере (control plane) юнит называется k3s, на воркере — k3s-agent, и половина людей смотрит логи не того юнита.

journalctl -u k3s -n 200 --no-pager | grep -E 'level=(fatal|error)'
journalctl -u k3s-agent -f   # на агенте

Файла /var/log/k3s.log не существует, k3s пишет только в journald, и строка с level=fatal почти всегда содержит готовый ответ. Дальше три команды: k3s check-config проверяет параметры ядра и заканчивается вердиктом STATUS: pass или fail (при fail чинится ядро, а не Kubernetes); kubectl get nodes -o wide отделяет «кластер не поднялся» от «сломано одно приложение»; k3s crictl ps -a показывает контейнеры containerd, включая упавшие незаметно для API-сервера.

Сервис k3s не стартует: cgroups, YAML и занятый порт

Общий симптом: Job for k3s.service failed because the control process exited with error code. Причин три.

Порт 6443 занят. В журнале: level=fatal msg="starting kubernetes: preparing server: listen tcp 0.0.0.0:6443: bind: address already in use". Проверка — ss -tlnp | grep 6443: обычно это процесс, который не умер. Штатный /usr/local/bin/k3s-killall.sh гасит k3s и контейнеры, оставляя данные в /var/lib/rancher/k3s — в отличие от k3s-uninstall.sh, который стирает кластер целиком.

Ошибка в /etc/rancher/k3s/config.yaml: level=fatal msg="failed to parse /etc/rancher/k3s/config.yaml: yaml: line 4: mapping values are not allowed in this context". Главная ловушка файла — флаги в нём пишутся без двух дефисов, а повторяющиеся становятся списком:

write-kubeconfig-mode: "0644"
tls-san:
  - k8s.example.com
  - 203.0.113.10

Если флаги вы правите не здесь, а в /etc/systemd/system/k3s.service или k3s.service.env, обязателен systemctl daemon-reload — иначе systemd запустит старую команду.

Cgroups. На ARM-платах и урезанных образах ядро стартует без memory-контроллера, и k3s пишет прямо: Failed to find memory cgroup, you may need to add "cgroup_memory=1 cgroup_enable=memory" to your linux cmdline. Параметры добавляются в загрузчик, дальше перезагрузка. Версию cgroup показывает stat -fc %T /sys/fs/cgroup/: cgroup2fs — вторая, норма для Ubuntu 22.04+ и Debian 12.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть k3s

kubectl не подключается: kubeconfig, права и TLS SAN

Самая массовая ошибка: The connection to the server localhost:8080 was refused - did you specify the right host or port? Это не про k3s — kubectl не нашёл конфиг и пошёл в дефолтный адрес. Лечится строкой export KUBECONFIG=/etc/rancher/k3s/k3s.yaml в ~/.bashrc или встроенным клиентом k3s kubectl get nodes.

Второй вариант той же проблемы: error: error loading config file "/etc/rancher/k3s/k3s.yaml": permission denied. Файл лежит с правами 0600 root:root. Совет «добавьте --write-kubeconfig-mode 0644» работает, но имейте в виду цену: внутри клиентские сертификаты с правами cluster-admin, и доступ к кластеру получает любой локальный пользователь. Где вы не один, честнее скопировать конфиг себе: sudo install -o $(id -u) -m 600 /etc/rancher/k3s/k3s.yaml ~/.kube/config.

Третья ошибка вылезает при управлении кластером с ноутбука: конфиг скопировали, заменили 127.0.0.1 на публичный адрес — и получили x509: certificate is valid for 10.43.0.1, 127.0.0.1, 192.168.100.5, kubernetes.default, localhost, not 203.0.113.10. Сертификат выпущен без вашего внешнего адреса, нужен флаг --tls-san 203.0.113.10 или доменное имя. Нюанс: к уже выпущенному сертификату флаг сам по себе ничего не добавит — удалите пару файлов и перезапустите сервис:

rm -f /var/lib/rancher/k3s/server/tls/serving-kube-apiserver.{crt,key}
systemctl restart k3s

Агент не входит в кластер: токен, порты, не тот IP

Симптом первый: в логе агента крутится failed to get CA certs: Get "https://203.0.113.10:6443/cacerts": dial tcp 203.0.113.10:6443: i/o timeout. Это сеть: проверьте с агента nc -zv 203.0.113.10 6443 и не забудьте про облачный фаервол провайдера — он невидим изнутри системы и рубит пакеты до того, как их увидит ufw.

Симптом второй: Node password rejected, duplicate hostname or contents of '/etc/rancher/node/password' may not match server node-passwd entry. Классика клонированных виртуалок — две ноды с одинаковым hostname. Задайте разные (hostnamectl set-hostname k3s-worker-2), удалите на агенте /etc/rancher/node/password, перезапустите.

Симптом третий: failed to validate server configuration: token CA hash does not match. Берите токен там, где он лежит: cat /var/lib/rancher/k3s/server/node-token. Он выглядит как K10<hash>::server:<пароль> и отличается от соседнего файла token — их часто путают.

Дальше порты — 6443 открыли, а межнодовый трафик ходит по другим.

ПортПротоколНаправлениеЗачем
6443TCPагент → серверKubernetes API, регистрация ноды
8472UDPвсе ноды между собойflannel VXLAN, трафик подов
51820UDPвсе ноды между собойесли --flannel-backend=wireguard-native
10250TCPсервер → агентkubelet: logs, exec, metrics-server
2379–2380TCPсервер → сервервстроенный etcd в HA-конфигурации

Забытый 8472/udp даёт самый коварный набор симптомов: нода Ready, поды запущены, но под на первой ноде не достучится до сервиса на второй, а kubectl logs для чужой ноды виснет по таймауту. Забытый 10250/tcp — это metrics-server в CrashLoop и error: Metrics API not available на kubectl top nodes.

При нескольких интерфейсах нода регистрируется по адресу приватной сети, до которой соседи не дотягиваются: задайте явно --node-ip и --node-external-ip на агенте. И важное: flannel в режиме VXLAN трафик между подами не шифрует. Если ноды связаны публичной сетью, ставьте --flannel-backend=wireguard-native сразу при инициализации — задним числом бэкенд не меняется.

Сеть и DNS: «работает, но иногда» — это про MTU

Есть класс ошибок, которые выглядят мистикой: kubectl отвечает, поды бегают, мелкие запросы проходят, а curl к внешнему HTTPS внутри пода висит и git clone замирает на 20%. Это MTU: VXLAN добавляет 50 байт заголовка, поэтому при MTU интерфейса 1500 поды получают 1450. Что решил flannel, видно в cat /run/flannel/subnet.env — строка FLANNEL_MTU=1450.

Ломается это чаще всего на туннелях: у WireGuard типичный MTU 1420, правильное значение для подов 1370, а flannel, привязавшийся к eth0, поставит 1450. Пакеты уходят в чёрную дыру — маленькие пролетают, крупные молча теряются. Лечится флагом --flannel-iface=wg0: MTU считается от нужного интерфейса. Проверка с ноды: ping -M do -s 1400 -c 2 10.0.0.5 вернёт ping: local error: message too long, mtu=1420.

Вторая типовая беда — DNS: в логах приложения dial tcp: lookup api.example.com on 10.43.0.10:53: server misbehaving. Причина в systemd-resolved: /etc/resolv.conf хоста указывает на заглушку 127.0.0.53, CoreDNS копирует эту настройку и форвардит запросы на loopback внутри собственного пода, где никого нет. Решение — флаг --resolv-conf=/run/systemd/resolve/resolv.conf, а результат проверьте одноразовым подом: kubectl run -it --rm dns --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default.

Третье — фаервол на ноде. Политика DROP в цепочке FORWARD (дефолт ufw) режет трафик между подами, минимально нужно пропустить сети кластера: ufw allow from 10.42.0.0/16 to any и ufw allow from 10.43.0.0/16 to any. И общее правило: k3s сам управляет своими цепочками iptables, а инструмент, перезаписывающий таблицы целиком, снесёт KUBE-* и CNI-* — кластер ослепнет до перезапуска.

Ingress, диск и сертификаты: что ломается на дистанции

EXTERNAL-IP висит в <pending>. Смотрим kubectl -n kube-system get svc traefik, затем kubectl -n kube-system get pods | grep svclb. Если под svclb-traefik-* в CrashLoopBackOff, а в логе bind: address already in use — на портах 80 и 443 хоста уже сидит nginx или apache, поставленный до k3s. Либо освобождайте порты (systemctl disable --now nginx), либо отключайте балансировщик флагом --disable=servicelb.

PVC в Pending с сообщением waiting for first consumer to be created before binding — не ошибка: local-path создаёт том, только когда под назначен на ноду. Минус в другом — том лежит в /var/lib/rancher/k3s/storage конкретной ноды, и под с ним на другую ноду не переедет.

Диск. Симптом — no space left on device и условие DiskPressure в kubectl describe node: kubelet выселяет поды при свободном месте меньше 10% на nodefs. Место съедают /var/lib/rancher/k3s/agent/containerd (слои образов), снапшоты etcd и journald. Уборка — k3s crictl rmi --prune и journalctl --vacuum-time=7d.

Сертификаты. Однажды кластер, который вы год не трогали, встречает вас так: x509: certificate has expired or is not yet valid: current time 2026-08-28T10:12:33Z is after 2026-07-14T09:31:07Z. Внутренние сертификаты k3s живут 365 дней и обновляются при перезапуске сервиса, если до истечения осталось меньше 90 дней — то есть кластер, который не перезагружали больше года, ломается сам по себе. Сроки покажет openssl x509 -enddate -noout -in /var/lib/rancher/k3s/server/tls/serving-kube-apiserver.crt, лечение — systemctl restart k3s, а если срок вышел, то k3s certificate rotate и перезапуск. Та же ошибка бывает при сбитых часах: в timedatectl должно быть System clock synchronized: yes.

Какой сервер под k3s взять в MAATRIX

Часть разобранного выше — не кривые руки, а нехватка ресурсов и ограничения площадки. Считаем честно: k3s server в простое держит 500–700 МБ RSS, плюс containerd, CoreDNS, Traefik и metrics-server — около 1–1,2 ГБ съедено до первого вашего приложения. На инстансе с 2 ГБ всё «вроде работает», а первая же сборка выносит поды по OOM.

Минимум для одиночной ноды: 2 vCPU, 4 ГБ RAM, 60 ГБ NVMe. Хватает на control plane плюс два-три небольших сервиса и базу. Диск меньше 40 ГБ брать не стоит: слои образов за пару месяцев набирают 15–25 ГБ, и с DiskPressure вы познакомитесь раньше, чем с проблемами приложения. Комфортно: 4 vCPU, 8 ГБ RAM, 100–160 ГБ NVMe — прод из пяти-семи сервисов с базой и очередями. Раскладка по памяти — в материале сколько RAM нужно для k3s.

Настоящий HA — это три сервера со встроенным etcd, а не два: кворум из двух не собирается, при падении одной ноды кластер встанет. И etcd чувствителен к задержкам диска на fsync — на медленном хранилище вы получите etcdserver: request timed out и перевыборы лидера на ровном месте. Локальный NVMe здесь не маркетинг, а требование.

Локация. По умолчанию для k3s берите UK (Лондон). Причина прикладная: кластер постоянно тянет образы из Docker Hub, GHCR, quay.io и registry.k8s.io, а с российских адресов вы регулярно ловите failed to resolve reference "docker.io/library/nginx:1.29-alpine": unexpected status from HEAD request: 403 Forbidden и вынуждены прописывать зеркала в /etc/rancher/k3s/registries.yaml. Из Лондона реестры доступны напрямую, плюс 8–15 мс до Франкфурта и рабочие 40–55 мс до Москвы. Франция — по той же логике для континентальной Европы. Россию выбирают под 152-ФЗ, и тогда зеркала закладывайте сразу. США — если поды ходят к зарубежным ИИ-API.

Заказ занимает пару минут: выбираете локацию и конфигурацию, отмечаете приложение k3s — сервер приедет с развёрнутым кластером, останется забрать kubeconfig. Ручной порядок — в пошаговой установке k3s на Ubuntu 24.04, выбор оркестратора — в сравнении k3s против Docker Swarm. Оплата — картами российских банков, по СБП, криптой или токеном MAAT; иностранная карта не нужна, даже если сервер в Лондоне.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть k3s

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Почему kubectl работает под root, но не под моим пользователем?

Файл /etc/rancher/k3s/k3s.yaml имеет права 0600 root:root. Скопируйте его себе: sudo install -o $(id -u) -m 600 /etc/rancher/k3s/k3s.yaml ~/.kube/config. Флаг --write-kubeconfig-mode 0644 тоже решает вопрос, но раздаёт cluster-admin всем локальным пользователям.

Нода Ready, но поды на разных нодах не видят друг друга

Почти наверняка закрыт 8472/udp, порт flannel VXLAN: проверьте правила и на серверах, и в облачном фаерволе. Если ноды связаны туннелем, добавьте --flannel-iface=wg0, иначе MTU будет посчитан неверно.

Переживут ли поды перезапуск сервиса k3s?

Да: контейнеры держит отдельный процесс containerd-shim-runc-v2, он не умирает вместе с k3s, и простой затрагивает только control plane на 20–40 секунд. А k3s-killall.sh останавливает всё вместе с контейнерами.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.