Сейчас контейнеризация и Kubernetes в частности — стандарт де-факто для запуска приложений «в бою». И запустить-то приложение в «кубе» несложно, но как всегда есть нюанс и не один. Обсудим, что нужно разработчику и админу учесть и сделать для того, чтобы приложение работало быстро и надёжно, не требуя к себе особого внимания. Например, посмотрим, как работают requests и limits на ресурсы, чем должны отличаться liveness и readiness пробы, и на что следует обращать внимание в мониторинге и так далее.
6. Марсианский Open Source
Yabeda: Ruby application instrum
entation fram
ework Lefthook: git hooks m
anager AnyCable: Polyglot replacem
ent for ActionCable server PostCS S : A tool for transform
ing CS S with JavaS cript
Im
gproxy: Fast and secure standalone server for
resizing and converting rem
ote im
ages
Logux: Client-server com
m
unication fram
ework based on
Optim
istic UI, CRDT, and log
Overm
ind: Process m
anager for Procfile-based
applications and tm
ux
И многие другие на evilmartians.com/oss
9. Зачем разработчику знать Kubernetes?
TL;DR: Чтобы быстрее деплоить новые фичи самим и не ждать админов/девопсов.
Kubernets’а бояться — в деплой не ходить от марсианского SRE.
Кирилл Кузнецов -
Кирилл Кузнецов - …
…
Вечерняя школа Kubernetes для разработчиков от Slurm.io
Урок 1: Введение в
Урок 1: Введение в …
…
10. Что такое Kubernetes…
Кластерная операционная система для деплоя приложений
Абстрагирует приложение от нижележащего железа/облаков*
Декларативная конфигурация и встроенный control loop
Использует (Docker-)контейнеры для запуска приложений…
…и свои абстракции для их оркестрации и запуска
* https://buttondown.email/nelhage/archive/two-reasons-kubernetes-is-so-complex/
11. …и из чего он состоит
Источник: Kubernets’а бояться — в деплой не ходить (слайды)
12. Pod
минимальная и главная единица в k8s
— «атом» ⚛️
логически неделимая группа
контейнеров (но обычно 1 основной)
запускаются вместе на одной машине
делят между собой localhost и сеть
есть внутрикластерный IP-адрес
с точки зрения приложения — как
будто отдельный сервер
Документация:
kubernetes.io/docs/concepts/workloads/pods
Картинка: kubernetes.io/docs/tutorials/kubernetes-
basics/explore/explore-intro
13. Service
Абстракция для логической
группировки pod’ов
Service discovery — есть
внутрикластерное DNS-имя
Балансируют трафик между своими
подами (round robin)
Реализованы как набор правил
iptables
Позволяет нам масштабировать
приложения горизонтально
Документация:
kubernetes.io/docs/concepts/services-
networking/service
Картинка: kubernetes.io/docs/tutorials/kubernetes-
basics/expose/expose-intro
15. Kubernetes health probes
У каждого отдельного контейнера внутри каждого пода:
liveness
Контейнер убивается и перезапускается, если он не отвечает на «ты жив?».
readiness
Под исключается из балансировки трафика через сервис, если не отвечает на
«ну что, готов?» и включается обратно, когда отвечает утвердительно.
startup (k8s 1.20+)
Позволяет отсрочить начало liveness и readiness проверок для
долгозапускающихся приложений
Важно: и liveness и readiness выполняются параллельно всё время жизни пода.
https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
18. Очереди запросов
Запросы ждут свободного воркера/бэкенда в Nginx или апп-сервере.
Картинка: https://railsautoscale.com/request-queue-time/
19. Приходит нагрузка 🏋️
1. Медленные запросы попадают на один под и «забивают» его
2. «Забитый» контейнер в поде перестаёт отвечать на liveness 🥀
3. Kubernetes убивает контейнер 💀
4. И тут же запускает его заново, но это занимает какое-то время… ⌚
5. На время перезапуска на другие поды приходит больше запросов.
6. GOTO 1 🤡
Неправильно настроенная liveness-проба под нагрузкой убьёт
приложение, под за подом!
21. Что же делать?
Пустить liveness пробу в обход!
port: 8080 # ← другой порт
containers:
- name: app
livenessProbe:
httpGet:
path: /health
timeoutSeconds: 3
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 80
timeoutSeconds: 3
periodSeconds: 10
Картинка: behance.net/gallery/35173039/Stickers-for-
another-one-IT-conference-(DUMP2016)
22. Healthcheck’и: итого
1. Liveness ходит через «чёрный ход»
Поднимите listener на отдельном порту, куда будет ходить только проба.
Kubernetes не должен прибивать ваши поды под нагрузкой!
2. Readiness ходит вместе с клиентскими запросами
Позвольте «забитому» поду выйти из балансировки и «остыть».
Таймаут нужно подобрать эмпирически, он не должен быть слишком мал.
Следите за наличием неготовых подов в мониторинге!
Мораль: делайте стресс-тесты!
23. Следите за очередью запросов!
Время ожидания запросов в очереди — это главная метрика, которая показывает,
что приложение «на пределе». Выведите её себе в мониторинг.
Если она ощутимо больше 0 — надо скейлиться вверх (в Kubernetes есть
Horizontal Pod Autoscaler)
Если она всегда строго 0 — можно подумать о скейлинге вниз.
Следите за USE и RED метриками, когда дело касается производительности!
Utilization: количество свободных воркера
Saturation: время ожидания свободного воркера (95p)
Errors: процент ошибок при обработке запросов
Duration: время обработки запроса (95p)
USE method: https://www.brendangregg.com/usemethod.html
RED method: https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/
24. А как масштабироваться-то?
Kubernetes Horizontal Pod Autoscaler!
Разбираем автоске
Разбираем автоске…
…
Видео Слайды
Используйте USE-метрики для масштабирования!
Слайды: https://speakerdeck.com/dragonsmith/razbiraiem-avtoskieilingh-v-kubernetes
26. Requests и limits 101
Для каждого контейнера в Pod’е:
requests и limits для Pod — сумма значений его контейнеров.
requests — инструкции для планировщика k8s
limits — инструкции для ядра ОС на нодах кластера
cpu — измеряются в millicpu (тысячных долях процессорного ядра)
memory — измеряются в байтах и кратных (мебибайты, гебибайты)
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 500m
memory: 512Mi
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
27. Requests 101
Инструкции для планировщика k8s для
распределения Pod’ов на ноды:
Не используются в рантайме*
Не учитывают фактическое
потребление*, только requests других
подов
requests:
cpu: 200m
memory: 256Mi
resources:
limits:
cpu: 500m
memory: 512Mi
* Используются при настройке OOM, но про это дальше Картинка: Илья Черепанов, внутренняя школа k8s
28. Limits 101
Реализуются ядром ОС на нодах:
cpu настраивает троттлинг CPU
memory настраивает Out of Memory
Killer
limits:
cpu: 400m
memory: 512Mi
resources:
requests:
cpu: 200m
memory: 256Mi
29. Так, что там за milliCPU ещё?
В случае limits настраивает CPU throttling — долю
процессорного времени, которое можно использовать в
течение 100мс.
Админы, настройте алерт CPUThrottlingHigh !
Не указывайте дробные CPU limits для контейнеров, где важна скорость ответа!
` `
cpu: 400m
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
memory: 512Mi
Подробнее: https://engineering.indeedblog.com/blog/2019/12/unthrottled-fixing-cpu-limits-in-the-cloud/
30. Утилизируем ядра
Процесс на языках с GIL (Ruby, Python) не может
утилизировать процессорное ядро целиком!
Максимум на 30-50%.
Используйте и процессы и потоки:
Запускайте 2-4 рабочих процесса на
контейнер (работает CoW 🐮)
По 4-6 потоков в каждом
➕Улучшается утилизация воркеров за счёт
раздачи запросов простаивающим воркерам.
Подробнее: https://www.speedshop.co/2017/10/12/appserver.html
31. Requests × Limits = QoS
В различных сочетаниях реквестов и лимитов поведение контейнера может
меняться драматично:
1. Guaranteed — requests = limits
гарантированно выдаётся CPU
убиваются по OOM последними
2. Burstable — requests ≠ limits
могут использовать CPU больше запрошенного
убиваются после BestEffort, в порядке «жадности»
3. BestEffort — нет ни requests ни limits
CPU выдаётся в последнюю очередь
Первыми убиваются OOM-киллером
Всегда указывайте и requests и limits!
` `
` `
` `
Подробнее: Управление ресурсами в Kubernetes — habr.com/ru/company/flant/blog/459326/