Namespaces, requests и limits

Рейтинг: 65.7% · 17 голосов
Kubernetes для разработчиков: поды, деплойменты, сервисы, ingress, конфиги и отладка. Уроки по главам с обсуждением.
Ответить
Аватара пользователя
anton_k8s
Сообщения: 55
Зарегистрирован: 12 май 2026, 03:23

Namespaces, requests и limits

Сообщение anton_k8s »

Оглавление курса (48)
  1. Зачем нужен Kubernetes и из чего состоит кластер
  2. Поднимаем локальный кластер: minikube и kind
  3. Поды: базовая единица запуска
  4. Deployment и ReplicaSet: управляем репликами
  5. Service: сетевой доступ к подам
  6. ConfigMap и Secret: выносим конфигурацию
  7. Ingress: пускаем трафик снаружи
  8. Хранилище: Volumes и PersistentVolumeClaim
  9. Namespaces, requests и limits (вы здесь)
  10. Health checks: liveness и readiness пробы
  11. Отладка: почему под не стартует
  12. Helm: пакетный менеджер для Kubernetes
  13. Базовая безопасность: RBAC и доступы
  14. Job и CronJob: разовые и периодические задачи
  15. StatefulSet и DaemonSet: stateful-нагрузки и системные агенты
  16. Стратегии обновления и планирование: rollout и rollback, graceful shutdown, nodeSelector, affinity, taints
  17. Автомасштабирование: HPA по метрикам, обзор VPA и Cluster Autoscaler
  18. Наблюдаемость: логи, метрики, events, обзор Prometheus и Grafana
  19. Безопасность глубже: securityContext, Pod Security Standards, NetworkPolicy, шифрование секретов
  20. Архитектура control plane: api-server, etcd, scheduler
  21. Узел кластера: kubelet, kube-proxy и container runtime
  22. Декларативная модель: reconciliation, контроллеры, CRD
  23. kubectl профессионально: get, describe, explain, jsonpath
  24. Под глубже: init, sidecar, lifecycle hooks и QoS
  25. Метки, селекторы и организация ресурсов
  26. Сервисы и kube-proxy глубже: типы, IPVS, EndpointSlices
  27. Ingress, ingress-контроллеры и Gateway API
  28. Секреты в кластере: шифрование, External Secrets, Vault
  29. Хранилище глубже: PV, StorageClass, CSI и StatefulSet
  30. Сеть кластера: CNI, NetworkPolicy и CoreDNS
  31. Планировщик: affinity, taints, topology spread
  32. Ресурсы, QoS и вытеснение: requests, limits, eviction
  33. Helm глубже: шаблоны, хуки, зависимости, OCI
  34. Kustomize и управление конфигурацией без шаблонов
  35. RBAC и аутентификация глубже
  36. Admission и Pod Security: контроль на входе
  37. Policy as code: Kyverno и OPA Gatekeeper
  38. GitOps: Argo CD и Flux
  39. Операторы и CRD: расширяем Kubernetes
  40. Сервис-меш: Istio, Linkerd и когда он нужен
  41. Эксплуатация кластера: апгрейд, узлы, бэкап etcd
  42. Где запускать кластер: managed, self-hosted, k3s, Deckhouse
  43. Траблшутинг кластера: Pending, CrashLoop, узлы NotReady
  44. Стоимость и эффективность кластера: FinOps
  45. CI/CD в Kubernetes: сборка, деплой, прогрессивные релизы
  46. Лучшие практики и антипаттерны Kubernetes
  47. Сквозной проект и путь дальше: от манифеста до прода
  48. Деплой приложений через Argo CD: Application, sync и App-of-Apps
Боль, которую мы лечим

Представь общий кластер на десяток команд. Один разработчик выкатывает Pod без описания ресурсов, его JVM на ровном месте съедает 12 ГБ, нода уходит в своп, и вместе с виновником с этой ноды вылетают чужие сервисы, которые вели себя прилично. Утром в дежурном чате претензии, а в логах - туман. Знакомо? Это классический результат кластера, где никто не задал правила игры: кто на каком участке живет, сколько кому можно занять и что произойдет при нехватке.

Этот урок про три инструмента, которые превращают хаос в управляемую систему. Namespace - граница, которая делит один физический кластер на логические участки (dev, prod, команды). requests - заявка ресурсов, под которую планировщик резервирует место. limits - жесткий потолок, за который контейнер не пустят. Поверх них - QoS-классы, которые решают, кого убьют первым при дефиците, и квоты, которые не дают одной команде сожрать кластер. Разберем не "что вписать в YAML", а механику под капотом: почему kubernetes namespace это не папка, почему requests limits kubernetes напрямую влияют на то, выживет твой Pod ночью или нет, и где грабли, на которые наступают все.

