Установка Kubernetes-кластера с нуля: пошаговое руководство для продакшена в 2026 году | AdminWiki

Установка Kubernetes-кластера с нуля: пошаговое руководство для продакшена в 2026 году

25 сентября 2026 14 мин. чтения
Содержание статьи

Что вы получите в итоге и кому подходит это руководство

К концу материала у вас будет рабочий кластер Kubernetes на собственных серверах или виртуальных машинах: control plane поднят, worker-ноды в статусе Ready, CNI установлен, StorageClass отвечает на заявки PVC, приложения можно деплоить обычным kubectl apply. Ставим через kubeadm с containerd в роли container runtime. Это стандартный путь для продакшена, когда нужен контроль над версиями каждого компонента и полное понимание того, что происходит внутри.

Руководство рассчитано на DevOps-инженеров и системных администраторов, которые уверенно работают в Linux и понимают, что такое контейнер, образ и namespace. Базовый синтаксис systemd, работу с репозиториями пакетов и правку конфигов считаем известными, поэтому на этих деталях не задерживаемся.

Минимальная топология для продакшена: один control plane и два worker-узла. Для отказоустойчивости control plane потребуется три узла и балансировщик перед API server. Официальный туториал Kubernetes по canary-развёртыванию, например, прямо требует кластер минимум с двумя узлами, которые не выполняют роль control plane (документация Kubernetes). Двух worker-нод хватает, чтобы проверить отказоустойчивость деплоя: поды разъедутся по разным машинам, и падение одной не остановит сервис.

Порядок работы такой: подготовка узлов, отключение swap, настройка модулей ядра и firewall, установка containerd, kubeadm init, выбор и установка CNI, присоединение worker-нод, хранилище, проверка работоспособности, разбор типичных ошибок. Если вам нужен более короткий вариант с акцентом только на базовую установку, посмотрите пошаговое руководство по установке кластера Kubernetes с kubeadm: там те же этапы, но без развёрнутого блока про хранилище и диагностику.

Выбор дистрибутива Kubernetes для продакшена в 2026 году

Дистрибутив определяет, сколько ручной работы ляжет на вас и что вы получите из коробки. kubeadm даёт bare-кластер: вы сами ставите CNI, сами выбираете storage, сами настраиваете обновления. k3s упаковывает control plane в один бинарник и запускается быстрее, но по умолчанию тянет за собой Flannel и local-path-provisioner. RKE2 собирает Kubernetes с усиленными настройками безопасности и CIS-профилем, что важно для проектов с требованиями комплаенса.

По версиям ориентир на 2026 год такой: Kubernetes 1.37 требует container runtime, совместимый с CRI, а Dockershim удалён из проекта начиная с 1.24. Отдельно стоит знать про Dynamic Resource Allocation: это стабильная функция с версии 1.35, впервые появилась в 1.30, и отключить её больше нельзя (описание DRA в документации Kubernetes). Для железа вроде GPU или FPGA это меняет способ выделения устройств подами, но на процесс первичной установки кластера не влияет.

Сравнительная таблица: kubeadm, k3s, RKE2

Критерийkubeadmk3sRKE2
Сложность установкиСредняя: все компоненты ставите самиНизкая: один бинарник или скриптНизкая: установочный скрипт
Минимум для control plane2 CPU, 2 GB RAM (для продакшена 4 CPU, 8 GB RAM)1 CPU, 1 GB RAM2 CPU, 2 GB RAM
Минимум для worker1 CPU, 2 GB RAM1 CPU, 512 MB RAM1 CPU, 2 GB RAM
Отказоустойчивость3 control plane и внешний балансировщик3 ноды с встроенным etcd3 ноды с встроенным etcd
CNI из коробкиНетFlannelCanal (Calico + Flannel)
Хранилище из коробкиНетlocal-path-provisionerlocal-path-provisioner
Безопасность по умолчаниюБазовые настройки, всё настраиваете самиУмереннаяУсиленная, профиль CIS
Типовой сценарийПродакшен с полным контролемEdge, тесты, небольшие кластерыПродакшен с требованиями безопасности

Для типового продакшена в 2026 году выбираем kubeadm и containerd. Полный контроль над CNI, хранилищем и версиями компонентов стоит потраченных вечеров. k3s берите, если кластер живёт на слабом железе или на периферии. RKE2 оправдан там, где аудит требует CIS-профиль и минимум ручных правок безопасности.

