Ключевые ограничения 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 превращается в ручное восстановление из манифестов, что занимает часы.
- Снапшот 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 - Выгрузка манифестов: экспортируйте все ресурсы через
kubectl get all -A -o yaml > cluster-backup.yaml. Отдельно сохраните ConfigMap, Secret и PVC. - Снапшоты дисков Windows-нод: на уровне облака или гипервизора сделайте снапшоты виртуальных машин. При локальном развёртывании используйте Windows Server Backup или
wbadmin. - Проверка совместимости: сверьте версии Kubernetes и Windows Server по матрице. Убедитесь, что CNI-плагин (Calico, Flannel, Antrea) поддерживает целевую версию Kubernetes и имеет сборку для Windows.
- Оценка 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 wideCNI-плагин требует отдельного внимания. 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 нод.