Всем привет! Меня зовут Маша и я являюсь ментором и преподавателем на курсе «Инфраструктурная платформа на основе Kubernetes». Задачей курса стоит не просто знакомство с Kubernetes как с системой для оркестрации, но также и построение экосистемы вокруг него. Начиная от выбора райнтайма для контейнера и заканчивая тем, как можно протестировать нашу систему на прочность — так называемый Chaos Engineering. Так как в Kubernetes достаточно много неочевидных и порой даже скрытых возможностей, я хотела бы познакомить с моим личным топ-5 интересных фич.
1. Автообновление configmap
Если кто-то из вас уже встречался с Kubernetes, то вы наверняка знаете о таком объекте, как конфигмап (Configmap). На самом деле цель его достаточно простая — хранение конфигурации. Неважно, отдельные это переменные или целые файлы. Для Kubernetes конфигмап может обновляться независимо от приложения, использующего его, при этом, приложению в большинстве случаев важно получить самую последнюю версию конфигурации. Автоматическое обновление конфигмап возможно получить только в двух случаях:
- Приложение умеет ходить в Kubernetes API и постоянно отслеживать изменения и забирать свежую конфигурацию
- Вы смонтировали конфигмап как вольюм и тогда за автообновление будет отвечать kubelet. Минус этого способа — задержка между обновлениями может быть критична и она определяется несколькими параметрами (подробнее по ссылке выше).
Но все не так плохо! Если вы используете helm для шаблонизации и деплоя ваших приложений, то можете воспользоваться воркэраундом из best-practice. Добавление аннотации, которая вычисляет чексумму указанных файлов приведет к обновлению деплоймента. Ну а если хелм не ваш выбор, то можно попробовать Reloader, который позволяет более гибко управлять обновлением секретов и конфигмап и их зависимостью от объектов с приложением — Deployment, ReplicaSet и тд.
2. Квотирование ресурсов
Администрирование Kubernetes само по себе не самая тривиальная задача, особенно, если кластер разрастается и им пользуется большое количество различных команд. Для того, чтобы контролировать потребление ресурсов, есть два объекта: ResourceQuota и LimitRange.
Используя ResourceQuota мы можем ограничить суммарное количество ресурсов, которое могут запросить все объекты в немспейсе (изолированное виртуальное окружение в рамках кластера. Это может выглядеть так:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
Здесь мы ограничиваем количество CPU, памяти и объектов типа Pod на немспейс. ResourceQuota поддерживает селекторы, поэтому мы можем гибко настроить политику для работы с различными типа приложений, например по их важности.
LimitRange помогает отслеживать выставление значений реквестов/лимитов по ресурсам для всех подов в немспейсе.
limits:
- default:
cpu: 1
defaultRequest:
cpu: 0.5
type: Container
В примере мы задаем значение реквест/лимит по CPU по умолчанию для всех контейнеров в немспейсе.
3. Шедулим немспейсы на ноды!
Как я уже упоминала, немспейс — это виртуальное окружение, которое есть только в виде ключа в ETCD (key-value база данных для Kubernetes) и определяет принадлежность объекта к тому или иному окружению. Но если мы хотим поды из некоторых немспейсов зашедулить на конкретный пул нод (например, чтобы изолировать нагрузку), возникают проблемы. Если мы используем nodeSelector / affinity / anti-affinity / tolerations — все это добавляет большое количество неудобств с точки зрения шаблонизации и поддержки конфигурации. Так как для всех этих опций нужна дополнительная конфигурация в манифесте Deployment / ReplicaSet и т.д.
Но если покопаться в документации Kubernetes, можно найти фичу под названием PodNodeSelector, которая позволяет отметить немспейс доступным для шедулинга только на ноды с определенным лейблом.
4. Бесшовно обновляем кластер
Процесс обновления кластера Kubernetes включает несколько этапов. И этапом 0 я бы поставила выставление PodDistruptionBudget на все объекты в кластере.
Зачем это нужно? Все просто — в процессе обновления кластера вам необходимо очистить ноду от находящихся на ней подах. Для того, чтобы быть уверенным, что вы не удаляете сразу 2 из 2 реплики вашего приложения, можно сконфигурировать PodDistruptionBudget и тогда уже Kubernetes будет отслеживать этот момент в процессе дрейнинга (очищения) ноды.
Есть несколько вариантов конфигурирования — исходя из минимального количества доступых подов или из максимального количества недоступных подов. Примеры:
minAvailable: 2
selector:
matchLabels:
app: zookeeper
maxUnavailable: 1
selector:
matchLabels:
app: zookeeper
5. Шедулинг v2.0
Про шедулинг можно говорить очень долго, да и возможностей для различных сценариев в Kubernetes уже предостаточно. Помимо простых возможностей по деплою подов только на разрешенные ноды, мы можем создавать так называемые топологии. Например, размазывать наши поды по AZ (availability-zones) или по дацацентрам или запретить размещать некоторые приложения на одних нодах. Со всем этим нам поможет affinity / anti-affinity.
Вот как это может выглядеть:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- store
topologyKey: "kubernetes.io/hostname"
В этом примере мы хотим, чтобы поды с нашим стораджем располагались обязательно (requiredDuringSchedulingIgnoredDuringExecution) на разных нодах(topologyKey).
По теме шедулинга рекомендую к ознакомлению официальную документацию.