Почему Docker больше не используется и что это значит для установки

Старые гайды начинаются с установки Docker Engine и содержат флаг --cri-socket. С Kubernetes 1.24 Dockershim удалён из проекта, и прямой интеграции с Docker Engine в Kubernetes больше нет: эта связка не входит в состав проекта с 1.24 (документация по container runtime). Kubernetes 1.37 требует CRI-совместимого runtime, и containerd или CRI-O закрывают это требование. Docker Engine в новых версиях сам использует containerd внутри, но kubelet должен обращаться к самому containerd, а не к обёртке Docker.

Проверить, что runtime настроен правильно, можно двумя командами:

kubectl get nodes -o wide
crictl info

В колонке CONTAINER-RUNTIME будет containerd со версией, а crictl info вернёт конфигурацию рантайма. Если таблица пустая или узлы висят в NotReady, ищите причину в journalctl -u kubelet: чаще всего kubelet не может подключиться к сокету containerd.

Требования к ресурсам и подготовка узлов

Минимальные требования для учебного контура: control plane 2 CPU, 2 GB RAM и 20 GB на диске, worker 1 CPU, 2 GB RAM и 20 GB. Для продакшена эти цифры умножайте: 4 CPU и 8 GB RAM для control plane, 4 CPU и 8-16 GB RAM для worker. etcd чувствителен к задержкам диска, поэтому под control plane берите SSD или NVMe, а не сетевой HDD. Если своих серверов нет, подойдут облачные VDS: Timeweb Cloud даёт серверы, базы данных, хранилище и Kubernetes, ресурсы можно менять по ходу проекта.

Подготовка выполняется на каждом узле без исключений. Пропущенный шаг на одной worker-ноде приводит к тому, что она не присоединится к кластеру.

Отключение swap и настройка модулей ядра

Сначала swap. Kubelet рассчитан на работу с реальной памятью и не стартует при включённом swap:

swapoff -a
sed -i '/ swap / s/^/#/' /etc/fstab

Первая команда гасит swap в текущей сессии, вторая комментирует его в fstab, чтобы после перезагрузки он не вернулся. Проверьте результат командой free -h: в строке Swap должно быть нулевое значение.

Теперь модули ядра и параметры сети. Ядро Linux по умолчанию не пропускает IPv4-пакеты между интерфейсами, а большинство сетевых функций Kubernetes рассчитывают на включённую пересылку (документация Kubernetes).

cat <<EOF | tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

modprobe overlay
modprobe br_netfilter

cat <<EOF | tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward                 = 1
EOF

sysctl --system

Модуль overlay обеспечивает работу файловых систем контейнеров, br_netfilter пропускает трафик через iptables. Параметр net.ipv4.ip_forward = 1 включает маршрутизацию пакетов, без него поды не выйдут за пределы своего узла.

Настройка firewall и необходимых портов

Firewall настраивайте до установки кластера. Закрытый порт 6443 приведёт к тому, что worker-ноды не присоединятся, а вы будете искать причину в kubelet.

УзелПорт и протоколНазначение
Control plane6443/tcpAPI server
Control plane2379-2380/tcpetcd client и peer
Control plane и worker10250/tcpkubelet API
Control plane10259/tcpkube-scheduler
Control plane10257/tcpkube-controller-manager
Worker30000-32767/tcpNodePort Service
Calico179/tcpBGP
Calico4789/udpVXLAN

Пример для ufw на control plane:

ufw allow 6443/tcp
ufw allow 2379:2380/tcp
ufw allow 10250/tcp
ufw allow 10259/tcp
ufw allow 10257/tcp
ufw reload

Вариант для firewalld:

firewall-cmd --permanent --add-port=6443/tcp
firewall-cmd --permanent --add-port=2379-2380/tcp
firewall-cmd --permanent --add-port=10250/tcp
firewall-cmd --reload

SELinux на RHEL-подобных системах держите включённым, но в режиме permissive хотя бы на время установки, иначе kubelet упрётся в отказы доступа к каталогам. AppArmor на Ubuntu оставляйте в штатном режиме: политики Kubernetes с ним совместимы.

Установка и настройка containerd

