Одновременно с ростом кластера Kubernetes растет количество ресурсов, volume и других API-объектов. Рано или поздно вы упретесь в потолок, будь то etcd
, память или процессор. Зачем подвергать себя ненужной боли и проблемам, если можно установить простые — хотя и довольно изощренные — правила? Вы можете настроить автоматизацию и мониторинг, которые будут содержать кластер в аккуратном состоянии. В статье разберемся, как избавиться от лишних нагрузок, через которые утекают ресурсы, и устаревших накопившихся объектов.
Что будет в статье:
- В чем проблема?
- Основы
- Ручная очистка
- Kube-janitor
- Мониторинг ограничений кластера
- Заключение
- От переводчиков
В чем проблема?
Ограничение количества подов. Каждый кластер Kubernetes имеет несколько основных ограничений. Первое из них — количество подов на узел, которое по документации не рекомендуется делать больше 110. При этом, если у вас достаточно мощные узлы с большим количеством памяти и CPU, вы можете увеличить это количество — возможно, даже до 500, как было протестировано на OpenShift. Но если вы достигнете этих пределов, не удивляйтесь, если что-то пойдет не так, и не только потому, что не хватает памяти или мощности процессора.
Нехватка хранилища ephemeral storage. Все запущенные поды на узле используют по крайней мере часть этого пространства для логов, кэша, рабочего пространства или emptyDir волюмов. Вы можете достичь предела довольно быстро, что приведет к вытеснению уже существующих подов, или невозможности создания новых. Запуск слишком большого количества подов на узле тоже может способствовать этой проблеме: ephemeral storage используется для образов контейнеров и их записываемых слоев. Если узел достигает предела хранилища, он становится нерабочим (на него будет применен taint), о чем вы узнаете довольно быстро. Если вы хотите узнать текущее состояние диска на узле, запустите на нем df -h /var/lib.
Лишние расходы на PVC. Схожим образом источником проблем могут стать persistent volume, особенно если вы запускаете Kubernetes в облаке и платите за каждый предоставленный PVC. Очевидно, что для экономии денег необходимо чистить неиспользуемые PVC. Содержание используемых PVC чистыми тоже важно, потому что позволяет избежать нехватки места для ваших приложений. Особенно, если вы запускаете базы данных в кластере.
Низкая производительность etcd. Еще один источник проблем — чрезмерное количество объектов, поскольку все они находятся в хранилище etcd
. По мере роста количества данных в etcd
, его производительность может начать снижаться. Этого нужно стараться не допускать всеми силами: etcd
— мозг кластера Kubernetes. Учитывая вышесказанное, чтобы упереться в etcd,
вам понадобится действительно большой кластер, как продемонстрировано в этом посте OpenAI. В то же время нет какой-то единой метрики для замера производительности etcd
, потому что она зависит от количества объектов, их размеров и частоты использования. Так что наилучшим выходом будет профилактика: простое сохранение чистоты и порядка. В противном случае вас могут ждать весьма неприятные сюрпризы.
Нарушение границ безопасности. Наконец, мусор в кластере может стать источником проблем сам по себе. Не забывайте подчищать Role Bindings и учетные записи (Service Account), когда ими никто не пользуется.
Основы
Первое, что можно решить с помощью квот — количество и размер PVC:
apiVersion: v1
kind: LimitRange
metadata:
name: pvc-limit
spec:
limits:
- type: PersistentVolumeClaim
max:
storage: 10Gi
min:
storage: 1Gi
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: pvc-quota
spec:
hard:
persistentvolumeclaims: "10"
requests.storage: "10Gi"
# сумма запрошенного хранилища в bronze storage class не может превышать 5 Гб
bronze.storageclass.storage.k8s.io/requests.storage: "5Gi"
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-count-quota
spec:
hard:
configmaps: "2"
secrets: "10"
services: "5"
count/jobs.batch: "8"
apiVersion: v1
kind: ResourceQuota
metadata:
name: ephemeral-storage-quota
spec:
hard:
requests.ephemeral-storage: 1Gi
limits.ephemeral-storage: 2Gi
Наконец, вы можете установить время жизни (TTL) для очистки кластера от объектов, которые существуют там слишком долго. Эта процедура использует TTL-контроллер, который находится в стадии бета-тестирования с версии v1.21, и в настоящее время работает только для задач, использующих поле .spec.ttlSecondsAfterFinished.
В будущем, возможно, он будет расширен на другие ресурсы, например, поды.
Ручная очистка
kubectl delete all -l some-label=some-value # Delete based on label
kubectl delete pod $(kubectl get pod -o=jsonpath='{.items[?(@.status.phase=="Succeeded")].metadata.name}') # Delete all "Succeeded" Pods
Могу посоветовать такой инструмент, как k8spurger. Он ищет неиспользуемые объекты вроде RoleBinding, ServiceAccounts, ConfigMaps и создает список ресурсов-кандидатов на удаление. Это поможет сузить круг поиска.
Kube-janitor
В разделах выше мы рассмотрели несколько вариантов простой очистки для конкретных случаев. Но лучшим решением для наведения порядка в любом кластере будет использование kube-janitor. Этот инструмент работает в вашем кластере так же, как любая другая рабочая нагрузка, и использует JSON-запросы для поиска ресурсов, которые можно удалить на основе TTL или истечения срока действия.
Для развертывания kube-janitor на вашем кластере запустите:
git clone https://codeberg.org/hjacobs/kube-janitor.git
cd kube-janitor
kubectl apply -k deploy/
Это разложит kube-janitor в default namespace и запустит его с правилами по умолчанию в пробном режиме с использованием флага —dry-run.
Перед отключением dry-run нужно установить собственные правила. Они лежат в config map kube-janitor, которая выглядит примерно так:
apiVersion: v1
kind: ConfigMap
metadata:
name: kube-janitor
namespace: default
data:
rules.yaml: |-
rules:
...
Конечно, для нас самый интересный раздел здесь — правила, rules
. Вот несколько полезных примеров, которые вы можете использовать для очистки своего кластера:
rules:
# Удаление Jobs в development namespaces после 2 дней.
- id: remove-old-jobs
resources:
- jobs
jmespath: "metadata.namespace == 'development'"
ttl: 2d
# Удаление тех подов в development namespaces, которые не в состоянии выполнения (Failed, Completed).
- id: remove-non-running-pods
resources:
- pods
jmespath: "(status.phase == 'Completed' || status.phase == 'Failed') && metadata.namespace == 'development'"
ttl: 2h
# Удаление всех PVC, которые не использует ни один под
- id: remove-unused-pvcs
resources:
- persistentvolumeclaims
jmespath: "_context.pvc_is_not_mounted"
ttl: 1d
# Удаление всех Deployments, чье имя начинается с 'test-'
- id: remove-test-deployments
resources:
- deployments
jmespath: "starts_with(metadata.name, 'test-')"
ttl: 1d
# Удаление всех ресурсов в playground namespace через неделю
- id: remove-test-deployments
resources:
- "*"
jmespath: "metadata.namespace == 'playground'"
ttl: 7d
Этот пример показывает несколько базовых вариантов настройки для очистки от временных, устаревших или неиспользуемых ресурсов. Помимо правил такого рода, можно установить абсолютные дату/время истечения срока действия для конкретных объектов.
Это можно сделать с помощью аннотаций, например:
apiVersion: v1
kind: Namespace
metadata:
annotations:
# будет удалено 18.6.2021 в полночь
janitor/expires: "2021-06-18"
name: temp
spec: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
# будет удалено 20.6.2021 в 17:30
janitor/expires: "2021-06-20T17:30:00Z"
name: nginx
spec:
replicas: 1
...
Когда закончите устанавливать правила и аннотации, вам стоит дать kube-janitor поработать какое-то время в dry-run режиме с включенными логами отладки. Это мера предосторожности, чтобы инструмент не удалил то, что удалять было не нужно.
Другими словами, не обвиняйте меня, если сотрете production волюмы из-за неправильной конфигурации и отсутствия тестирования.
Наконец, при использовании kube-janitor нужно учитывать его потребности в ресурсах. Если в кластере много объектов, ему может потребоваться больше памяти, чем выделенные по умолчанию 100 Мб. Чтобы его под не застревал в CrashLoopBackOff, я выставляю ему лимит 1 Гб.
Мониторинг ограничений кластера
Это только некоторые метрики из тех, которые вы можете использовать. Какие из них будут доступны, зависит также от ваших инструментов мониторинга, т.е. вы можете использовать какие-то специальные метрики, доступные на вашем сервисе.