Обновление Kubernetes с Windows-нодами: ограничения и пошаговое руководство 2026 | AdminWiki

Обновление Kubernetes с Windows-нодами: ограничения и пошаговое руководство 2026

06 августа 2026 7 мин. чтения

Ключевые ограничения Windows-контейнеров при обновлении Kubernetes

Обновление гибридного кластера Kubernetes, где control-plane работает на Linux, а worker-ноды - на Windows Server, требует учёта специфических ограничений. Пропуск этапа проверки совместимости API приводит к массовым отказам при деплое. Главное правило: версия Windows-нод не может опережать версию control-plane, а разрыв между ними не должен превышать одного минорного релиза. Нарушение этого правила вызывает ошибку NodeVersionSkew и потерю ноды из кластера.

Контейнеры Windows не поддерживают привилегированный режим, hostNetwork и ряд возможностей Linux-ядра. При обновлении версии API часть ресурсов становится недоступной, а старые манифесты перестают применяться. Перед началом обновления проверьте все деплойменты на наличие депрекейтов - утилита kubectl convert или плагин kubepug выявят проблемные места за минуты.

Какие версии API и ресурсы недоступны для Windows-контейнеров

С выходом Kubernetes 1.25 прекращена поддержка networking.k8s.io/v1beta1 для Ingress, а в 1.26 удалены бета-версии autoscaling/v2beta2 и policy/v1beta1 (PodSecurityPolicy). Если ваши манифесты ссылаются на эти API, после обновления control-plane они не применятся. Для Windows-контейнеров критичны следующие ограничения:

  • securityContext: поля runAsUser, privileged, capabilities, seLinuxOptions игнорируются или вызывают ошибку. Windows использует windowsOptions для GMSA и настроек хоста.
  • hostNetwork: недоступен. Поды не могут использовать сетевой стек ноды напрямую.
  • volumeMounts: монтирование подкаталогов из ConfigMap/Secret не работает - только полный том.
  • readinessProbe/livenessProbe: exec-проверки выполняются внутри контейнера Windows, но не все команды доступны (например, /bin/sh отсутствует).

Проверьте депрекейты командой:

kubectl get deployments,statefulsets,daemonsets -A -o json | kubepug --k8s-version=v1.28

Затем сконвертируйте манифесты в актуальный API:

kubectl convert -f old-ingress.yaml --output-version networking.k8s.io/v1

Официальная матрица совместимости Windows Server и Kubernetes доступна в документации Microsoft: Windows Server 2022 поддерживает Kubernetes 1.25+, Windows Server 2019 - 1.14–1.25. Если ваш кластер старше 1.25 на Windows Server 2019, обновление потребует миграции на Server 2022.

Подготовка к обновлению: чек-лист для гибридного кластера

Риск потери данных и длительного простоя снижается до нуля, если следовать чек-листу. Первый и обязательный шаг - резервное копирование etcd. Без снапшота откат control-plane превращается в ручное восстановление из манифестов, что занимает часы.

  1. Снапшот etcd:
    ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d).db \
      --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
  2. Выгрузка манифестов: экспортируйте все ресурсы через kubectl get all -A -o yaml > cluster-backup.yaml. Отдельно сохраните ConfigMap, Secret и PVC.
  3. Снапшоты дисков Windows-нод: на уровне облака или гипервизора сделайте снапшоты виртуальных машин. При локальном развёртывании используйте Windows Server Backup или wbadmin.
  4. Проверка совместимости: сверьте версии Kubernetes и Windows Server по матрице. Убедитесь, что CNI-плагин (Calico, Flannel, Antrea) поддерживает целевую версию Kubernetes и имеет сборку для Windows.
  5. Оценка downtime: Drain каждой Windows-ноды перед обновлением остановит поды. Заранее согласуйте окно обслуживания и настройте PodDisruptionBudget для критичных сервисов.

Для кластеров, развёрнутых через Kubespray, процедура обновления имеет свою специфику. Рекомендую ознакомиться с руководством по обновлению Kubernetes через Kubespray, где разобраны типовые ошибки и настройка inventory-файлов.

Пошаговое обновление control-plane на Linux

Control-plane обновляется первым, строго на одну минорную версию за шаг. Перескок через несколько версий (например, с 1.25 на 1.28) не поддерживается и ломает кластер. Процесс состоит из трёх этапов: обновление пакетов kubeadm/kubectl/kubelet, применение новой версии к control-plane, обновление CNI-плагинов.