Изображение

Namespace - не папка, а граница имен и политик

Namespace в Kubernetes - это область видимости имен (отсюda и название) плюс точка приложения политик. Внутри одного namespace имена ресурсов уникальны: два Deployment с именем api в одном namespace невозможны, а в разных - запросто. Service получает внутреннее DNS-имя вида

Код: Выделить всё

api.production.svc.cluster.local
, где production - это namespace. Поэтому из Pod в namespace production до сервиса в том же namespace можно стучаться просто по имени api, а до чужого - по полному FQDN. Это первое, что путает новичков: namespace меняет сетевую адресацию через DNS.

Важно понимать, что namespace - это логическая, а не физическая изоляция. Pod из dev и Pod из prod могут оказаться на одной и той же ноде и по умолчанию свободно общаются по сети - namespace сам по себе не строит сетевой барьер. Чтобы запретить трафик между namespace, нужны NetworkPolicy (на CNI вроде Cilium или Calico). А чтобы развести по разным нодам - taints/affinity. Namespace дает другое: пространство имен, область для RBAC, область для квот и LimitRange.

Не все ресурсы живут в namespace. Есть namespaced-объекты (Pod, Deployment, Service, ConfigMap, Secret, PVC) и cluster-scoped (Node, PersistentVolume, StorageClass, ClusterRole, сами Namespace). Проверить, что где, можно так:

Код: Выделить всё

kubectl api-resources --namespaced=true | head
# NAME          SHORTNAMES   APIVERSION   NAMESPACED   KIND
# pods          po           v1           true         Pod
# services      svc          v1           true         Service
# deployments   deploy       apps/v1      true         Deployment

kubectl api-resources --namespaced=false
# nodes, persistentvolumes, storageclasses, clusterroles, namespaces...
Создается namespace одной командой или манифестом. Манифест предпочтительнее - он живет в Git и проходит через GitOps (Argo CD/Flux):

Код: Выделить всё

apiVersion: v1
kind: Namespace
metadata:
  name: team-billing
  labels:
    team: billing
    env: prod
    pod-security.kubernetes.io/enforce: baseline
Обрати внимание на лейбл

Код: Выделить всё

pod-security.kubernetes.io/enforce
. Это и есть актуальный на 2026 способ навесить Pod Security Standards через Pod Security Admission (PSP давно удалены). Лейбл на namespace - и весь Pod внутри проверяется на соответствие профилю baseline или restricted прямо при создании, без отдельных контроллеров. Удобно: политика безопасности привязана к границе namespace.

RBAC и квоты: namespace как единица управления

Namespace - естественная единица для раздачи прав. Role действует внутри одного namespace, ClusterRole - на весь кластер. Связка RoleBinding выдает команде права только на ее участок:

Код: Выделить всё

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: team-billing
  name: developer
