Namespace, labels, selectors

Уровень: beginner ~50 мин Практика: Uptime Kuma (MIT)

Что нужно знать перед уроком

  • M1.03 — Service и порты — label selector уже встречался у Service/Deployment — здесь разбираем его полностью

Что нужно знать перед уроком

M1 уроки 2–3 — вы уже использовали selector: matchLabels у Deployment и Service интуитивно. Здесь — полный разбор селекторов и второй важной оси изоляции — Namespace.

Теория

Namespace-scoped vs cluster-scoped ресурсы

Не все объекты Kubernetes привязаны к namespace. Namespace-scoped — Pod, Deployment, Service, ConfigMap, Secret, Role, RoleBinding — существуют «внутри» конкретного namespace, их имена уникальны только в пределах namespace (web в ns-a и web в ns-b — разные объекты). Cluster-scoped — сама Namespace, Node, PersistentVolume, ClusterRole, ClusterRoleBinding, StorageClass, а из объектов Deckhouse — Module, PackageRepository (ровно то разграничение, которое станет центральным в M2 уроке 1) — существуют «поверх» всех namespace сразу, их имена уникальны на весь кластер.

1
2
kubectl api-resources --namespaced=true    # список namespace-scoped типов
kubectl api-resources --namespaced=false   # список cluster-scoped типов

Labels и Selectors — механизм связи «многие ко многим»

Label — произвольная пара key: value в метаданных объекта, не влияющая на поведение сама по себе (в отличие от spec) — просто маркер для группировки и поиска. Selector — выражение, отбирающее объекты по их лейблам. Их комбинация — основной механизм связи между независимо существующими объектами Kubernetes (Deployment находит «свои» Pod’ы, Service находит «свои» Pod’ы, NetworkPolicy находит «свои» Pod’ы — и всё это через один и тот же механизм лейблов, без прямых ссылок по имени).

Equality-based селекторы (поддерживаются и в matchLabels, и в -l):

1
2
kubectl get pods -l 'env=prod'          # равенство
kubectl get pods -l 'tier!=frontend'    # неравенство

Set-based селекторы (поддерживаются только в matchExpressions, недоступны в matchLabels):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
selector:
  matchExpressions:
    - key: env
      operator: In
      values: ["prod", "qa"]
    - key: tier
      operator: NotIn
      values: ["frontend"]
    - key: partition
      operator: Exists # проверка наличия ключа лейбла, безотносительно значения
    - key: partition
      operator: DoesNotExist # проверка отсутствия ключа

Через -l в CLI то же самое пишется как env in (prod,qa), env notin (dev), голое partition (Exists) или !partition (DoesNotExist).

Где работает только matchLabels, а где нужен matchExpressions
matchLabels — упрощённый синтаксис, поддерживающий только equality-сравнение (эквивалент нескольких In с одним значением). Как только нужна проверка «одно из нескольких значений», отрицание набора значений или сама проверка присутствия ключа — необходим matchExpressions. Оба блока можно комбинировать в одном селекторе одновременно — итоговое условие — их логическое И.

ResourceQuota vs LimitRange — два уровня одной задачи

Обе задачи направлены на «не дать namespace съесть кластер», но на разных уровнях:

LimitRangeResourceQuota
Уровень примененияодин объект (Pod/Container/PVC)весь namespace (агрегат)
Что задаётdefault/min/max для одного контейнерасуммарный лимит CPU/RAM/число объектов на весь namespace
Пример«у каждого контейнера memory не больше 512Mi»«суммарно в namespace не больше 4 CPU и 8Gi RAM»
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: LimitRange
metadata: { name: default-limits, namespace: course-m1-namespaces }
spec:
  limits:
    - type: Container
      default: { cpu: "200m", memory: "256Mi" }
      defaultRequest: { cpu: "100m", memory: "128Mi" }
      max: { cpu: "1", memory: "1Gi" }
---
apiVersion: v1
kind: ResourceQuota
metadata: { name: namespace-quota, namespace: course-m1-namespaces }
spec:
  hard:
    requests.cpu: "2"
    requests.memory: "4Gi"
    pods: "20"

Оба механизма работают одновременно и не заменяют друг друга: LimitRange следит за «дисциплиной» отдельных объектов (не дать создать Pod без лимитов вообще, задав default), ResourceQuota — за агрегатным потолком namespace целиком.

Частые ошибки и подводные камни

  • Ожидать, что matchLabels поддерживает In/NotIn/Exists. Он поддерживает только точное равенство — для сложной логики нужен matchExpressions.
  • Путать namespace-изоляцию с сетевой изоляцией. Namespace сам по себе не ограничивает сетевой трафик между Pod’ами разных namespace — для этого нужен NetworkPolicy (M10 урок 9), namespace — это только логическая группировка имён и область действия RBAC/квот.
  • Забыть, что ResourceQuota требует, чтобы у всех Pod’ов в namespace были заданы requests (если квота задана по requests.cpu/requests.memory) — иначе kubectl apply для Pod без resources будет отклонён с ошибкой квоты.

