Deckhouse Kubernetes 1.31 в изолированном КИИ: обновление без внешних registry
Обновили Deckhouse-кластер в изолированном КИИ-сегменте до Kubernetes 1.31: подробно о переносе образов, обновлении встроенных компонентов и порядке прохода контуров.
Deckhouse Kubernetes Platform добавила поддержку Kubernetes 1.31 с улучшениями для изолированных контуров
Deckhouse Kubernetes Platform выпустила поддержку Kubernetes 1.31 - и мы уже прошли это обновление на одном из кластеров в изолированном КИИ-сегменте. Кластер находится в сети без маршрутизации во внешний интернет: никакого DockerHub, никакого registry.deckhouse.io напрямую. Вся доставка образов - через внутренний зеркальный реестр, который мы ведём сами. Именно этот кейс и разберём: не само по себе содержание 1.31 (это мы разобрали ещё в октябре), а механику обновления в условиях закрытого контура.
Что изменилось в Deckhouse при поддержке 1.31
Deckhouse при переходе на новую минорную версию Kubernetes обновляет не только control plane, но и набор встроенных компонентов: CNI (Cilium в нашем случае), CSI-драйверы, metrics-server, coredns, kube-proxy. Всё это идёт как часть релизного бандла Deckhouse, а не отдельными обновлениями. В изолированном контуре это значит: все образы этих компонентов нужно иметь в локальном реестре до начала обновления. Не «в процессе» - именно до.
Дополнительно в этом релизе Deckhouse улучшил работу с ImagePullSecrets во встроенных компонентах при нестандартном registry-эндпойнте - это как раз наш случай. Раньше часть системных подов игнорировала переопределение registry через deckhouse-registry-сикрет и пыталась тянуть образы из registry.deckhouse.io. В 1.31-релизе это починено централизованно.
Подготовка: инвентаризация образов
Первый шаг - получить список образов, которые Deckhouse будет использовать после обновления. Это делается через dhctl:
dhctl mirror pull-images \
--license=<your-ee-license> \
--registry=registry.deckhouse.io \
--deckhouse-tag=v1.63 \
--output-dir=/tmp/deckhouse-images
Флаг --deckhouse-tag - это тег самого Deckhouse, а не версия Kubernetes. Версия кластера управляется через ClusterConfiguration.kubernetesVersion. Тег Deckhouse, в котором появилась поддержка 1.31 - v1.63.x (текущая стабильная ветка на момент обновления).
Команда выгружает всё: образы control plane, системных компонентов, модулей, которые активированы в вашем кластере. Размер выгрузки немаленький - несколько десятков GB для полного набора. На изолированный сервер это уходит через съёмный носитель или по защищённому каналу - в зависимости от регламента конкретного КИИ.
# После переноса на изолированный хост - заливка в локальный реестр
dhctl mirror push-images \
--registry=registry.internal.kii.local/deckhouse \
--input-dir=/tmp/deckhouse-images
Вот здесь первый нюанс: внутренний реестр должен поддерживать OCI-формат и корректно обрабатывать multi-arch манифесты. У нас стоит Harbor. Подводных камней с Harbor не было, но важно проверить, что robotaccount для push имеет права на создание репозиториев - иначе push-images упадёт на первом же образе с непонятной ошибкой.
Настройка Deckhouse на работу с локальным реестром
Если кластер изначально разворачивался с внешним реестром, а потом переводился на изолированный контур - в deckhouse-registry сикрете нужно убедиться, что адрес реестра и учётные данные актуальны:
kubectl -n d8-system get secret deckhouse-registry -o jsonpath='{.data.address}' | base64 -d
Если адрес не совпадает с вашим локальным реестром - обновляем через dhctl config edit provider-cluster-configuration или напрямую через патч сикрета (второй вариант хуже, потому что Deckhouse может перезатереть его своим значением при следующем reconcile).
Отдельно - clusterConfiguration. Там в imagesRepo должен быть прописан ваш локальный путь:
imagesRepo: registry.internal.kii.local/deckhouse
Если это не так, нужно обновить через dhctl config edit cluster-configuration и дождаться, пока Deckhouse применит изменение.
Само обновление: порядок действий
После того как образы залиты и конфигурация проверена:
Выставить целевую версию Kubernetes. В ClusterConfiguration меняем kubernetesVersion: "1.31" и применяем через deckhouse-controller. Deckhouse не обновляет кластер сразу - он сначала проверяет наличие образов в локальном реестре для всех компонентов новой версии.
Отследить статус через очередь. Deckhouse управляет обновлением через nodegroup-механизм: control plane обновляется первым, затем поочерёдно ноды по группам. Посмотреть текущее состояние:
kubectl -n d8-system get pod deckhouse-0 -o jsonpath='{.status.containerStatuses[0].image}'
kubectl get nodes -o custom-columns='NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion'
PodDisruptionBudget - то же, что и при обычном обновлении. Если у вас есть деплойменты с maxUnavailable: 0 и одной репликой, drain будет ждать. Мы на этом кластере уже сталкивались с этим при прошлом обновлении - проверили заранее.
Встроенные компоненты: где пришлось вмешаться
Cilium при переходе на 1.31 пересоздаёт часть eBPF-программ. На нагруженных нодах в момент пересоздания краткосрочно прерывалась связность между подами - порядка 3-5 секунд на ноду. Для большинства сервисов это прошло незаметно, но один из компонентов с коротким таймаутом на health check дал алерт. Alertmanager поймал, ничего не упало, но полезно знать заранее: при rolling update Cilium ожидать кратковременных прерываний - нормально.
CoreDNS обновился без видимых последствий. metrics-server тоже.
CSI-драйвер для нашей СХД (Ceph через rook-ceph) - отдельная история. Rook-ceph в этом кластере стоит не через Deckhouse-модуль, а как самостоятельное решение. Deckhouse его не трогает при обновлении, что хорошо - мы обновляем rook-ceph отдельно по собственному расписанию. Но важно проверить совместимость: rook-ceph 1.15+ поддерживает Kubernetes 1.31, более ранние версии - нет.
Итог
Обновление прошло без деградации сервисов. На прохождение всего контура - от выгрузки образов до полного обновления последней рабочей ноды - ушло примерно полдня с учётом времени на перенос образов на изолированный сегмент.
Главный вывод: dhctl mirror-инструментарий для изолированных контуров работает как нужно - образы переносятся воспроизводимо, ничего не нужно тянуть вручную построчно из release notes. Улучшение поведения с локальным реестром в этом релизе Deckhouse реально ощутимо: системные поды перестали пытаться обратиться во внешний registry даже при специфичных условиях перезапуска.
Следующая задача - аналогичный проход на втором кластере этого же клиента, где сеть ещё жёстче изолирована и Harbor настроен с proxy-кэшем вместо прямой заливки. Посмотрим, как там себя поведёт push-images в связке с proxy-cache-режимом. В managed-сопровождении держим оба кластера - по результатам второго прохода будет понятнее, стоит ли что-то менять в схеме доставки образов.