Олег Марков
Как ограничить ресурсы используя Limits в Kubernetes
Введение
В Kubernetes эффективное распределение вычислительных ресурсов между контейнерами и приложениями играет ключевую роль. Без правильных ограничений какое-то приложение может занять слишком много CPU или памяти, из-за чего другие сервисы окажутся «голодными» или даже будут завершены системой. Kubernetes предоставляет механизм для явного ограничения использования ресурсов контейнерами с помощью параметров Limits и Requests, и сегодня мы детально разберём, как именно эти ограничения на ресурсы (limits) работают, для чего они нужны, и как ими управлять.
Ограничения ресурсов в Kubernetes: основы
Что такое ресурсы в Kubernetes
В Kubernetes ресурсами обычно называют процессорное время (CPU) и оперативную память (memory), хотя возможны и другие типы ресурсов (например, GPU, storage). Каждый под или контейнер может использовать только ограниченное количество ресурсов кластера.
Requests vs Limits: в чем разница
Здесь важно понимать два понятия:
- Requests (запросы) — минимальное количество ресурса, которое Kubernetes выделит контейнеру. Если все Pods запросили больше ресурсов, чем есть в узле, новые Pods не запускаются.
- Limits (лимиты) — это жесткий предел: контейнер не сможет использовать больше установленного значения этого ресурса.
Requests и Limits могут быть разными или совпадать в зависимости от ваших целей.
Пример: почему это важно
Представьте, что в кластере запускается сервис, который иногда активно использует CPU. Без ограничений он может «съесть» весь процессор на ноде, создав лаг для остальных контейнеров. Если задать предел, вы защищаете стабильность всей системы.
Как работают limits в Kubernetes
Где задаются ограничения
Ограничения ресурсов задаются на уровне контейнеров в спецификации Pod (или Deployment, StatefulSet и так далее), в секции resources
для каждого контейнера.
Давайте посмотрим, как выглядит базовый пример
apiVersion: v1
kind: Pod
metadata:
name: nginx-limited
spec:
containers:
- name: nginx
image: nginx:latest
resources:
requests:
memory: "64Mi" # Минимум 64 MiB памяти
cpu: "250m" # Минимум 0.25 CPU
limits:
memory: "128Mi" # Не больше 128 MiB памяти
cpu: "500m" # Не больше 0.5 CPU
Комментарии поясняют, как limits и requests управляют памятью и CPU для контейнера nginx. В этом примере контейнер гарантировано получит 250 мили-CPU (0.25 CPU) и 64 мегабайта памяти, но не сможет превысить лимит в 0.5 CPU и 128 мегабайт памяти.
За что отвечают limits
- cpu — максимальное количество процессорного времени. Если контейнер пытается использовать больше, его процессы будут «замедлять».
- memory — предел оперативной памяти. Превышение этого лимита приводит к тому, что процесс убивает ядро (OOM kill).
Обратите внимание: превышение лимита CPU ведёт лишь к замедлению, а лимита памяти — к принудительному завершению.
Как Kubernetes применяет limits
Kubernetes взаимодействует с container runtime (например, Docker, containerd), чтобы установить ограничения на уровне cgroups в Linux. Система ядра следит, чтобы процессы не превышали выделенные ресурсы.
Давайте разберём это на более практическом примере.
Пример с несколькими контейнерами
apiVersion: v1
kind: Pod
metadata:
name: multi-container-limits
spec:
containers:
- name: frontend
image: frontend:latest
resources:
limits:
memory: "256Mi"
cpu: "1"
- name: backend
image: backend:latest
resources:
limits:
memory: "512Mi"
cpu: "2"
Здесь у пода два контейнера, каждый со своими независимыми лимитами.
Как считать значения resources
- CPU указывается в ядер (целые значения) или мили-CPU (
1000m
= 1 CPU,500m
= 0.5 CPU) - Память указывается в байтах (
B
), килобайтах (Ki
), мегабайтах (Mi
), гигабайтах (Gi
), и т.д.
Пример: "500Mi"
— это 500 «меби-байт», не 500 мегабайт (MB). 1 Mi = 1024^2 байта.
Что будет, если не задать limits
Если не указать limits, контейнер сможет потреблять все ресурсы ноды, что в большинстве случаев опасно! Поэтому часто рекомендуют явно задавать ограничения для всех контейнеров.
Примеры настройки limits в различных объектах
Применение limits для Deployment
Давайте создадим Deployment, где nginx ограничен по ресурсам:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-limited-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
resources:
limits:
memory: "128Mi"
cpu: "500m"
Этот пример показывает, как limits работают в типичных production-объектах Kubernetes.
Использование defaults через LimitRange
Чтобы не забывать проставлять limits для каждого контейнера, используйте LimitRange. Так можно задать лимиты по умолчанию для всего namespace.
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: dev
spec:
limits:
- default:
cpu: 500m
memory: 256Mi
defaultRequest:
cpu: 200m
memory: 128Mi
type: Container
Размещая этот объект в namespace dev
, вы добиваетесь, что все контейнеры автоматически получат значения по умолчанию, если их не указать явно.
Советы, рекомендации и подводные камни
Как выбирать правильные значения limits
- Не завышайте значения — иначе часть ресурсов пропадёт невостребованной, а новые сервисы не смогут развернуться.
- Не занижайте — это может вызывать сбои, если приложению действительно нужны большие ресурсы.
- Тестируйте под нагрузкой — используйте стресс-тесты, чтобы подобрать оптимальные значения.
Как проверить текущие limits
Для любого pod запустите:
kubectl get pod <имя-pod> -o json | jq .spec.containers[].resources
Здесь я использовал jq
для более удобного отображения ресурсов каждого контейнера.
Остановка контейнера из-за превышения лимита памяти
Если ваш контейнер завершается с ошибкой OOMKilled, посмотрите события:
kubectl describe pod <имя-pod>
В строках событий (Events) будет видно, что pod был убит из-за Memory limit exceeded.
Изменение limits в уже созданных объектах
Для изменения ресурсов используйте kubectl edit
или отредактируйте манифест и примените его заново:
kubectl edit deployment <имя>
При изменении limits происходит rolling update (если это Deployment).
Короткий обзор дополнительных возможностей
Ограничения на уровне Namespace с ResourceQuota
Вы можете ограничить общий объём ресурсов на namespace:
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
namespace: dev
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
Так можно предотвратить злоупотребление ресурсами отдельным проектом или командой.
Настройка limits для нестандартных ресурсов
Если ваш кластер поддерживает GPU или другие специфические ресурсы, их тоже можно писать в limits. Пример для GPU NVIDIA:
resources:
limits:
nvidia.com/gpu: 1 # нужен 1 GPU
Это потребует наличия device plugin для GPU на worker-нодах.
Инструменты для наблюдения за потреблением ресурсов
- kubectl top — покажет текущую нагрузку на pod'ы или ноды.
- Prometheus + Grafana — лучшее решение для мониторинга ресурсов и анализа.
Пример просмотра загруженности пода:
kubectl top pod <имя-pod>
Вы увидите потребление CPU и памяти «живьём».
Использование limits в CI/CD
Вставляйте секцию resources с limits в шаблоны деплоймента ваших приложений — это best practice для Production среды. Часто для helm charts уже есть параметры values для настройки limits.
Как узнать, почему pod не стартует из-за requests/limits
Если Pod не стартует, посмотрите описание:
kubectl describe pod <имя-pod>
В разделе Events будет видно, если на ноде не хватает ресурсов для выделенных requests или limits слишком большие.
Как поступать с мультитенантными кластерами
- Применяйте LimitRange и ResourceQuota для отдельных namespace.
- Мониторьте потребление ресурсов и своевременно пересматривайте значения limits.
Заключение
Ограничение ресурсов с помощью limits в Kubernetes — важнейший механизм поддержания стабильности и безопасности в распределённом окружении. Грамотно подобранные лимиты защищают инфраструктуру от ран-ауэй контейнеров, минимизируют неожиданные остановки сервисов и повышают эффективность использования вычислительных мощностей кластера. Используйте limits вместе с requests, LimitRange и ResourceQuota, а для контроля применяйте инструменты мониторинга — так вы обеспечите безопасность и производительность ваших приложений.
Частозадаваемые технические вопросы по теме статьи и ответы на них
1. Как удалить LimitRange из namespace, если он мешает нужной конфигурации?
Удалите объект с помощью команды:shell
kubectl delete limitrange <имя-овъекта> -n <namespace>
2. Как узнать, используются ли дефолтные или явно прописанные limits в поде?
Используйте команду:shell
kubectl get pod <имя-pod> -o yaml | grep -A5 "resources:"
Тут покажутся заданные ограничения. Дефолтные limits не прописываются явно в объекте pod — смотрите LimitRange вашего namespace.
3. Можно ли менять limits для работающего pod без пересоздания?
Нет, limits меняются только на уровне pod spec, для этого требуется пересоздание pod (например, rolling update для Deployment).
4. Могут ли контейнеры внутри одного pod видеть друг друга по потребляемому ресурсу?
Нет, limits назначаются для каждого контейнера отдельно. Но если один контейнер превышает лимиты памяти, это может привести к завершению всего pod.
5. Как задать limits для нескольких сред (dev, stage, prod) через helm?
Используйте values.yaml в helm charts, объявив отдельные параметры для limits и requests. Например:
yaml
resources:
limits:
cpu: {{ .Values.resources.limits.cpu }}
memory: {{ .Values.resources.limits.memory }}
Для каждой среды задайте свои значения в соответствующем values-<env>.yaml
.
Постройте личный план изучения Kubernetes до уровня Middle — бесплатно!
Kubernetes — часть карты развития DevOps
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Kubernetes
Лучшие курсы по теме

Kubernetes и Helm
Антон Ларичев
Docker и Ansible
Антон Ларичев