rules:
- apiGroups: ["", "apps"]
  resources: ["pods", "deployments", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
Привязал эту Role к группе разработчиков billing - и они хозяева в team-billing, но не видят чужого. В managed-кластерах (Yandex Managed Kubernetes, VK Cloud, Deckhouse) это базовый паттерн мультитенантности: namespace на команду плюс RBAC плюс квота. Без квоты картина неполная - дальше про нее.

requests vs limits: гарантия против потолка

Вот сердце урока. У контейнера есть два числа на каждый ресурс - requests и limits. Это разные сущности, и путать их дорого.

requests - это заявка, на основе которой работает планировщик (kube-scheduler). Когда ты пишешь

Код: Выделить всё

requests.memory: 512Mi
, ты говоришь: "этому контейнеру для работы нужно гарантированно 512 МБ". Планировщик смотрит на ноды и ищет ту, где сумма requests всех уже размещенных Pod плюс твой request влезает в Allocatable ноды. То есть requests - это бронь места. Важнейший нюанс: планировщик считает по requests, а не по фактическому потреблению. Если контейнер запросил 512Mi, а реально жрет 100Mi - 412Mi на ноде все равно считаются занятыми для планирования. Перезаложишь requests - получишь полупустые ноды и счет от облака.

limits - это жесткий потолок на рантайме, который применяет уже не планировщик, а ядро Linux через cgroups. И тут ключевая асимметрия между CPU и памятью, ее надо понять раз и навсегда.

CPU - сжимаемый ресурс. CPU limit реализуется через CFS-квоту планировщика ядра: контейнеру выдают X микросекунд процессорного времени за каждый период (обычно 100 мс). Уперся в limit - тебя throttling, то есть притормаживают, заставляют ждать следующего периода. Процесс не падает, он просто медленнее. Поэтому слишком тесный CPU limit - это латентность и тормоза на ровном месте, даже когда на ноде полно свободных ядер.

Память - несжимаемый ресурс. Память нельзя "притормозить" - она либо есть, либо нет. Превысил memory limit - ядро через OOM killer убивает процесс. В статусе Pod ты увидишь OOMKilled и reason 137 (это 128 + сигнал 9, SIGKILL). Никаких предупреждений, никакого throttling - мгновенная смерть контейнера. Это грабли номер один: люди ставят memory limit "на глаз", приложение в пике дотягивается до него и падает в самый нагруженный момент.

Код: Выделить всё

resources:
  requests:
    cpu: "250m"        # 0.25 ядра гарантированно
    memory: "512Mi"    # 512 МБ забронированы
  limits:
    cpu: "1"           # потолок 1 ядро, дальше throttling
    memory: "512Mi"    # потолок 512 МБ, дальше OOMKill (137)
Запись CPU: это 250 милли-ядер, то есть 0.25 vCPU; это одно полное ядро. Память в Mi/Gi (мебибайты, степени двойки) или M/G (мегабайты, степени десяти) - не путай Mi и M, разница около 5 процентов и на больших числах заметна. Когда говорят kubernetes ресурсы, имеют в виду в первую очередь именно эту пару cpu/memory; есть еще ephemeral-storage и расширенные ресурсы вроде GPU (nvidia.com/gpu), они описываются так же.

QoS-классы и порядок вытеснения (kubernetes qos)

Kubernetes автоматически присваивает каждому Pod один из трех QoS-классов на основе того, как заданы requests и limits. Ты не пишешь класс руками - он вычисляется. И именно kubernetes qos определяет, кого kubelet убьет первым, когда на ноде кончится память (eviction под node memory pressure).
  • Guaranteed - у каждого контейнера в Pod заданы и requests, и limits, и они равны по cpu и по memory. Это самый защищенный класс. Такие Pod кубелет трогает последними.
  • Burstable - заданы какие-то requests/limits, но условие равенства не выполнено (например, request меньше limit). Pod может "бурстить" сверх request, пока на ноде есть слабина, но под давлением не защищен.
  • BestEffort - не задано вообще ничего, ни requests, ни limits. Полностью бесправный класс.
Порядок вытеснения при нехватке памяти на ноде: сначала BestEffort (их кубелет режет первыми, независимо от реального потребления), потом Burstable - причем в первую очередь те, кто сильнее всех превысил свой request, и в последнюю очередь Guaranteed. Логика простая и честная: кто ничего не попросил - тот первый кандидат на выход; кто взял ровно сколько забронировал - тот под защитой. Посмотреть присвоенный класс:

Код: Выделить всё

kubectl get pod api-7d9f -o jsonpath='{.status.qosClass}'
# Guaranteed

kubectl describe pod api-7d9f | grep -A1 'QoS Class'
# QoS Class:  Burstable
Практический вывод: для важного stateful (БД, брокеры) целься в Guaranteed - request равен limit, никто не выселит первым. Для типового stateless-сервиса нормален Burstable с разумным зазором. BestEffort в проде - почти всегда баг конфигурации, а не осознанное решение.

LimitRange и ResourceQuota: правила на весь namespace

Два контейнера выше задают ресурсы поштучно. Но в реальном кластере на команды нельзя надеяться, что каждый все пропишет. Тут два namespace-объекта.

LimitRange работает на уровне отдельного контейнера/Pod в namespace: задает дефолты (если разработчик не указал requests/limits, они подставятся автоматически) и границы (min/max, чтобы нельзя было запросить 64 ядра или поставить смешные 1Mi).

Код: Выделить всё

apiVersion: v1
kind: LimitRange
metadata:
  name: defaults
  namespace: team-billing
spec:
  limits:
  - type: Container
    default:            # станет limits, если не задано
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:     # станет requests, если не задано
      cpu: "100m"
      memory: "128Mi"
    max:
      cpu: "2"
      memory: "2Gi"
    min:
      cpu: "50m"
      memory: "64Mi"
Тонкий, но важный эффект: LimitRange спасает от BestEffort. Контейнер без resources: попал бы в BestEffort и вылетел бы первым при давлении. LimitRange же подставит ему defaultRequest и default - и Pod станет Burstable, то есть получит хоть какую-то защиту. Один объект на namespace - и весь "забывчивый" софт автоматически приподнят над дном.

ResourceQuota (resourcequota) работает на уровне всего namespace: ограничивает суммарное потребление и количество объектов. Это бюджет команды.

Код: Выделить всё

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-budget
  namespace: team-billing
spec:
  hard:
    requests.cpu: "10"
    requests.memory: 20Gi
    limits.cpu: "20"
    limits.memory: 40Gi
    pods: "50"
    persistentvolumeclaims: "10"
    count/services.loadbalancers: "2"
Тут есть жесткое правило, о которое спотыкаются: если в namespace действует ResourceQuota на requests/limits, то каждый Pod обязан их указать. Создаешь Pod без requests.memory в namespace с квотой на requests.memory - и API-сервер отклонит его с ошибкой "must specify requests.memory". Именно поэтому ResourceQuota и LimitRange ходят парой: квота требует указывать ресурсы, а LimitRange гарантирует, что значения подставятся по умолчанию. Без LimitRange команда упрется в стену отказов. Смотрим расход бюджета:

Код: Выделить всё

kubectl describe resourcequota team-budget -n team-billing
# Resource         Used   Hard
# --------         ----   ----
# limits.cpu       6      20
# limits.memory    18Gi   40Gi
# pods             23     50
# requests.cpu     3500m  10
# requests.memory  9Gi    20Gi
Колонка Used против Hard - это и есть пульс namespace. Видишь requests.cpu близко к Hard - значит новые Pod скоро перестанут планироваться по квоте, пора либо чистить, либо расширять бюджет.

Типичные грабли и антипаттерны
  • Нет requests вообще. Планировщик считает Pod "невесомым" и пихает на любую ноду. В пике все такие Pod дерутся за память, нода уходит в OOM, выселяются соседи. Всегда задавай requests хотя бы примерно.
  • Memory limit == request, но впритык по факту. Класс Guaranteed - хорошо, но если limit равен реальному пику, любой всплеск дает OOMKilled 137. Memory нельзя throttle, потолок жесткий. Закладывай запас над наблюдаемым пиком.
  • Слишком тесный CPU limit. Сервис тормозит, latency растет, а CPU на ноде свободен - это throttling. Часто CPU limit вообще лучше не ставить (только request), чтобы дать бурстить; многие команды осознанно отказались от CPU limits именно из-за паразитного throttling.
  • request сильно больше потребления. Ноды полупустые по факту, но "забронированы" под requests - платишь за воздух. Обратная сторона недобора - это перебор.
  • Один limit на всех "чтобы не думать". 4Gi всем подряд: мелочи переплачивают, прожорам не хватает. Размеры индивидуальны.
  • Забыли про init/sidecar-контейнеры. Нативные sidecar (1.29+, как init с restartPolicy: Always) тоже потребляют ресурсы и тоже учитываются в requests Pod. Не заложил - получил неверное планирование.
Right-sizing - это про то, чтобы числа отражали реальность. Снимаешь метрики (Prometheus, VPA в режиме recommend, в managed-кластерах встроенные дашборды), смотришь p95/p99 потребления за пару недель, ставишь requests около типовой нагрузки, а memory limit - с разумным запасом над пиком. В Kubernetes 1.35 in-place pod resize стал стабильным (GA): теперь cpu/memory requests и limits можно менять у работающего Pod без его пересоздания - kubelet переписывает cgroups на лету. Это сильно облегчает right-sizing: подкрутил цифры - контейнер не перезапустился.

Мини-лаба: повтори руками
  • Создай namespace:

    Код: Выделить всё

    kubectl create namespace lab
  • Примени к нему LimitRange и ResourceQuota из примеров выше (поменяй namespace на lab).
  • Запусти Pod без resources:

    Код: Выделить всё

    kubectl run be --image=nginx -n lab
    . Проверь его QoS:

    Код: Выделить всё

    kubectl get pod be -n lab -o jsonpath='{.status.qosClass}'
    - убедись, что LimitRange сделал его Burstable, а не BestEffort, и посмотри, какие requests/limits подставились в describe.
  • Создай Pod с равными requests и limits (cpu 200m, memory 256Mi и там, и там) - проверь, что класс Guaranteed.
  • Попробуй задать в Pod memory request 100Gi (выше max и выше квоты) - получи и разбери ошибку отказа.
  • Глянь расход:

    Код: Выделить всё

    kubectl describe resourcequota -n lab
    - сопоставь Used и Hard.
  • Удали песочницу:

    Код: Выделить всё

    kubectl delete namespace lab
    - заодно увидишь, как удаление namespace каскадом сносит все внутри.
Контрольные вопросы
  • Контейнер уперся в CPU limit и в memory limit - что произойдет в каждом случае и почему поведение разное?
  • По какому числу планировщик выбирает ноду - по requests или по фактическому потреблению, и чем грозит сильный перебор requests?
  • Какие три условия дают Pod класс Guaranteed, и в каком порядке kubelet выселяет классы при нехватке памяти на ноде?
  • Зачем ResourceQuota и LimitRange почти всегда применяют в паре, а не по отдельности?
Итог

Namespace режет кластер на участки с собственными правами (RBAC), безопасностью (PSS-лейблы) и бюджетом (ResourceQuota). requests - это бронь под планировщик, limits - жесткий потолок на рантайме: CPU за потолком throttling (медленно), memory за потолком OOMKilled 137 (мгновенно). Из соотношения этих чисел автоматически рождается QoS-класс, который ночью под нагрузкой решает, кого выселят первым. LimitRange подставляет дефолты и поднимает забывчивых из BestEffort, ResourceQuota держит команду в бюджете - вместе они превращают общий кластер в систему, где соседи не роняют друг друга. А right-sizing с in-place resize 1.35 позволяет подгонять цифры по реальным метрикам, не пересоздавая Pod.
👍5 ❤️2 🔥 😄 🤔2
✔ Лучший ответ сформирован автоматически — jimmy36
anton_k8s писал(а):лимит по CPU тема холиварная а в чем тогда защита от соседа по ноде, который начнет жрать весь проц? requests же вроде только при планировании учитываются. или под нагрузкой ядро таки делит cpu пропорционально requests? кто-нибудь проверял на живом кластере, а не в теории
Перейти к ответу →
Аватара пользователя
jimmy36
Сообщения: 1
Зарегистрирован: 12 май 2026, 11:23

Re: Namespaces, requests и limits

Сообщение jimmy36 »

✔ Лучший ответ — сформирован автоматически
anton_k8s писал(а):лимит по CPU тема холиварная
а в чем тогда защита от соседа по ноде, который начнет жрать весь проц? requests же вроде только при планировании учитываются. или под нагрузкой ядро таки делит cpu пропорционально requests? кто-нибудь проверял на живом кластере, а не в теории
👍 ❤️1 🔥 😄 🤔
Аватара пользователя
vernonn
Сообщения: 2
Зарегистрирован: 28 май 2026, 10:21

Re: Namespaces, requests и limits

Сообщение vernonn »

про OOMKilled по кругу прямо наша история. джава неделю рестартовала, лимит 512Mi, а хип сам себе выбрал больше и привет 137. вылечили -XX:MaxRAMPercentage=75, с тех пор тишина. короче если у вас jvm в контейнере, лимит без настройки хипа это лотерея
👍2 ❤️ 🔥 😄 🤔
Аватара пользователя
travio
Сообщения: 1
Зарегистрирован: 13 май 2026, 11:45

Re: Namespaces, requests и limits

Сообщение travio »

вместо kubectl config set-context всем советую поставить kubectx и kubens, переключение неймспейса одной командой и с автодополнением. на minikube тоже работает, жить становится сильно проще
👍 ❤️1 🔥 😄 🤔
Аватара пользователя
Mana21
Сообщения: 1
Зарегистрирован: 14 май 2026, 16:26

Re: Namespaces, requests и limits

Сообщение Mana21 »

вопрос по квотам: а что будет с подами, которые уже крутились в неймспейсе без requests до того, как туда повесили ResourceQuota? их прибьет или они доживают до первого рестарта?
👍 ❤️ 🔥1 😄 🤔
Ответить
← Предыдущая глава
Хранилище: Volumes и PersistentVolumeClaim
Следующая глава →
Health checks: liveness и readiness пробы

Все главы курса «Kubernetes: оркестрация контейнеров от основ до продакшена»

Поделиться темой: ✈ Telegram VK
  • Похожие темы
Похожие запросы: Раздача статики и SPA на nginx

Вернуться в «Kubernetes на практике»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость