Моя домашняя лаборатория — кластер 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 — это нормально», а «сначала замерь, потом выбирай форму миграции»: живая миграция на бумаге выглядела безопаснее и была ровно тем, что сломало бы всё.