Обновление kubeadm и компонентов control-plane

На всех control-plane нодах выполните:

apt-mark unhold kubeadm kubectl kubelet
apt update && apt install -y kubeadm=1.28.2-1.1 kubectl=1.28.2-1.1 kubelet=1.28.2-1.1
apt-mark hold kubeadm kubectl kubelet

Проверьте доступные версии и план обновления:

kubeadm upgrade plan

Вывод покажет целевую версию, состояние кластера и предупреждения. Примените обновление к первой control-plane ноде:

kubeadm upgrade apply v1.28.2

Флаг --etcd-upgrade=false пропускает обновление etcd, если оно не требуется. Для экспериментальных версий добавьте --allow-experimental-upgrades. После завершения обновите kubelet на всех control-plane нодах:

systemctl daemon-reload && systemctl restart kubelet

Проверьте версии:

kubectl get nodes -o wide

CNI-плагин требует отдельного внимания. Calico для Windows обновляется через манифест оператора, Flannel - через kubectl apply с новым DaemonSet. Убедитесь, что версия CNI совместима с новой версией Kubernetes и поддерживает Windows-ноды. После обновления CNI проверьте логи подов в kube-system на предмет ошибок сетевого взаимодействия.

Обновление Windows worker-нод: настройка Kubelet и ContainerD

Windows-ноды обновляются последовательно, по одной. Перед началом drain ноды, чтобы перенести рабочую нагрузку:

kubectl drain win-node-01 --ignore-daemonsets --delete-emptydir-data

Остановите службы kubelet и kube-proxy на Windows-ноде:

Stop-Service kubelet -Force
Stop-Service kube-proxy -Force

Скачайте новые бинарники kubelet и kube-proxy из официального репозитория Kubernetes (путь вида https://dl.k8s.io/v1.28.2/bin/windows/amd64/). Замените файлы в C:\k\ (стандартный путь установки).

Конфигурация Kubelet для Windows: ключевые параметры

Файл конфигурации kubelet (C:\var\lib\kubelet\config.yaml) содержит специфические для Windows параметры:

apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
clusterDNS:
- 10.96.0.10
clusterDomain: cluster.local
featureGates:
  WindowsHostProcessContainers: true
cgroupDriver: systemd
networkPlugin: cni
podCIDR: 10.244.0.0/16
resolvConf: ""
authentication:
  anonymous:
    enabled: false
  webhook:
    enabled: true
authorization:
  mode: Webhook

Критичные отличия от Linux:

  • --windows-service - регистрирует kubelet как службу Windows, управляемую через sc.exe.
  • --network-plugin=cni - обязательно, другие плагины Windows не поддерживает.
  • --cgroups-per-qos=false - cgroups v1 в Windows реализованы частично, управление ресурсами идёт через --reserved-cpus.

Регистрация службы после замены бинарника:

sc.exe create kubelet binPath= "C:\k\kubelet.exe --windows-service --config=C:\var\lib\kubelet\config.yaml --kubeconfig=C:\etc\kubernetes\kubelet.conf --log-dir=C:\var\log\kubelet" start= auto
sc.exe start kubelet

Настройка ContainerD на Windows Server

ContainerD на Windows использует конфигурационный файл C:\Program Files\containerd\config.toml. После обновления Kubernetes необходимо проверить и скорректировать параметры:

version = 2
[plugins."io.containerd.grpc.v1.cri"]
  sandbox_image = "mcr.microsoft.com/oss/kubernetes/pause:3.9"
  [plugins."io.containerd.grpc.v1.cri".containerd]
    default_runtime_name = "runhcs-wcow-process"
    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runhcs-wcow-process]
      runtime_type = "io.containerd.runhcs.v1"

Параметр sandbox_image должен указывать на актуальный образ pause для Windows. Версия 3.9 совместима с Kubernetes 1.25+. runtime_type = "io.containerd.runhcs.v1" включает поддержку Windows-контейнеров через Host Compute Service (HCS). Без этой строки ContainerD не сможет запускать Windows-поды.

После изменения конфигурации перезапустите службу:

Restart-Service containerd

Проверьте, что нода вернулась в кластер и готова принимать нагрузку:

kubectl uncordon win-node-01
kubectl get node win-node-01 -o wide

Для углублённого понимания безопасности контейнеров на Windows рекомендую руководство по безопасности Docker на Windows Server, где разобрана интеграция со средствами аудита и сканирования образов.

Решение типовых проблем после обновления