Практика в кластере

🧩 Практика урока: Uptime Kuma · лицензия MIT

Uptime Kuma — self-hosted мониторинг доступности сервисов (Node.js), легко разворачивается в нескольких экземплярах — удобно для демонстрации изоляции по namespace и лейблам.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
kubectl create namespace course-m1-ns-team-a
kubectl create namespace course-m1-ns-team-b

for ns in course-m1-ns-team-a course-m1-ns-team-b; do
kubectl apply -n $ns -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: uptime-kuma
  labels: { app: uptime-kuma, env: staging }
spec:
  replicas: 1
  selector: { matchLabels: { app: uptime-kuma } }
  template:
    metadata: { labels: { app: uptime-kuma, env: staging, team: ${ns##*-} } }
    spec:
      containers:
        - name: uptime-kuma
          image: louislam/uptime-kuma:1
          ports: [{ containerPort: 3001 }]
          resources:
            requests: { cpu: "100m", memory: "128Mi" }
            limits: { cpu: "300m", memory: "256Mi" }
EOF
done
  1. Убедитесь, что одноимённые Deployment’ы в разных namespace не конфликтуют:
1
kubectl get deployments -A -l app=uptime-kuma
  1. Потренируйтесь с равенство-based и set-based селекторами:
1
2
3
kubectl get pods -A -l 'env=staging'
kubectl get pods -A -l 'team in (a,b)'
kubectl get pods -A -l 'team notin (b)'
  1. Примените LimitRange/ResourceQuota из теории на course-m1-ns-team-a и проверьте, что превышение квоты блокируется:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
kubectl apply -n course-m1-ns-team-a -f - <<'EOF'
apiVersion: v1
kind: ResourceQuota
metadata: { name: quota }
spec:
  hard: { pods: "2" }
EOF
kubectl scale deployment/uptime-kuma -n course-m1-ns-team-a --replicas=5
kubectl get deployment uptime-kuma -n course-m1-ns-team-a   # реплик меньше желаемого — квота блокирует создание сверх лимита
kubectl describe resourcequota quota -n course-m1-ns-team-a

Практика разработки

Используется официальный образ louislam/uptime-kuma; собственная сборка — в M3.

Шпаргалка команд урока

1
2
3
4
5
6
7
8
kubectl api-resources --namespaced=true|false
kubectl get <kind> -A -l 'key=value'
kubectl get <kind> -A -l 'key in (v1,v2)'
kubectl get <kind> -A -l 'key notin (v1)'
kubectl get <kind> -A -l 'key'          # Exists
kubectl get <kind> -A -l '!key'         # DoesNotExist
kubectl describe resourcequota <name> -n <ns>
kubectl describe limitrange <name> -n <ns>

Вопросы для самопроверки

Какой из перечисленных объектов является cluster-scoped, а не namespace-scoped?

PersistentVolume, как и Node, ClusterRole, сама Namespace — существуют вне привязки к конкретному namespace.

Источник: Kubernetes — kubectl reference

Какое выражение НЕЛЬЗЯ выразить через matchLabels, требуется matchExpressions?

matchLabels поддерживает только точное равенство; проверка «одно из нескольких значений» требует matchExpressions с operator: In.

Источник: Kubernetes — labels

В чём разница между LimitRange и ResourceQuota?

LimitRange — дисциплина отдельного объекта (min/max/default), ResourceQuota — суммарный потолок ресурсов и числа объектов на namespace.

Источник: Kubernetes — limit storage consumption

Что произойдёт, если в namespace с ResourceQuota по requests.cpu попытаться создать Pod без указанных resources.requests?

Если в namespace действует ResourceQuota по compute-ресурсам, все Pod'ы обязаны явно указывать requests/limits — иначе создание блокируется.

Источник: Kubernetes — resource quotas

Изолирует ли Namespace сетевой трафик между Pod'ами разных namespace по умолчанию?

По умолчанию Pod'ы разных namespace могут свободно обращаться друг к другу по сети — явная изоляция требует NetworkPolicy.

Источник: Kubernetes — network policies

Рекомендуемая литература

Официальная документация

Статьи и блоги

Книги

  • Marko Lukša. Kubernetes in Action. 2nd ed., 2022. ISBN 978-1617297618.
  • Kelsey Hightower, Brendan Burns, Joe Beda. Kubernetes: Up and Running. 3rd ed., 2022. ISBN 978-1098110201.
  • Michael Hausenblas, Stefan Schimanski. Programming Kubernetes. 2019. ISBN 978-1492047107.

Связанные материалы