Моя домашняя лаборатория — кластер kubeadm из семи нод, на котором крутятся реальные сервисы для семьи и моих проектов. В августе он упёрся в стену, в которую скоро упрутся и многие продовые кластеры, поэтому я использовал его как репетицию.
Три проблемы, которые блокировали друг друга
- Kubernetes 1.33 вышел из поддержки в июне 2026.
- Community ingress-nginx ретировали (архив в марте 2026, патчей безопасности больше не будет), а его последний релиз не поддерживал ничего новее 1.33. То есть он блокировал каждый шаг апгрейда.
- Исходный инвентарь kubespray был утерян, так что декларативно ничего не переприменить. Кластер тихо стал обычным kubeadm-кластером.
По одной эти проблемы не решаются: ingress блокирует апгрейд, а апгрейд — причина менять ingress. Поэтому план уложился в один день: Calico → Cilium (eBPF, без kube-proxy), ingress-nginx → Gateway API и 1.33 → 1.34 → 1.35 → 1.36.
Почему Cilium, зная, что он рискованнее
Безопасным CNI-независимым выбором была отдельная реализация Gateway API, например Envoy Gateway. Я всё равно выбрал Cilium и записал почему: ресурсы Gateway API переносимы. HTTPRoute, написанные сегодня, переживут смену GatewayClass. Рискованный вариант не тупиковый — в отличие от ещё одного апгрейда ретированного ingress-контроллера, который всё равно упёрся бы в 1.35.
Записанное обоснование окупилось: когда та же развилка возникла на рабочем кластере, ответ уже был.
Живая миграция: попробовал и отказался по фактам
У Cilium есть задокументированная миграция по нодам, когда Calico и Cilium работают рядом. Она провалилась по конкретной причине: Calico работал с VXLAN в режиме Always, и у нод Calico не было маршрута до pod CIDR Cilium. Поды мигрированной ноды не видели ничего на остальных нодах — даже CoreDNS. Два острова — ровно то, что гибридный режим должен предотвращать, а апстрим предупреждает, что процедура не проверена с существующими NetworkPolicy.
Поэтому я перешёл на контролируемый big-bang: разметить все ноды, записать CNI-конфиг Cilium, перезагрузить весь кластер (около 2,5 минуты простоя), затем ещё одна перезагрузка после удаления Calico, чтобы вычистить его правила iptables и VXLAN-интерфейс.
Порядок, который имел значение
- Замена kube-proxy должна была приехать вместе с удалением NodeLocal DNSCache и возвратом
clusterDNSна CoreDNS. Как только Cilium транслирует ClusterIP в eBPF, локальный кеш на ноде работать не может, и поды остались бы с мёртвым резолвером. - Cilium вместе с kube-proxy в режиме IPVS — сломанное промежуточное состояние, а не перевалочный пункт. Поды не достают ни один ClusterIP.
- Переключение ingress было наименее рискованной частью. Gateway работал рядом с ingress-nginx, каждый хост проверялся через него заголовком
Host:, пока реальный трафик шёл по-старому, затем хосты переключались по одному с мгновенным откатом. Туннели Cloudflare, чьи правила живут в панели Cloudflare, а не в кластере, перенастроены через API. Только после этого ingress-nginx удалён.
Грабли, о которых стоит прочитать до
- Pod CIDR по умолчанию в чарте —
10.0.0.0/8. В сети с приватными маршрутами в10.xон молча проглатывает LAN и все маршруты в VPN. - Если
/opt/cni/binпринадлежит не root, init-контейнер Cilium падает: он сбрасываетDAC_OVERRIDE. - Без kube-proxy агенту нужен
k8sServiceHostна локальный API-эндпоинт, иначе он зависает на собственном eBPF. helm upgradeне перезапускает Cilium, если поменялся только ConfigMap. И агенту, и оператору нуженrollout restart. Встроенная проверка дрейфа об этом скажет (Mismatch found).TLSRouteживёт в экспериментальном наборе CRD Gateway API.- Прокси без SNI ломает TLS passthrough с ошибкой 502.
kubeadm upgrade nodeна последней control-plane ноде возвращал аддон kube-proxy на каждом хопе, потому что--skip-phasesне наследуется. Проверяйте kube-proxy после каждого хопа.
Итог
Семь из семи нод Ready на 1.36, ноль проблемных подов, все тома хранилища здоровы, все приложения Argo CD Synced и Healthy, все эндпоинты отвечают. Урок, который я несу в рабочие кластеры, — не «big-bang — это нормально», а «сначала замерь, потом выбирай форму миграции»: живая миграция на бумаге выглядела безопаснее и была ровно тем, что сломало бы всё.