Как развернуть кластер Kubernetes на собственных мощностях с kubeadm

На чтение
7 мин
Дата обновления
05.11.2026

Первый кластер на собственных машинах удобнее строить как небольшой стенд: один control-plane и один worker. Такой вариант позволяет увидеть работу kubeadm, сети Pod и подключения узла. Он не обеспечивает отказоустойчивость control-plane и не заменяет проектирование производственной инфраструктуры.

Ниже — документированный учебный маршрут для Linux с systemd и apt, ветки Kubernetes 1.37 и Calico 3.33.0. Предполагается установленный и настроенный CRI-совместимый containerd. Команды составлены по документации; кластер здесь фактически не разворачивался. На других версиях сначала сверяйте поддерживаемое сочетание Kubernetes, runtime и CNI, а не копируйте номера механически.

Подготовьте узлы и адресный план

Документация kubeadm указывает минимум 2 ГБ памяти на машину и не менее двух CPU для control-plane; приложениям понадобится дополнительный ресурс. Узлы должны иметь полную сетевую связность, уникальные имена и идентификаторы. Проверьте интерфейсы, маршрут по умолчанию и доступность выбранных адресов.

Авторский пример: control-plane cp1 имеет адрес 10.10.0.10, worker — 10.10.0.11; сеть Pod выбрана 192.168.0.0/16. Адреса замените своими и заранее убедитесь, что Pod-сеть не пересекается с сетью машин, VPN и Service-сетью. При нескольких интерфейсах адрес, автоматически выбранный kubeadm, может оказаться не тем, который доступен остальным узлам.

Не отключайте firewall целиком. API server по умолчанию использует TCP 6443, kubelet — TCP 10250; полный перечень включает отдельные порты etcd, scheduler и других компонентов. Разрешайте необходимые направления по официальной таблице и дополнительно учитывайте требования выбранного сетевого плагина. NodePort-диапазон не нужно публиковать в интернет только потому, что он есть в таблице.

Runtime, cgroups и swap: до kubeadm init

На каждом узле нужен runtime с поддержкой CRI. Установка одного Docker Engine не является прямой заменой этой настройки: встроенный dockershim удалён из Kubernetes. Для выбранного containerd проверьте, что CRI-плагин включён и его socket доступен.

Драйвер cgroups у kubelet и runtime должен быть согласован. Для systemd-систем документация рекомендует systemd-драйвер. В containerd 2.x параметр runc находится в такой ветке конфигурации:

[plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options]
  SystemdCgroup = true

Это фрагмент существующего /etc/containerd/config.toml, не замена всего файла. Для containerd 1.x путь секции другой. После корректировки перезапустите containerd и проверьте его состояние. В новых сочетаниях версий kubelet может определять драйвер через CRI; важно согласование результата, а не наличие скопированной строки в неподходящей секции.

sudo systemctl restart containerd
sudo systemctl status containerd --no-pager
swapon --show
sudo swapoff -a

Для простого стенда выбран вариант без swap. swapoff отключает его временно: отдельно настройте постоянное отключение по правилам вашей ОС. Kubernetes допускает специальные варианты использования swap, но они требуют настройки kubelet; совет «swap невозможен в любой версии» неверен.

Для маршрутизации IPv4 проверьте forwarding. Если его нужно включить вручную, сохраните настройку и примените:

printf 'net.ipv4.ip_forward = 1\n' | sudo tee /etc/sysctl.d/k8s.conf
sudo sysctl --system
sysctl net.ipv4.ip_forward

Установите компоненты на всех узлах

Официальный репозиторий pkgs.k8s.io разделён по minor-версиям. В показанной ветке используется v1.37; при выборе другой версии меняют адрес репозитория и читают соответствующую документацию. Не смешивайте компоненты разных поколений случайным обновлением ОС.

sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg
sudo mkdir -p -m 755 /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.37/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.37/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

Команды записи предполагают новый подготовленный стенд и заменяют содержимое названных конфигурационных файлов. В существующей системе сначала сопоставьте их с текущей конфигурацией. Зафиксируйте установленные версии командой kubeadm version и сведениями менеджера пакетов. До инициализации kubelet может перезапускаться в ожидании конфигурации — сам по себе этот этап не доказывает неисправность.

Инициализируйте только control-plane

На cp1 выполните init с вашим доступным адресом и согласованной Pod-сетью:

sudo kubeadm init --apiserver-advertise-address=10.10.0.10 --pod-network-cidr=192.168.0.0/16

При нескольких runtime явно выбирают подходящий CRI socket. Не пропускайте ошибки предварительной проверки массовым ignore-preflight-errors: сообщение должно быть разобрано по существу. Для будущей высокой доступности отдельно проектируют общий control-plane endpoint; один advertise-address этого не заменяет.

После успешного init настройте kubectl обычному пользователю на control-plane:

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

admin.conf предоставляет административные полномочия: не публикуйте его и не раздавайте как обычный файл проекта. Сохраните выданную kubeadm команду join в защищённом месте. Node пока может быть NotReady, а CoreDNS — ожидать сеть: установка CNI является следующим отдельным шагом.

Установите один CNI — в примере Calico

Для нового on-premises кластера документация Calico предлагает оператор. Для Kubernetes 1.36 и выше в рассмотренной версии используется следующий CRD-манифест. Вариант ниже — iptables, без перехода на eBPF:

kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.33.0/manifests/v3_projectcalico_org.yaml
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.33.0/manifests/tigera-operator.yaml
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.33.0/manifests/custom-resources.yaml

До применения откройте custom-resources.yaml и проверьте настройки, включая IP pool и соответствие выбранной Pod-сети. Только затем создайте ресурсы:

kubectl create -f custom-resources.yaml
kubectl get tigerastatus
kubectl get pods -A

Оператор управляет развёртыванием компонентов. Дождитесь их готовности и проверьте события при ошибках загрузки образов или сети. Не устанавливайте поверх второй CNI, пытаясь ускорить переход в Ready. Требования ядра и сетевой инфраструктуры Calico проверяют до установки, особенно если вы меняете способ маршрутизации.

Подключите worker и проверьте результат

На подготовленном worker выполните точную команду, которую напечатал init. Её структура выглядит так; TOKEN и HASH необходимо заменить реальными значениями своего кластера:

sudo kubeadm join 10.10.0.10:6443 --token TOKEN --discovery-token-ca-cert-hash sha256:HASH

Не публикуйте токен вместе с отчётом о стенде. Если команда устарела, получите актуальную по инструкции kubeadm для bootstrap tokens; не отключайте проверку доверия ради устранения сообщения.

С control-plane проверьте узлы и системные Pod. Авторский порядок диагностики:

kubectl get nodes -o wide
kubectl get pods -A
kubectl describe node worker1
kubectl get events -A --sort-by=.metadata.creationTimestamp

worker1 замените именем узла из вывода. При проблеме runtime смотрите его журнал и журнал kubelet; при NotReady после CNI — сетевые компоненты и сообщения узла; при join timeout — доступность API и адрес. Не запускайте init повторно на worker.

Ready у двух узлов, работающие системные компоненты и понятная конфигурация — результат базового развёртывания. Отдельно проверьте свой тестовый workload и связь Pod. Хранилище, ingress, резервное копирование etcd, обновления и отказоустойчивость остаются следующими инженерными задачами, а не автоматически полученными свойствами первого стенда.