Всем привет! Меня зовут Маша и я являюсь ментором и преподавателем на курсе «Инфраструктурная платформа на основе 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).

По теме шедулинга рекомендую к ознакомлению официальную документацию.