Сначала kubelet и kubectl. Подключите официальный репозиторий пакетов Kubernetes для нужной минорной версии, затем:

apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl

Команда apt-mark hold фиксирует версии: автоматическое обновление kubelet при плановом обновлении пакетов ломает совместимость компонентов. Обновляйте kubelet, kubeadm и kubectl вместе и осознанно.

Дальше containerd. Ставьте из официального репозитория проекта, минимальная рабочая версия для Kubernetes 1.37 - 1.7.x, но берите свежую стабильную ветку. После установки сгенерируйте конфиг и включите cgroup driver systemd:

mkdir -p /etc/containerd
containerd config default | tee /etc/containerd/config.toml
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
systemctl restart containerd
systemctl enable containerd

Почему именно systemd: kubelet и container runtime обязаны использовать один и тот же cgroup driver, и при systemd в роли init-системы рекомендуют драйвер systemd, а не cgroupfs. С версии 1.22 kubeadm по умолчанию выставляет systemd, если драйвер не задан явно (документация по container runtime). При ручной правке containerd.conf этого значения нет, и рассинхрон драйверов даёт периодические падения подов с ошибками cgroup.

Проверка после перезапуска: systemctl status containerd должен показать active (running), а crictl info вернуть заполненную конфигурацию runtime.

Установка control plane с kubeadm

Инициализация control plane: команда и параметры

Перед init зафиксируйте два значения: адрес API server и диапазон адресов подов. Диапазон потом менять сложно, он должен совпадать с настройками CNI.

kubeadm init \
  --control-plane-endpoint=10.0.0.10:6443 \
  --pod-network-cidr=192.168.0.0/16 \
  --upload-certs

Параметр --control-plane-endpoint задаёт адрес, по которому узлы видят API server. Для одного control plane это IP машины, для HA - DNS-имя балансировщика, и тогда переезд узла не потребует перенастройки kubelet на всех worker-нодах. Диапазон 192.168.0.0/16 подходит Calico, для Flannel используйте 10.244.0.0/16. Флаг --upload-certs выгружает сертификаты в Secret, чтобы упростить добавление второго и третьего control plane.

Вывод команды обязательно сохраните: в конце kubeadm печатает команду kubeadm join с токеном и хешем сертификата. Именно ей присоединяются worker-ноды, и после перезапуска терминала восстановить её из истории не всегда получится.

Настройка kubectl и проверка статуса

Kubeconfig лежит в /etc/kubernetes/admin.conf и принадлежит root. Скопируйте его для своего пользователя:

mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes

На этом этапе control plane будет в статусе NotReady. Это нормально: без CNI узел не готов принимать поды. Поды CoreDNS останутся в Pending по той же причине. Посмотреть, что происходит, можно так:

kubectl get pods -n kube-system
kubectl describe node control-plane-1
journalctl -u kubelet -n 100 --no-pager

Если kubelet вообще не поднялся, ищите в его логах ошибку подключения к containerd или сообщение про включённый swap.

Установка CNI-плагина и настройка сети

CNI отвечает за адресацию подов и их связность между узлами. Без него кластер существует только формально: узлы NotReady, поды в Pending, DNS не работает. Подробный разбор модели сети с адресами подов, Service и диагностикой собран в отдельном материале про сети в Kubernetes, CNI и Service network.

Выбор CNI: Calico, Cilium или Flannel

CNINetworkPolicyeBPFBGPСложность
CalicoДаОпциональный dataplaneДаСредняя
CiliumДаДа, по умолчаниюОпциональноСредняя и высокая
FlannelНетНетНетНизкая

Для продакшена берите Calico: NetworkPolicy из коробки, предсказуемая маршрутизация, BGP при соединении с физической сетью. Cilium выбирайте, если нужны eBPF-ускорение, наблюдаемость на уровне L7 и вы готовы разбираться с его моделью. Flannel оставьте для лабораторий и кластеров, где политики безопасности не нужны. Детальные замеры и критерии выбора собраны в сравнении какой CNI-плагин выбрать в 2026 году.

Установка Calico и проверка сетевой связности

Скачайте манифест Calico нужной версии из официального репозитория проекта и перед применением проверьте в нём переменную CALICO_IPV4POOL_CIDR: она должна совпадать с --pod-network-cidr, который вы указали при kubeadm init. Расхождение - самая частая причина неработающей сети после установки.

