Kubernetes 1.14: Windows Node в production - запустили .NET-легаси без изменения кода
Kubernetes 1.14 GA стабилизировал поддержку Windows-нод. Добавили Windows-ноду в гибридный кластер и запустили .NET-легаси в Windows-контейнере - сеть пришлось настраивать отдельно.
Kubernetes 1.14 GA - стабильная поддержка Windows-нод и улучшения в области persistent volumes
Kubernetes 1.14 вышел 25 марта и принёс несколько заметных вещей. Но нас в этом релизе больше всего интересовала одна: поддержка Windows-нод переехала из beta в GA. Официально стабильная. Можно в production.
У нас как раз был повод проверить.
Контекст: .NET-легаси в гибридном кластере
В одном из managed-проектов есть старый .NET-сервис. Не .NET Core - именно .NET Framework 4.7, Windows-only, переписывать его в обозримой перспективе никто не собирался. Остальная инфраструктура проекта уже в Kubernetes на Linux-нодах. Сам сервис жил на отдельной Windows VM и доставлялся туда по старинке - скриптами, руками, иногда молитвами.
Хотелось унифицировать. Раз уж Kubernetes 1.14 объявил Windows GA - время попробовать добавить Windows-ноду в кластер и загнать этот сервис в контейнер.
Спойлер: запустили. Но путь был не совсем прямым.
Что изменилось в 1.14 для Windows
До 1.14 поддержка Windows-нод была в beta с кучей оговорок. В 1.14 её подняли до GA - это означает стабильный API и гарантию совместимости в рамках жизненного цикла версии. Конкретные улучшения:
- Runcontainerimage и связанные операции kubelet теперь работают стабильно на Windows без экспериментальных флагов.
- Улучшена поддержка persistent volumes - в частности, флаги монтирования, которые раньше работали по-разному на Windows и Linux, выровняли поведение.
- Storage plugin subPath стал корректно работать с Windows-путями.
Плюс в этом же релизе подтянули kubectl - kubectl diff наконец стал первоклассным инструментом, а не экспериментальным флагом. Мелочь, но приятная.
Как добавляли Windows-ноду
Кластер у нас на kubeadm. Добавление Windows-ноды - это не kubeadm join по умолчанию, там есть своя процедура. Грубо:
- Windows Server 2019 - минимальное требование для Windows-контейнеров в Kubernetes. Мы подняли ноду на WS2019 Core, благо у нас уже был опыт с этим.
- kubelet и kube-proxy для Windows - скачиваются отдельно, устанавливаются как Windows-сервисы через скрипт
PrepareNode.ps1из официальных материалов SIG Windows. - CNI-плагин для Windows - и вот здесь начинается самое интересное.
Сеть: отдельная история
Сетевой оверлей на Windows работает иначе, чем на Linux. Flannel с VXLAN-бэкендом, который стоит у нас на Linux-нодах, на Windows не поддерживается. Вместо этого Windows использует host-gw режим или WinOverlay - VXLAN-реализацию через специфичный для Windows HNS (Host Networking Service).
Мы пошли по пути host-gw для Windows-нод и потратили на это заметную часть времени. Нюансы:
- Flannel на Windows нужен отдельный DaemonSet с образом под Windows. Образ отдельный -
flannel:v0.11.0-windowsamd64. - HNS-сеть при первом запуске создаётся с задержкой и может выглядеть как зависший контейнер. Первые несколько минут нервные.
- Маршруты между Linux- и Windows-нодами в
host-gwрежиме требуют что все ноды находились в одной L2-сети. В нашем случае - да, но это надо учитывать при планировании топологии.
DNS внутри Pod-ов на Windows-ноде работает через kube-dns/CoreDNS так же, как на Linux - здесь без сюрпризов.
Сервис в контейнере
Сам .NET-сервис мы завернули в Windows-контейнер на базе mcr.microsoft.com/windows/servercore:ltsc2019. Dockerfile простой: скопировать собранные DLL-ки, прописать entrypoint. Код не трогали вообще - сервис написан как console app, слушает порт, читает конфиг из переменных окружения. Это и спасло.
nodeSelector в манифесте Deployment:
nodeSelector:
kubernetes.io/os: windows
Без этого Kubernetes попытается разместить Pod на Linux-ноде и получит ошибку несовместимости образа.
Pod поднялся, сервис ответил на первый запрос. Момент, честно говоря, неожиданно приятный - когда что-то такое большое просто берёт и работает.
Что не идеально
Образы большие. Windows Server Core - это несколько гигабайт базового образа. Pull на новой ноде занимает время, которое на Linux измеряется секундами, а тут - минутами. Нано-сервер был бы меньше, но наш сервис требует полного Server Core.
Мониторинг. cAdvisor на Linux-нодах работает с containerd. На Windows-ноде ситуация другая - метрики контейнеров идут через другие механизмы, стандартный cAdvisor там работает не полноценно. Пришлось смотреть в сторону кастомных метрик.
Обновление. Rolling update работает, но медленнее - из-за времени pull образа. Нужно учитывать в minReadySeconds и timeout.
Итого
Гибридный кластер с Linux- и Windows-нодами работает. .NET-легаси в контейнере запускается и отвечает на запросы без каких-либо изменений в коде самого сервиса. Сетевой оверлей потребовал отдельной настройки и разбора того, как HNS работает с Flannel - но это решаемо.
Для нас это значит: Windows-зависимые компоненты можно постепенно включать в общую операционную модель кластера, а не держать их на отдельных VM с ручным управлением. Не всё одинаково гладко по сравнению с Linux, но разрыв уже не катастрофический.
Эксплуатируем дальше, смотрим как будет вести себя под реальной нагрузкой.
- containerd 1.2 и CRI: перевели кластер с docker shim - стало тише и быстрее · 31 января 2019
- Windows Server 2019 Core в продакшне: меньше GUI - меньше боли · 7 февраля 2019