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

Первый кластер на собственных машинах удобнее строить как небольшой стенд: один 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, обновления и отказоустойчивость остаются следующими инженерными задачами, а не автоматически полученными свойствами первого стенда.

