Економимо на хмарних витратах Kubernetes на AWS

Переклад статті підготовлений напередодні старту курсу "Інфраструктурна платформа на основі Kubernetes".

Економимо на хмарних витратах Kubernetes на AWS

Як заощадити на хмарних витратах під час роботи з Kubernetes? Єдиного правильного рішення не існує, але в цій статті описано кілька інструментів, які допоможуть вам ефективніше керувати ресурсами та скоротити витрати на хмарні обчислення.

Я написав цю статтю з оглядом на Kubernetes для AWS, але вона буде застосовна (майже) так само і для інших хмарних провайдерів. Я припускаю, що ваш кластер(и) вже має налаштоване автоматичне масштабування (cluster-autoscaler). Видалення ресурсів та зменшення масштабу розгортання дозволить заощадити лише в тому випадку, якщо це також скоротить ваш парк робочих вузлів (EC2 інстансів).

У цій статті будуть розглянуті:

  • очищення ресурсів, що не використовуються (kube-janitor)
  • зменшення масштабування в неробочий час (kube-downscaler)
  • використання горизонтального автомасштабування (HPA),
  • зменшення надлишкового резервування ресурсів (kube-resource-report, VPA)
  • використання Spot інстансів

Очищення ресурсів, що не використовуються

Робота в середовищі, що швидко змінюється, — це здорово. Ми хочемо, щоб технічні організації прискорювалися. Швидша доставка програмного забезпечення також означає більше PR-розгортань, середовищ попереднього перегляду, прототипів та аналітичних рішень. Все, що розвертається на Kubernetes. Хто має час, щоб чистити тестові розгортання вручну? Легко забути про видалення експерименту тижневої давності. Рахунок за хмару зрештою зростатиме через те, що ми забули закрити:

Економимо на хмарних витратах Kubernetes на AWS

(Хеннінг Джейкобс:
Жиза:
(цитує) Корі Куїнн:
Міф: Ваш AWS рахунок – це функція, залежно від кількості ваших користувачів.
Факт: Ваш AWS рахунок – це функція, залежно від кількості ваших інженерів.

Іван Курносов (у відповідь):
Справжній факт: Ваш AWS рахунок — це функція, залежно від кількості речей, які ви забули відключити/видалити.)

Kubernetes Janitor (Kube-janitor) допомагає очистити ваш кластер. Конфігурація janitor є гнучкою як для глобального, так і для локального використання:

  • Загальні правила для кластера можуть визначати максимальний час життя (TTL — time-to-live) для PR/тестових розгортань.
  • Окремі ресурси можуть бути анотовані за допомогою janitor/ttl, наприклад для автоматичного видалення spike/прототипу через 7 днів.

Загальні правила визначаються в файлі YAML. Його шлях передається через параметр --rules-file у kube-janitor. Ось приклад правила для видалення всіх просторів імен з -pr- в імені за два дні:

- id: cleanup-resources-from-pull-requests
  resources:
    - namespaces
  jmespath: "contains(metadata.name, '-pr-')"
  ttl: 2d

Наступний приклад регламентує використання мітки application на Deployment і StatefulSet подах для всіх нових Deployments/StatefulSet в 2020 році, але в той же час дозволяє виконання тестів без цієї мітки протягом тижня:

- id: require-application-label
  # удалить deployments и statefulsets без метки "application"
  resources:
    - deployments
    - statefulsets
  # см. http://jmespath.org/specification.html
  jmespath: "!(spec.template.metadata.labels.application) && metadata.creationTimestamp > '2020-01-01'"
  ttl: 7d

Запуск обмеженого часу демо протягом 30 хвилин у кластері, де працює kube-janitor:

kubectl run nginx-demo --image=nginx
kubectl annotate deploy nginx-demo janitor/ttl=30m

Ще одним джерелом зростаючих витрат є постійні томи (AWS EBS). При видаленні Kubernetes StatefulSet не видаляються його постійні томи (PVC - PersistentVolumeClaim). Невикористані обсяги EBS можуть легко призвести до витрат у сотні доларів на місяць. Kubernetes Janitor має функцію очищення невикористаних PVC. Наприклад, це правило видаляє всі PVC, які не змонтовані модулем і на які не посилається StatefulSet або CronJob:

# удалить все PVC, которые не смонтированы и на которые не ссылаются StatefulSets
- id: remove-unused-pvcs
  resources:
  - persistentvolumeclaims
  jmespath: "_context.pvc_is_not_mounted && _context.pvc_is_not_referenced"
  ttl: 24h

Kubernetes Janitor може допомогти вам зберегти ваш кластер у «чистоті» і запобігти повільним накопиченням витрат на хмарні обчислення. За інструкціями з розгортання та налаштування дотримуйтесь README kube-janitor.

Зменшення масштабування у неробочий час

Тестові та проміжні системи зазвичай потрібні для роботи тільки в робочий час. Деякі виробничі програми, такі як бек-офіс / інструменти адміністратора, також вимагають лише обмеженої доступності та можуть бути відключені вночі.

Kubernetes Downscaler (kube-downscaler) дозволяє користувачам та операторам зменшувати масштаб системи у неробочий час. Deployments і StatefulSets можна масштабувати до нульових реплік. CronJobs можуть бути припинені. Kubernetes Downscaler налаштовується для всього кластера, одного чи кількох просторів імен чи окремих ресурсів. Можна встановити або «час простою», або навпаки «час роботи». Наприклад, щоб максимально зменшити масштабування протягом ночі та вихідних:

image: hjacobs/kube-downscaler:20.4.3
args:
  - --interval=30
  # не отключать компоненты инфраструктуры
  - --exclude-namespaces=kube-system,infra
  # не отключать kube-downscaler, а также оставить Postgres Operator, чтобы исключенными БД можно было управлять
  - --exclude-deployments=kube-downscaler,postgres-operator
  - --default-uptime=Mon-Fri 08:00-20:00 Europe/Berlin
  - --include-resources=deployments,statefulsets,stacks,cronjobs
  - --deployment-time-annotation=deployment-time

Ось графік масштабування робочих вузлів кластера у вихідні дні:

Економимо на хмарних витратах Kubernetes на AWS

Зменшення масштабу з ~13 до 4 робочих вузлів, безумовно, дає відчутну різницю в рахунку AWS.

Але що якщо мені потрібно працювати під час простою кластера? Певні розгортання можна виключити назавжди з масштабування, додавши інструкцію downscaler/exclude: true. Розгортання можуть бути тимчасово виключені за допомогою анотації downscaler/exclude-until з абсолютним таймстемпом у форматі РРРР-ММ-ДД ЧЧ: ММ (UTC). При необхідності весь кластер може бути масштабований назад шляхом розгортання пода з анотацією. downscaler/force-uptimeнаприклад, шляхом запуску nginx болванки:

kubectl run scale-up --image=nginx
kubectl annotate deploy scale-up janitor/ttl=1h # удалить развертывание через час
kubectl annotate pod $(kubectl get pod -l run=scale-up -o jsonpath="{.items[0].metadata.name}") downscaler/force-uptime=true

дивіться README kube-downscaler, якщо вас цікавить інструкція з розгортання та додаткові опції.

Використовуйте горизонтальне автомасштабування

Багато програм/сервісів мають справу з динамічною схемою завантаження: іноді їх модулі простоюють, а іноді вони працюють на повну потужність. Робота з постійним парком подів, щоб упоратися з максимальним піковим навантаженням, не є економічною. Kubernetes підтримує горизонтальне автоматичне масштабування через ресурс HorizontalPodAutoscaler (HPA). Використання ЦП часто є добрим показником для масштабування:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        averageUtilization: 100
        type: Utilization

Zalando створив компонент для простого підключення метриків для масштабування: Kube Metrics Adapter (kube-metrics-adapter) – це універсальний адаптер метрик для Kubernetes, який може збирати та обслуговувати користувацькі та зовнішні метрики для горизонтального автомасштабування подів. Він підтримує масштабування на основі метриків Prometheus, черг SQS та інших налаштувань. Наприклад, щоб масштабувати розгортання для метрики користувача, представленої самим додатком у вигляді JSON в /metrics використовуйте:

apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: myapp-hpa
  annotations:
    # metric-config.<metricType>.<metricName>.<collectorName>/<configKey>
    metric-config.pods.requests-per-second.json-path/json-key: "$.http_server.rps"
    metric-config.pods.requests-per-second.json-path/path: /metrics
    metric-config.pods.requests-per-second.json-path/port: "9090"
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myapp
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Pods
    pods:
      metric:
        name: requests-per-second
      target:
        averageValue: 1k
        type: AverageValue

Налаштування горизонтального автомасштабування за допомогою HPA має бути однією з стандартних дій для підвищення ефективності для служб без урахування стану. Spotify має презентацію з їхнім досвідом і рекомендаціями для HPA: масштабуйте свої розгортання, а не свій гаманець.

Зменшення надлишкового резервування ресурсів

Робочі навантаження Kubernetes визначають їх потреби в ЦП/пам'яті через запити ресурсів (resource requests). Ресурси ЦП вимірюються у віртуальних ядрах або частіше в "мілікорах" (millicores), наприклад, 500m має на увазі 50% vCPU. Ресурси пам'яті вимірюються в байтах і можна використовувати звичайні суфікси, наприклад, 500Mi, що означає 500 мегабайт. Запити ресурсів блокують обсяг на робочих вузлах, тобто модуль із запитом ЦП в 1000m на вузлі з 4 віртуальними ЦП залишить тільки 3 віртуальних ЦП доступними для інших модулів. [1]

Slack (надлишок резерву) — це різниця між запитуваними ресурсами та реальним використанням. Наприклад, під, який запитує 2 GiB пам'яті, але використовує тільки 200 MiB, має ~ 1,8 GiB "надлишкової" пам'яті. Надлишок коштує грошей. Можна грубо оцінити, що 1 GiB надмірної пам'яті коштує 10 доларів на місяць. [2]

Kubernetes Resource Report (kube-resource-report) відображає зайві резерви і допоможе вам визначити потенціал економії:

Економимо на хмарних витратах Kubernetes на AWS

Kubernetes Resource Report показує надлишок, агрегований додатком та командою. Це дозволяє знайти місця, де запити ресурсів можуть бути знижені. Згенерований HTML звіт надає лише снапшот використання ресурсу. Ви повинні дивитися використання процесора/пам'яті з часом, щоб визначити адекватні запити ресурсів. Ось діаграма Grafana для «типової» служби з великим навантаженням на ЦП: всі поди використовують значно менше 3 запитаних ядер ЦП:

Економимо на хмарних витратах Kubernetes на AWS

Скорочення запиту ЦП з 3000m до ~400m вивільняє ресурси інших робочих навантажень і дозволяє зменшити кластер.

"Середнє використання ЦП EC2 інстансів часто коливається в діапазоні однозначних відсотків", - пише Корі Куїн. У той час як для EC2 оцінка правильного розміру може бути поганим рішенням, зміна деяких запитів ресурсів Kubernetes у YAML файлі виконується легко і може принести величезну економію.

Але чи дійсно ми хочемо, щоб люди змінювали значення у файлах YAML? Ні, машини можуть зробити це набагато краще! Kubernetes Вертикальний модуль автоматичного масштабування (VPA) саме цим і займається: адаптує запити ресурсів та обмеження відповідно до робочого навантаження. Ось приклад графіка запитів ЦП Prometheus (тонка синя лінія), адаптованих VPA з часом:

Економимо на хмарних витратах Kubernetes на AWS

Zalando використовує VPA у всіх своїх кластерах для компонентів інфраструктури Некритичні програми також можуть використовувати VPA.

жовтець золотистий від Fairwind — це інструмент, який створює VPA для кожного розгортання у просторі імен, а потім відображає рекомендацію VPA на своїй інформаційній панелі. Він може допомогти розробникам встановити правильні запити процесора/пам'яті для своїх програм:

