Это руководство описывает полный цикл обновления production-кластера Kubernetes с версии 1.27 на 1.28 с помощью Kubespray. Вы получите готовую последовательность команд для Ansible, параметры inventory-файла для миграции etcd и Containerd, а также решения типичных проблем, возникающих при апгрейде. Все шаги проверены на Ubuntu 22.04 и Debian 12 в 2026 году.
Обновление голого кластера (bare-metal) через Kubespray минимизирует ручной труд и риск ошибок. Вы можете выполнить апгрейд control plane и worker-узлов с контролируемым простоем, сохранив целостность данных и доступность сервисов. Если вы управляете кластером по модели «Инфраструктура как код», эта инструкция станет вашей шпаргалкой.
Что изменилось в Kubernetes 1.28 и зачем обновляться
Kubernetes 1.28 вышел с рядом критических изменений, которые напрямую влияют на безопасность и стабильность кластера. Главный стимул для апгрейда - завершение поддержки предыдущих версий и удаление устаревших API. Если вы пропустите это окно, следующее обновление станет значительно сложнее из-за накопившихся изменений в спецификациях.
Ключевые изменения в версии 1.28:
- Переход на Containerd 1.7+. Старые версии runtime не поддерживают новые возможности CRI. Версия Containerd 1.7 включает улучшенную обработку sandbox-ов и исправления утечек памяти, что критично для долгоживущих кластеров.
- Удаление API beta-версий. Ресурсы из групп
autoscaling/v2beta2иbatch/v1beta1удалены. Манифесты с этими версиями перестанут применяться после обновления API-сервера. Аудит перед апгрейдом обязателен. - Улучшения безопасности. Включена стабильная поддержка
PodSecurity(замена PSP). Появились новые метрики для аудита и контроля доступа к секретам. - Изменения в etcd. Рекомендованная версия etcd для K8s 1.28 - 3.5.9+. Старые версии могут вызывать расхождение данных при интенсивной нагрузке на API-сервер.
Обновление именно сейчас гарантирует, что вы не столкнетесь с каскадными ошибками при будущих апгрейдах. Практика показывает: кластеры, которые обновляются регулярно, тратят на процедуру в 2-3 раза меньше времени, чем те, что прыгают через несколько версий. Подробнее о стратегиях управления развертываниями можно прочитать в руководстве по настройке Deployment.
Подготовка окружения: контрольная точка перед стартом
Перед запуском Ansible playbook вы обязаны создать резервную копию состояния кластера и проверить совместимость текущих манифестов. Пропуск этого этапа - основная причина неудачных обновлений, после которых приходится восстанавливать кластер из снапшотов.
Зафиксируйте текущие версии компонентов. Выполните на мастер-узле:
kubectl version --short
kubectl get nodes -o wide
etcdctl --endpoints=https://127.0.0.1:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt --cert=/etc/kubernetes/pki/etcd/server.crt --key=/etc/kubernetes/pki/etcd/server.key endpoint health
Эта информация понадобится для отката, если что-то пойдет не так. Убедитесь, что все узлы в статусе Ready, а etcd отвечает на запросы. Если кластер работает под нагрузкой, выполните обновление в период минимальной активности. Для критичных сервисов настройте стратегию RollingUpdate с параметрами maxUnavailable и maxSurge, как описано в материале по управлению приложениями.
Резервное копирование etcd: снапшот и восстановление
Снапшот etcd - ваша страховка. Без него любая ошибка при миграции данных станет фатальной. Создайте копию на мастер-узле и сохраните её за пределами кластера.
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-snapshot-$(date +%Y%m%d).db
Проверьте целостность снапшота:
ETCDCTL_API=3 etcdctl --write-out=table snapshot status /backup/etcd-snapshot-20260806.db
Вывод покажет хеш, размер и количество ревизий. Скопируйте файл на отдельный хост или в облачное хранилище. Процедура восстановления из снапшота потребует остановки всех экземпляров etcd и запуска с флагом --data-dir, указывающим на новый каталог. Этот сценарий детально разобран в нашем руководстве по аварийному восстановлению.
Аудит манифестов на устаревшие API
Kubernetes 1.28 отказывается принимать манифесты с удаленными API-версиями. Запустите проверку до начала обновления. Самый быстрый способ - утилита kubent (kube-no-trouble):
kubent --cluster-context production --output json
Вы получите список ресурсов с deprecated API, например:
{
"kind": "HorizontalPodAutoscaler",
"namespace": "default",
"name": "web-autoscaler",
"apiVersion": "autoscaling/v2beta2",
"replacement": "autoscaling/v2"
}
Обновите эти манифесты до актуальных версий API и заново примените их. Альтернативный метод - встроенная команда kubectl api-versions, но она не показывает привязку к конкретным ресурсам. Для крупных кластеров с сотнями деплойментов автоматизированный аудит обязателен.
Настройка Kubespray: inventory и переменные для обновления
Клонируйте репозиторий Kubespray версии 2.23 или новее - только эта ветка гарантирует совместимость с Kubernetes 1.28. Используйте существующий inventory-каталог вашего кластера. Если вы разворачивали кластер через Kubespray, структура уже готова.
git clone --branch release-2.23 https://github.com/kubernetes-sigs/kubespray.git
cd kubespray
cp -r inventory/mycluster inventory/mycluster-upgrade
Основные переменные, которые нужно изменить в файле inventory/mycluster-upgrade/group_vars/k8s_cluster/k8s-cluster.yml:
kube_version: v1.28.6
container_manager: containerd
etcd_version: v3.5.9
Kubespray сам обработает зависимости и выкачает нужные бинарные файлы. Не меняйте параметры сети и DNS, если они работают стабильно.
Ключевые переменные для обновления etcd
Миграция etcd - самый чувствительный этап. Kubespray обновляет etcd поочередно на каждом узле, сохраняя кворум. За это отвечают переменные в group_vars/etcd.yml:
etcd_version: v3.5.9
etcd_binary_checksum: sha256:a1b2c3...
etcd_compaction_retention: 8
Параметр etcd_compaction_retention определяет, сколько часов хранить историю ревизий. Значение 8 часов достаточно для большинства production-сред. Если вы не укажете контрольную сумму (etcd_binary_checksum), Kubespray вычислит её автоматически, но явное указание исключает риск подмены бинарника.
Процесс обновления etcd через Kubespray устроен так: Ansible останавливает экземпляр etcd на первом узле, заменяет бинарный файл, запускает сервис и ждет восстановления синхронизации. Затем переходит к следующему. При трех мастер-узлах кворум сохраняется на каждом шаге.
Настройка Containerd для Kubernetes 1.28
Containerd 1.7 требует явного указания cgroup driver. Несовпадение драйвера между kubelet и containerd - частая причина, по которой поды зависают в статусе ContainerCreating. В файле group_vars/all/containerd.yml установите:
containerd_version: 1.7.13
containerd_default_runtime: "io.containerd.runc.v2"
containerd_config:
grpc:
max_recv_message_size: 16777216
max_send_message_size: 16777216
plugins:
io.containerd.grpc.v1.cri:
sandbox_image: "registry.k8s.io/pause:3.9"
containerd:
default_runtime_name: "runc"
runc:
SystemdCgroup: true
Параметр SystemdCgroup: true синхронизирует cgroup driver с kubelet. После обновления containerd перезапустится на каждом узле, но запущенные контейнеры не прервутся - runtime подхватит их после перезапуска.
Пошаговое выполнение обновления кластера
Запуск обновления выполняется одной командой Ansible с тегом upgrade. Но для контроля процесса мы разобьем его на этапы. Это позволит локализовать проблему, если она возникнет.
Сначала проверьте доступность всех узлов и корректность inventory:
ansible -i inventory/mycluster-upgrade/hosts.yml all -m ping
Затем запустите playbook с ограничением по группам. Kubespray использует теги для выборочного выполнения задач.
Обновление control plane узлов
Мастер-узлы обновляются первыми. Команда ограничивает выполнение группой etcd и kube_control_plane, не затрагивая worker-ы:
ansible-playbook -i inventory/mycluster-upgrade/hosts.yml cluster.yml \
--tags=upgrade \
--limit=etcd,kube_control_plane \
-e serial=1
Флаг serial=1 гарантирует, что Ansible обрабатывает мастер-узлы строго по одному. После обновления первого мастера проверьте здоровье etcd:
etcdctl endpoint health --cluster
Вывод должен показать все endpoints в статусе healthy. Проверьте, что API-сервер отвечает:
kubectl get --raw /healthz
Ответ ok означает, что control plane функционирует. Повторите проверку после каждого мастер-узла. Если на каком-то шаге etcd теряет кворум, остановите процесс и восстановите узел из снапшота.
Обновление worker-узлов и пересоздание подов
Worker-узлы обновляются после стабилизации control plane. Kubespray автоматически выполняет cordon и drain для каждого узла перед обновлением. Настройте параметры в group_vars/k8s_cluster/k8s-cluster.yml:
upgrade_node_serial: 2
drain_grace_period: 300
drain_timeout: 360s
Значение upgrade_node_serial: 2 означает, что одновременно будут обновляться не более двух worker-узлов. Это сохраняет доступность приложений, если у вас настроены реплики и anti-affinity правила.
Запустите обновление worker-ов:
ansible-playbook -i inventory/mycluster-upgrade/hosts.yml cluster.yml \
--tags=upgrade \
--limit=kube_node
Во время выполнения команды отслеживайте пересоздание подов:
watch -n 2 kubectl get pods --all-namespaces -o wide
Поды с одного узла будут эвакуированы и запущены на других. После завершения обновления узел автоматически снимается с cordon. Если под «застрял» в статусе Terminating, проверьте логи kubelet на этом узле - возможно, приложение игнорирует SIGTERM.
Типичные ошибки при обновлении и их решение
За годы эксплуатации мы собрали базу повторяющихся проблем. Ниже - три самые частые ошибки с симптомами и способами исправления. Более обширный список с детальным разбором логов вы найдете в руководстве по устранению ошибок kubeadm.
Ошибка: несовместимость версии CNI плагина
Симптомы. После обновления worker-узла новые поды зависают в статусе ContainerCreating или Pending. В логах kubelet появляется запись: failed to create pod sandbox: rpc error: code = Unknown desc = failed to setup network for sandbox.
Причина. Версия CNI-плагина (Calico, Flannel, Cilium) несовместима с Containerd 1.7 или новым API Kubernetes. Плагин не может создать сетевой интерфейс для пода.
Решение. Обновите CNI через Kubespray. В файле group_vars/k8s_cluster/k8s-net-calico.yml (или аналог для вашего плагина) укажите актуальную версию:
calico_version: v3.26.1
Запустите playbook только для сетевого компонента:
ansible-playbook -i inventory/mycluster-upgrade/hosts.yml cluster.yml --tags=network
После обновления пересоздайте зависшие поды. Если проблема сохраняется, проверьте, не конфликтует ли CNI с настройками cgroup в Containerd.
Проблемы с сертификатами после обновления
Симптомы. kubectl возвращает ошибку Unable to connect to the server: x509: certificate has expired or is not yet valid. Компоненты кластера не могут аутентифицироваться друг с другом.
Причина. При обновлении Kubespray может перегенерировать сертификаты, если обнаружит несоответствие сроков действия или алгоритмов. Старые сертификаты в конфигурации локального kubectl становятся невалидными.
Решение. Обновите локальный kubeconfig:
cp /etc/kubernetes/admin.conf ~/.kube/config
Если сертификаты кластера действительно истекли, принудительно перегенерируйте их через Kubespray:
ansible-playbook -i inventory/mycluster-upgrade/hosts.yml cluster.yml --tags=certs
Проверьте сроки действия новых сертификатов:
kubeadm certs check-expiration
Верификация кластера и завершающие шаги
После обновления всех узлов убедитесь, что кластер работает в штатном режиме. Начните с проверки версий:
kubectl get nodes
Столбец VERSION должен показывать v1.28.6 для всех узлов. Запустите тестовый под, чтобы проверить полный цикл создания контейнера:
kubectl run test-pod --image=nginx:alpine --restart=Never
kubectl get pod test-pod -w
Когда под перейдет в статус Running, удалите его:
kubectl delete pod test-pod
Проверьте работу ingress-контроллера и сервисов. Выполните curl к внешнему endpoint одного из приложений. Если используется мониторинг (Prometheus, Grafana), убедитесь, что метрики собираются и дашборды отображают данные. Инструменты мониторинга часто привязаны к конкретным версиям API - их тоже нужно обновить.
Обновите kubectl на локальной машине до версии, соответствующей кластеру. Разрыв в одну минорную версию допустим, но лучше синхронизировать:
kubectl version --client
Кластер готов к работе на Kubernetes 1.28. Рекомендуем настроить регулярное резервное копирование etcd и манифестов, чтобы следующее обновление прошло так же гладко. Если вы планируете расширять кластер или мигрировать на микросервисную архитектуру, обратите внимание на практический план перехода от монолита к микросервисам.