Обновление кластера Kubernetes с версии 1.28 до 1.29 через kubeadm - это контролируемая процедура, которая при правильной подготовке выполняется без потери данных и с минимальным влиянием на рабочие нагрузки. Это руководство содержит точную последовательность команд, проверенную на bare-metal кластере Ubuntu 22.04. Вы выполните резервное копирование etcd, обновите control-plane, поочередно прокатите апдейт по worker-узлам и приведете в соответствие версии CNI и CoreDNS.
Процесс обновления занимает от 30 до 60 минут в зависимости от размера кластера. Главный принцип - строгая последовательность: сначала control-plane, затем worker-ноды. Нарушение порядка или пропуск проверки совместимости - основная причина сбоев, с которыми сталкиваются администраторы. Если вы управляете кластером через подход «Инфраструктура как код», обратите внимание на автоматизацию обновления Kubernetes на bare metal с Ansible - это сокращает время операции с часов до минут.
Что нового в Kubernetes 1.29 и зачем обновляться
Релиз 1.29 принес несколько критичных изменений, которые напрямую влияют на эксплуатацию. Во-первых, API версии flowcontrol.apiserver.k8s.io/v1beta2 удален - если ваши манифесты или операторы его используют, обновление заблокирует их работу. Во-вторых, прекращена поддержка insecure-режима в kubelet (флаг --pod-infra-container-image удален полностью). В-третьих, улучшена производительность etcd за счет оптимизации снапшотов.
Своевременный апгрейд закрывает векторы уязвимостей, исправленные в патчах 1.28.x, и дает доступ к новым возможностям планировщика. Главный практический стимул - политика поддержки Kubernetes: версия 1.28 получает исправления безопасности только до выхода 1.31. После этого кластер остается без патчей. Если вы еще не знакомы с альтернативными подходами к обновлению, изучите стратегии обновления Kubernetes: Rolling, Blue-Green и Canary - это поможет выбрать оптимальный сценарий для вашей среды.
Подготовка к обновлению: контрольный список
Перед запуском kubeadm upgrade выполните пять обязательных проверок. Пропуск любого из пунктов этого списка - прямой путь к длительной диагностике и потенциальной потере данных.
Резервное копирование etcd и конфигураций
Снапшот etcd - единственный гарантированный способ отката при фатальном сбое. Выполните команду на control-plane узле:
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 snapshot status /backup/etcd-snapshot-20260807.db
Сохраните манифесты статических подов и конфигурацию kubeadm:
cp -r /etc/kubernetes /backup/kubernetes-config-$(date +%Y%m%d)
cp /var/lib/kubelet/config.yaml /backup/kubelet-config.yaml
Проверка совместимости версий и план обновления
Убедитесь, что текущая версия kubeadm - 1.28.x. Пропускать минорные версии нельзя: обновление с 1.27 сразу на 1.29 не поддерживается.
kubeadm version
kubectl version --short
Запросите план обновления. kubeadm проанализирует кластер и покажет доступные целевые версии:
kubeadm upgrade plan
Вывод покажет версии kubeadm, kubelet, etcd и CoreDNS, которые будут обновлены. Обратите внимание на строки с предупреждениями о deprecated API - их нужно устранить до начала процедуры.
Проверьте использование устаревших API в текущих ресурсах:
kubectl get apiservices | grep -v Available
kubectl api-resources --api-group=flowcontrol.apiserver.k8s.io
Если обнаружены ресурсы с API v1beta2 flowcontrol, обновите их манифесты до v1beta3 до запуска kubeadm upgrade. Игнорирование этого шага приведет к ошибкам при обновлении control-plane.
Пошаговое обновление control-plane узла
Control-plane обновляется первым. На время обновления API-сервер будет недоступен, поэтому запланируйте окно на 10-15 минут. Рабочие нагрузки на worker-узлах продолжат работу.
Обновление пакетов kubeadm, kubelet, kubectl
Добавьте репозиторий Kubernetes 1.29. Для Ubuntu 22.04:
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
Удерживайте kubelet от автоматического обновления до завершения процедуры:
sudo apt-mark hold kubelet kubectl
Установите kubeadm версии 1.29.x:
sudo apt install -y kubeadm=1.29.8-1.1
Проверьте версию:
kubeadm version
Выполнение kubeadm upgrade apply
Выведите control-plane узел из планирования - новые поды не будут на него назначаться:
kubectl drain <control-plane-node> --ignore-daemonsets --delete-emptydir-data
Запустите обновление с указанием целевой версии:
sudo kubeadm upgrade apply v1.29.8
kubeadm выведет подтверждение версии и запросит согласие. Внимательно прочитайте вывод - если есть предупреждения о deprecated API, прервите процедуру (Ctrl+C) и устраните их. При успешном выполнении вы увидите сообщение [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.29.8".
Обновление kubelet и возврат узла в работу
Снимите блокировку с kubelet и kubectl, установите новые версии:
sudo apt-mark unhold kubelet kubectl
sudo apt install -y kubelet=1.29.8-1.1 kubectl=1.29.8-1.1
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Верните узел в планирование:
kubectl uncordon <control-plane-node>
Проверьте статус узла и версии компонентов:
kubectl get nodes
kubectl version --short
Control-plane должен отображаться как Ready, версия 1.29.8. Если статус NotReady, проверьте логи kubelet: journalctl -u kubelet -f.
Обновление worker-узлов
Worker-ноды обновляются последовательно, по одной. Это сохраняет доступность приложений при настроенных репликах и PodDisruptionBudget. Для каждого worker-узла выполните одинаковую процедуру.
Поочередное обновление: drain, upgrade, uncordon
Шаг 1 - выведите узел из планирования и эвакуируйте поды:
kubectl drain <worker-node> --ignore-daemonsets --delete-emptydir-data --grace-period=60
Флаг --grace-period=60 дает контейнерам 60 секунд на корректное завершение. Увеличьте значение для тяжелых нагрузок.
Шаг 2 - обновите kubeadm на worker-узле (подключитесь к нему по SSH):
sudo apt update
sudo apt install -y kubeadm=1.29.8-1.1
Шаг 3 - выполните обновление конфигурации узла:
sudo kubeadm upgrade node
Шаг 4 - обновите kubelet и перезапустите его:
sudo apt install -y kubelet=1.29.8-1.1
sudo systemctl daemon-reload
sudo systemctl restart kubelet
Шаг 5 - верните узел в кластер:
kubectl uncordon <worker-node>
Дождитесь перехода узла в статус Ready, затем переходите к следующему. Параллельное обновление нескольких worker-узлов допустимо, если количество реплик ваших сервисов гарантирует доступность при временном сокращении пула нод.
Обновление плагинов CNI и CoreDNS
После обновления всех узлов приведите версии сетевого плагина и CoreDNS в соответствие с рекомендациями для Kubernetes 1.29.
Обновление сетевого плагина (CNI)
Проверьте текущую версию CNI. Для Calico:
kubectl get deployment -n kube-system calico-kube-controllers -o jsonpath='{.spec.template.spec.containers[0].image}'
Для Flannel:
kubectl get daemonset -n kube-flannel kube-flannel-ds -o jsonpath='{.spec.template.spec.containers[0].image}'
Сверьтесь с матрицей совместимости вашего CNI. Calico 3.27+ и Flannel 0.24+ поддерживают Kubernetes 1.29. Загрузите актуальный манифест и примените его:
# Для Calico
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml
# Для Flannel
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.24.0/Documentation/kube-flannel.yml
Проверьте перезапуск подов CNI и отсутствие ошибок в логах.
Обновление CoreDNS
Проверьте текущую версию CoreDNS:
kubectl get deployment -n kube-system coredns -o jsonpath='{.spec.template.spec.containers[0].image}'
Kubernetes 1.29 рекомендует CoreDNS 1.11.1. Обновите через kubeadm:
kubeadm upgrade apply v1.29.8 --feature-gates=CoreDNS=true
Либо вручную отредактируйте deployment:
kubectl set image deployment/coredns -n kube-system coredns=registry.k8s.io/coredns/coredns:v1.11.1
Убедитесь, что все поды CoreDNS перезапустились и находятся в статусе Running.
Типичные ошибки при обновлении и их решение
За годы эксплуатации кластеров мы собрали повторяющиеся сценарии сбоев. Вот конкретные сообщения об ошибках и команды для их устранения.
Ошибка: сертификаты истекли или не обновляются
Симптом: после kubeadm upgrade apply узлы не подключаются к API-серверу, в логах kubelet ошибка x509: certificate has expired.
Причина: сертификаты control-plane не обновились в процессе апгрейда. Решение - принудительное обновление:
sudo kubeadm certs renew all
sudo systemctl restart kubelet
Проверьте срок действия сертификатов:
sudo kubeadm certs check-expiration
Поды не запускаются после обновления узла
Симптом: после drain и uncordon поды висят в статусе Pending или CrashLoopBackOff.
Причина 1 - kubelet не перезапустился корректно. Проверьте логи:
journalctl -u kubelet -n 50 --no-pager
Причина 2 - CNI не совместим с новой версией kubelet. Проверьте логи сетевых подов:
kubectl logs -n kube-system <cni-pod>
Решение: перезапустите kubelet, при необходимости обновите CNI до совместимой версии.
Причина 3 - устаревшие сетевые политики блокируют трафик. Временно отключите их для диагностики:
kubectl delete networkpolicy --all -n <namespace>
Стратегии минимизации downtime при обновлении
Downtime приложений при обновлении kubeadm - не обязательное зло, а результат планирования. Три механизма сводят его к нулю.
Первый - PodDisruptionBudget. Настройте PDB для каждого критичного deployment:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: app-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: critical-app
PDB блокирует drain узла, если эвакуация нарушит минимальное количество доступных реплик. kubeadm будет ждать, пока условие не выполнится.
Второй - правильная настройка drain. Флаг --grace-period задает время на graceful shutdown контейнеров. Флаг --ignore-daemonsets обязателен, так как DaemonSet-поды не эвакуируются. Для stateful-приложений с длительным завершением увеличьте grace period до 300 секунд.
Третий - очередность обновления узлов. Начинайте с узлов, на которых нет критичных нагрузок. Если приложение развернуто с тремя репликами на трех разных worker-узлах, обновляйте узлы последовательно, дожидаясь полной готовности реплик после каждого uncordon. Мониторинг во время процесса ведите через kubectl get pods -o wide -w в отдельном терминале.
Заключение: проверка кластера после обновления
Финальный аудит подтверждает, что кластер полностью функционален. Выполните пять проверок.
Первая - версии всех узлов:
kubectl get nodes -o wide
Все узлы должны показывать VERSION v1.29.8 и STATUS Ready.
Вторая - статус системных подов:
kubectl get pods -n kube-system
Все поды в статусе Running, количество перезапусков не увеличивается.
Третья - работоспособность DNS:
kubectl run -it --rm debug --image=busybox --restart=Never -- nslookup kubernetes.default
Четвертая - создание и удаление тестового пода:
kubectl run test-pod --image=nginx --restart=Never
kubectl get pod test-pod
kubectl delete pod test-pod
Пятая - проверка сертификатов:
sudo kubeadm certs check-expiration
Все сертификаты должны иметь срок действия более 30 дней. Если какие-то истекают раньше, обновите их командой kubeadm certs renew all. Обновите внутреннюю документацию, зафиксировав новую версию кластера и дату апгрейда. Проведите тестирование отказоустойчивости - отключите один worker-узел и убедитесь, что сервисы переезжают на оставшиеся.