kubectl apply -f calico.yaml
kubectl get pods -n kube-system -l k8s-app=calico-node
kubectl get nodes

Дождитесь, когда поды calico-node перейдут в Running, а узлы сменить NotReady на Ready. Затем проверьте реальную связность между подами:

kubectl run test1 --image=busybox --restart=Never -- sleep 3600
kubectl run test2 --image=busybox --restart=Never -- sleep 3600
kubectl get pods -o wide
kubectl exec -it test1 -- ping -c 3 <IP пода test2>

Ответные пакеты без потерь означают, что overlay-сеть работает, kube-proxy прописал маршруты, а CNI распределил адреса по узлам. Проблемы с MTU в overlay-сетях и разбор маршрутизации в bridge и overlay режимах разобраны в материале про сетевую маршрутизацию в Docker и Kubernetes.

Присоединение worker-нод к кластеру

Генерация команды join и присоединение

Токен из вывода kubeadm init живёт 24 часа. Если он истёк, сгенерируйте новый на control plane:

kubeadm token create --print-join-command

Команда выведет готовую строку вида kubeadm join 10.0.0.10:6443 --token <токен> --discovery-token-ca-cert-hash sha256:<хеш>. Выполните её под root на worker-ноде, подготовленной так же, как control plane: swap отключён, модули загружены, containerd с SystemdCgroup = true настроен.

kubectl get nodes -o wide

Все узлы должны перейти в Ready, в колонке ROLES у worker-нод будет . Проверить, что нода действительно принимает нагрузку, можно тестовым деплоем с двумя репликами.

Диагностика проблем при присоединении

Три причины покрывают большинство сбоев. Первая: неверный или просроченный токен, решается командой kubeadm token create --print-join-command. Вторая: несовпадение cgroup driver, kubelet стартует, но поды падают. Третья: firewall блокирует 6443 или 10250, соединение отваливается по таймауту.

journalctl -u kubelet -f
kubectl describe node worker-1
crictl ps

Логи kubelet показывают, на каком шаге обрывается соединение: TLS-рукопожатие, регистрация ноды, получение CNI-конфига. kubectl describe node выводит условия Ready, MemoryPressure и DiskPressure с расшифровкой причины. crictl ps на самой ноде подтверждает, что рантайм жив и контейнеры запускаются.

Настройка хранилища для продакшена

Выбор StorageClass и CSI-драйвера

ВариантТипРепликацияСценарий
local-path-provisionerЛокальные томаНетТесты, одна нода
LonghornРаспределённое блочноеДа, 3 репликиСредние кластеры на своей инфраструктуре
Ceph RBD и CephFSРаспределённое блочное и файловоеДаКрупные кластеры
Облачный CSIЗависит от провайдераДаManaged Kubernetes и облако

local-path-provisioner привязывает том к конкретному узлу. Узел упал - под с этим PVC не переедет, поэтому в продакшене такой вариант не подходит. Longhorn закрывает типовую задачу: блочные тома с репликацией между узлами и снапшотами, без отдельного кластера хранения. Ceph берите, когда томов сотни и нужны S3-совместимое объектное хранилище и файловые шары.

Установка Longhorn и проверка PVC

kubectl apply -f longhorn.yaml
kubectl -n longhorn-system get pods
kubectl get storageclass

Манифест Longhorn возьмите из официального репозитория проекта. Все поды в namespace longhorn-system должны быть Running, а в списке StorageClass появится longhorn. Назначьте его классом по умолчанию, чтобы PVC без явного указания класса получали тома именно от него:

kubectl patch storageclass longhorn -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

Проверочный PVC выглядит так:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
kubectl apply -f test-pvc.yaml
kubectl get pvc

Статус Bound означает, что CSI-драйвер создал том и привязал его к заявке. Если PVC висит в Pending, смотрите события: kubectl describe pvc test-pvc и логи подов csi-provisioner в longhorn-system.

Проверка работоспособности кластера и диагностика

Чек-лист проверки кластера

ПроверкаКомандаОжидаемый результат
Статус узловkubectl get nodesВсе узлы Ready
Системные подыkubectl get pods -AВсе поды Running, кроме завершённых Job
Адрес APIkubectl cluster-infoВыведен адрес control plane
DNSkubectl run test --image=busybox -- nslookup kubernetes.defaultОтвет с IP сервиса kubernetes
Деплойkubectl create deployment nginx --image=nginx --replicas=22 пода Running
Хранилищеkubectl get pvcBound

Особое внимание подам CoreDNS в namespace kube-system. Если они не в Running, DNS внутри кластера не работает, и сервисы не находят друг друга по именам, хотя сеть между подами жива.

Диагностика типовых сбоев

Узел NotReady почти всегда означает проблему с kubelet или CNI. Проверьте journalctl -u kubelet и поды calico-node. Под в Pending означает нехватку ресурсов на узлах, несовместимый nodeSelector или неготовый PVC: kubectl describe pod <имя> покажет событие FailedScheduling с причиной. Ошибки приложений ищите в kubectl logs <под> и kubectl logs <под> --previous, если контейнер уже перезапускался.

Для сетевых проблем полезен crictl: он показывает контейнеры на конкретном узле независимо от состояния API server. Команды crictl ps, crictl logs и crictl inspect дают ответ, когда kubectl недоступен.

Типичные ошибки при установке и как их избежать

  1. Swap не отключён. Kubelet не стартует, в логах сообщение про swap on. Решение: swapoff -a и правка /etc/fstab, затем перезапуск kubelet.
  2. Разные cgroup driver у kubelet и containerd. Поды запускаются и падают, в логах ошибки записи в cgroup. Решение: SystemdCgroup = true в /etc/containerd/config.toml и перезапуск containerd.
  3. Firewall блокирует порты. Worker-ноды не присоединяются, kubeadm join падает по таймауту. Решение: открыть 6443, 2379-2380, 10250 на control plane и 10250 на worker.
  4. Неверный pod-network-cidr. Узлы Ready, но поды не видят друг друга. Решение: привести CALICO_IPV4POOL_CIDR в манифесте CNI в соответствие с диапазоном, заданным при kubeadm init.
  5. Попытка использовать Docker Engine вместо CRI-runtime. Kubelet не находит сокет, кластер не поднимается. Решение: containerd или CRI-O, Dockershim не входит в Kubernetes с 1.24.
  6. CNI не установлен. Control plane и worker в NotReady, CoreDNS в Pending. Решение: применить манифест выбранного CNI и дождаться Running.
  7. Просроченный токен join. Новая нода не присоединяется, в логах kubelet ошибка авторизации. Решение: kubeadm token create --print-join-command и повторный запуск join.

Все семь пунктов проверяются до продакшена, а не после инцидента. Разбор более широкого набора граблей, включая requests и limits, RBAC, NetworkPolicy и обновления, собран в материале про 10 частых ошибок при настройке и эксплуатации Kubernetes.

Что дальше: подготовка кластера к деплою приложений

Кластер готов, но принимать трафик из интернета он пока не умеет. Следующий шаг: Ingress-контроллер (ingress-nginx или Traefik), затем cert-manager для автоматических TLS-сертификатов от Let's Encrypt. Без Ingress каждый сервис придётся публиковать через NodePort, а это открытый диапазон 30000-32767 на всех узлах.

Дальше мониторинг и логирование. Prometheus с Grafana закрывают метрики узлов, подов и control plane, Loki или ELK собирают логи. Отдельно настройте резервное копирование etcd: без снапшота восстановить кластер после потери control plane нельзя. Для managed-сценария, когда не хочется администрировать control plane самостоятельно, подойдёт облачный Kubernetes: Timeweb Cloud предлагает Kubernetes, серверы и хранилище в одном кабинете.

Безопасный выкат новых версий удобно отрабатывать на canary-развёртывании: стабильная версия запускается с 3 репликами, canary с 1, общий селектор Service распределяет трафик так, что примерно 25% запросов уходит на новую версию и 75% на прежнюю (туториал Kubernetes по canary-развёртыванию). Схема позволяет поймать регресс на малой доле трафика и откатить релиз, не трогая основную часть подов.

Стартовый набор для продакшена выглядит так: три control plane за балансировщиком, минимум два worker-узла, Calico, Longhorn, Ingress с TLS, Prometheus с Grafana, автоматические снапшоты etcd. Соберите кластер по шагам из этой статьи, прогоните чек-лист проверки и только после этого открывайте доступ приложениям.

Поделиться:
Сохранить гайд? В закладки браузера