После обновления гибридного кластера две категории ошибок встречаются чаще всего: отказы монтирования томов и сброс сетевых настроек GMSA. Диагностика начинается с логов пода и описания PVC.

Ошибки монтирования томов: FlexVolume и CSI

Симптом: под зависает в статусе ContainerCreating, в событиях - MountVolume.SetUp failed. Для FlexVolume причина кроется в устаревшем драйвере, который несовместим с новой версией kubelet. FlexVolume объявлен устаревшим с Kubernetes 1.23, и после обновления до 1.26+ драйверы могут перестать работать.

Диагностика:

kubectl describe pod <pod-name> -n <namespace>

В выводе ищите строку MountVolume.SetUp failed for volume. Если упоминается FlexVolume - мигрируйте на CSI-драйвер. Для SMB-томов Windows используйте smb.csi.k8s.io.

Для CSI-драйверов проблема обычно в несовместимости версии плагина с новой версией Kubernetes. Проверьте версию CSI-драйвера:

kubectl get csidrivers

Обновите манифесты CSI-плагина до версии, совместимой с вашим релизом Kubernetes. Если PVC не монтируется даже после обновления драйвера, удалите и пересоздайте PVC (данные на бэкенде хранения при этом сохраняются):

kubectl delete pvc <pvc-name> -n <namespace>
kubectl apply -f pvc.yaml

Сброс настроек сети GMSA после обновления

Group Managed Service Accounts (GMSA) позволяют Windows-подам аутентифицироваться в домене Active Directory без хранения паролей. После обновления kubelet или ContainerD спецификации GMSA могут сброситься, и поды теряют сетевую идентификацию.

Симптом: под запускается, но не может обратиться к доменным ресурсам, в логах - ошибки аутентификации Logon failure: unknown user name or bad password.

Диагностика:

kubectl describe pod <pod-name> -n <namespace> | grep -A5 GMSA

Если секция windowsOptions.gmsaCredentialSpec пуста или содержит неверный путь - спецификация повреждена. Перегенерируйте Credential Spec на Windows-ноде через PowerShell:

Install-Module -Name CredentialSpec -Force
New-CredentialSpec -AccountName WebApp01 -Domain contoso.com

Полученный JSON сохраните в Secret и обновите манифест пода. После пересоздания пода GMSA восстановится. Для предотвращения повторения проблемы храните Credential Spec в Secret кластера, а не в локальном файле ноды.

Если вы работаете с деплойментами в production-среде, пригодится руководство по Kubernetes Deployment с готовыми манифестами и настройкой проб.

Проверка успешности обновления и откат при необходимости

Критерии успешного обновления: все ноды в статусе Ready, версии control-plane и worker-нод совпадают, тестовые поды запускаются и завершаются без ошибок. Выполните финальную проверку:

kubectl get nodes -o custom-columns=NAME:.metadata.name,VERSION:.status.nodeInfo.kubeletVersion,OS:.status.nodeInfo.operatingSystem
kubectl run test-pod --image=mcr.microsoft.com/windows/servercore:ltsc2022 --restart=Never -- powershell "Write-Host 'OK'"
kubectl logs test-pod && kubectl delete pod test-pod

Мониторинг логов kubelet и ContainerD на Windows-нодах за последние 30 минут:

Get-EventLog -LogName Application -Source kubelet -After (Get-Date).AddMinutes(-30)
Get-EventLog -LogName Application -Source containerd -After (Get-Date).AddMinutes(-30)

Если обновление прошло неудачно, порядок отката зависит от компонента. Для control-plane восстановите etcd из снапшота:

ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-20260806.db \
  --data-dir /var/lib/etcd-backup \
  --name <node-name> \
  --initial-cluster <node-name>=https://<ip>:2380 \
  --initial-advertise-peer-urls https://<ip>:2380

Затем перезапустите etcd с восстановленными данными и повторите kubeadm init с флагом --ignore-preflight-errors=DirAvailable. Для Windows-нод откат проще: остановите службы, замените бинарники kubelet/kube-proxy на старые версии, восстановите конфигурацию ContainerD из резервной копии и запустите службы заново. Нода автоматически переподключится к кластеру со старой версией.

Для минимизации простоев при будущих обновлениях настройте стратегию RollingUpdate с корректными maxSurge и maxUnavailable. Это позволит обновлять поды без прерывания обслуживания, даже при drain нод.

Поделиться:
Сохранить гайд? В закладки браузера