Kubernetes 1.1: namespaces на практике и HPA который не дал завалить соседей
Запустили первый рабочий кластер Kubernetes для разработки: namespaces разделили dev/staging/prod, а HPA во время нагрузочного теста удержал остальные сервисы.
Kubernetes 1.1 вышел с улучшенными namespaces и горизонтальным автомасштабированием подов (HPA)
В июле мы разворачивали тестовый кластер Kubernetes 1.0 и честно написали что до продакшна ещё далеко - слишком много мест где можно обжечься. В начале ноября вышел 1.1, и именно он подтолкнул нас к тому чтобы поднять первый рабочий кластер - не лабораторный стенд, а реальную инфраструктуру для разработки нескольких команд.
Два конкретных новшества 1.1 сделали это возможным: доработанные namespaces с нормальными квотами ресурсов и Horizontal Pod Autoscaler. Без них задача «несколько команд, один кластер» выглядела как приглашение к войне за ресурсы.
Почему вообще один кластер
Логичный вопрос - зачем мучиться с мультиарендой, не проще ли дать каждой команде свой кластер?
Проще. Но у нас к тому моменту было несколько клиентских проектов на managed-инфраструктуре, и каждый из них тянул окружения dev, staging и prod. Три кластера на проект - это три набора etcd, трёх control plane нод, тройная операционная нагрузка. Умножаем на количество проектов и понимаем что это не масштабируется. Один кластер с нормальной изоляцией - разумный компромисс.
Что дали namespaces в 1.1
Namespaces были и раньше, но в 1.0 это был скорее логический тег без зубов. В 1.1 к ним добавили ResourceQuota и LimitRange - инструменты которые реально работают.
ResourceQuota на namespace - это жёсткий потолок. Мы назначили dev-неймспейсу лимит по CPU и памяти, staging получил побольше, prod - по фактической потребности плюс запас. Описывается одним манифестом:
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
cpu: "4"
memory: 8Gi
pods: "20"
LimitRange задаёт дефолтные лимиты на под - если разработчик забыл указать requests/limits, неймспейс подставляет своё. До этого под без лимитов мог занять всё что есть на ноде. Это была реальная дыра.
RBAC по неймспейсам - у 1.1 он пока базовый, но достаточный: разработчики проекта А не видят поды проекта Б и не могут в них залезть. Простая вещь, но без неё разговора о мультиарендности нет.
Разделить dev/staging/prod на уровне namespace оказалось проще чем мы ожидали. Настройка заняла вечер, после чего окружения живут на одном кластере и не знают друг о друге.
Нагрузочный тест который мог всё положить
Вот тут и появился HPA - и очень вовремя.
Одна из команд запустила нагрузочный тест staging-окружения. Инструмент тупо молотил HTTP-запросами, приложение начало отъедать ресурсы. В старой схеме это означало бы деградацию всего кластера - или кто-то вручную масштабирует реплики, или все остальные ждут пока тест закончится.
С HPA картина другая. Настроили автомасштабирование для тестируемого деплоймента:
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: staging-web
namespace: staging
spec:
scaleTargetRef:
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 8
targetCPUUtilizationPercentage: 70
Во время теста HPA поднял количество реплик с двух до шести - кластер вытянул нагрузку горизонтально. Важный момент: namespace staging имел квоту, за пределы которой HPA выйти не мог. Prod и dev при этом работали без изменений - ни деградации, ни конкуренции за ресурсы. Соседи не пострадали.
Это не магия - это просто два механизма которые работают вместе: quota держит namespace в рамках, HPA распределяет нагрузку внутри этих рамок. Элегантно.
Что пришлось решать по дороге
Без шероховатостей не обошлось.
Сеть между namespace. По умолчанию поды из разных неймспейсов видят друг друга - изоляция логическая, не сетевая. Нам это не подходило: staging не должен случайно попасть в prod-базу. Решили через NetworkPolicy - в 1.1 она экспериментальная и работает только с конкретными network плагинами. Использовали Calico, повозились с конфигурацией, в итоге сделали.
Мониторинг. kubectl get pods --all-namespaces даёт общую картину, но для нормального наблюдения нужно что-то снаружи. Подключили Heapster который в 1.1 научился агрегировать метрики по namespace - это помогло видеть потребление ресурсов по окружениям.
Persistent storage. Статефул-сервисы - базы, очереди - мы не стали тащить в кластер. Они живут отдельно, поды в кластере к ним подключаются по адресу. Это осознанный выбор: меньше риска, проще бэкапы, не нужно возиться с PersistentVolume на этом этапе.
Где мы сейчас
Кластер с разделением по namespace работает вторую неделю. Команды деплоят в dev самостоятельно, staging накатывается по пушу в ветку, prod пока руками через kubectl - автоматический деплой в прод ещё обсуждаем.
HPA включён только в staging - смотрим как ведёт себя в реальных условиях прежде чем включать в prod. ResourceQuota в prod выставили консервативно, с запасом: лучше потом поднять потолок чем разбираться почему соседний namespace упёрся в чужие лимиты.
Шишки ещё будут - кластер молодой, и первый серьёзный инцидент покажет где мы что не учли. Но пока картинка выглядит управляемее чем была.
- Kubernetes 1.0: Google объявляет оркестрацию production-ready · 1 июля 2015
- Docker Swarm 1.0: нативная кластеризация без сторонних костылей · 4 сентября 2015