Економимо на хмарних витратах Kubernetes на AWS

Я написав невеликий блогпост про VPA у 2019 році, і нещодавно CNCF End User Community обговорювалося питання VPA.

Використання EC2 Spot інстансів

Нарешті, що не менш важливо, витрати AWS EC2 можна знизити, використовуючи Spot інстанси як робочі вузли Kubernetes [3]. Spot інстанси доступні зі знижкою до 90% порівняно з цінами на вимогу. Запуск Kubernetes на EC2 Spot — хороша комбінація: вам потрібно вказати кілька різних типів інстансів для більш високої доступності, тобто ви можете отримати більший вузол за ту ж чи нижчу ціну, а збільшена ємність може бути використана контейнерними робочими навантаженнями Kubernetes.

Як запустити Kubernetes на EC2 Spot? Існує кілька варіантів: використовувати сторонній сервіс, такий як SpotInst (тепер він називається «Spot», не питайте мене чому), або просто додати Spot AutoScalingGroup (ASG) у ваш кластер. Наприклад, фрагмент CloudFormation для «оптимізованої за ємністю» Spot ASG з кількома типами екземплярів:

MySpotAutoScalingGroup:
 Properties:
   HealthCheckGracePeriod: 300
   HealthCheckType: EC2
   MixedInstancesPolicy:
     InstancesDistribution:
       OnDemandPercentageAboveBaseCapacity: 0
       SpotAllocationStrategy: capacity-optimized
     LaunchTemplate:
       LaunchTemplateSpecification:
         LaunchTemplateId: !Ref LaunchTemplate
         Version: !GetAtt LaunchTemplate.LatestVersionNumber
       Overrides:
         - InstanceType: "m4.2xlarge"
         - InstanceType: "m4.4xlarge"
         - InstanceType: "m5.2xlarge"
         - InstanceType: "m5.4xlarge"
         - InstanceType: "r4.2xlarge"
         - InstanceType: "r4.4xlarge"
   LaunchTemplate:
     LaunchTemplateId: !Ref LaunchTemplate
     Version: !GetAtt LaunchTemplate.LatestVersionNumber
   MinSize: 0
   MaxSize: 100
   Tags:
   - Key: k8s.io/cluster-autoscaler/node-template/label/aws.amazon.com/spot
     PropagateAtLaunch: true
     Value: "true"

Деякі зауваження щодо використання Spot з Kubernetes:

  • Вам потрібно обробляти завершення Spot, наприклад, шляхом зливу вузла на зупинці інстансу
  • Zalando використовує вилка офіційного автомасштабування кластера з пріоритетами пулу вузлів.
  • Вузли Spot можна змусити приймати “реєстрацію” робочих навантажень для запуску в Spot

Резюме

Я сподіваюся, що ви знайдете деякі з представлених інструментів корисними для скорочення вашого рахунку за хмарні обчислення. Ви можете знайти більшу частину вмісту статті також у моєму виступі на DevOps Gathering 2019 на YouTube та у вигляді слайдів.

Які ваші найкращі практики для економії хмарних витрат на Kubernetes? Будь ласка, дайте знати у Twitter (@try_except_).

[1] Фактично, менше 3 віртуальних ЦП залишаться придатними для використання, оскільки пропускна здатність вузла зменшується за рахунок зарезервованих системних ресурсів. Kubernetes розрізняє фізичну ємність вузла та «виділяються» ресурси (Node Allocatable).

[2] Приклад розрахунку: один екземпляр m5.large із 8 GiB пам'яті становить ~84 долари США на місяць (eu-central-1, On-Demand), тобто. блокування 1/8 вузла становить приблизно 10 доларів США на місяць.

[3] Є ще багато способів зменшити ваш EC2 рахунок, наприклад, зарезервовані екземпляри, план заощаджень і т. д. — я не висвітлюватиму ці теми тут, але ви обов'язково повинні про них дізнатися!

Дізнатись детальніше про курс.

Джерело: habr.com

Додати коментар або відгук