🐳 Раздел 14 · Вопрос #21

Что такое namespace

Namespace — это квартиры в большом многоквартирном доме:


🟢 Junior Level

30-секундный ответ

Namespace (Пространство имён) — это встроенный механизм Kubernetes для виртуального логического разделения одного физического кластера на изолированные рабочие области для разных команд, проектов или окружений (dev, stage, prod).

  • Устранение конфликта имён: внутри одного namespace имена ресурсов должны быть уникальными, но в разных пространствах имён могут одновременно работать поды или сервисы с абсолютно одинаковыми именами (например, payment-service в dev и payment-service в prod).
  • Разделение прав доступа (RBAC): администратор может дать разработчикам полные права в пространстве developer-sandbox, но запретить даже чтение логов в пространстве production.
  • Ограничение ресурсов: каждому пространству имён можно задать жесткий лимит по суммарному расходу CPU и оперативной памяти (ResourceQuota).

Наглядная аналогия из жизни

Namespace — это квартиры в большом многоквартирном доме:

  • Сам дом — это физический кластер серверов.
  • Квартиры 101, 102 и 103 — это пространства имён (dev, stage, prod).
  • В каждой квартире на кухне стоит свой холодильник с биркой «Холодильник» (одноименные поды order-db). Жильцы разных квартир не путают свои холодильники, потому что они находятся в изолированных комнатах.

Базовый манифест и команды

apiVersion: v1
kind: Namespace
metadata:
  name: billing-prod
  labels:
    environment: production
    team: billing
# Просмотреть список всех пространств имён в кластере
kubectl get namespaces

# Запустить под в конкретном namespace
kubectl run test-pod --image=nginx -n billing-prod

# Переключить рабочий namespace по умолчанию (чтобы не писать флаг -n)
kubectl config set-context --current --namespace=billing-prod

[!WARNING] Namespace — это НЕ физическая и НЕ сетевая изоляция! По умолчанию в Kubernetes включена плоская сеть: любой под из пространства dev может свободно отправлять HTTP-запросы в базу данных в пространстве prod. Для реальной сетевой изоляции необходима настройка NetworkPolicy.


🟡 Middle Level

Разделение ресурсов: Namespace-Scoped vs Cluster-Scoped

                           [ Kubernetes Кластер ]
                                     │
         ┌───────────────────────────┴───────────────────────────┐
         ▼                                                       ▼
  [ Namespace-Scoped Ресурсы ]                            [ Cluster-Scoped Ресурсы ]
  Живут строго внутри пространства имён:                  Глобальны для всего кластера:
  - Pod, Deployment, StatefulSet                         - Node (Физический сервер)
  - Service, Ingress, EndpointSlice                      - PersistentVolume (PV)
  - ConfigMap, Secret                                    - StorageClass
  - PersistentVolumeClaim (PVC)                          - ClusterRole, ClusterRoleBinding
  - ServiceAccount, Role, RoleBinding                    - Namespace (Само пространство)

Межсетевое взаимодействие: CoreDNS и FQDN

Поды из разных пространств имён могут легко обращаться друг к другу по сети с использованием полных доменных имён (FQDN):

http://<service-name>.<namespace-name>.svc.cluster.local:<port>
  • Внутри одного namespace: достаточно короткого имени: http://postgres:5432.
  • Из другого namespace: требуется FQDN: http://postgres.billing-prod.svc.cluster.local:5432.

Контроль ёмкости: ResourceQuota vs LimitRange

Для защиты кластера от «жадных» арендаторов используются два дополняющих друг друга механизма:

1. ResourceQuota (Суммарный потолок на весь Namespace)

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: dev-team
spec:
  hard:
    requests.cpu: "20"        # Сумма всех requests.cpu не может превысить 20 ядер
    requests.memory: 50Gi     # Сумма всех requests.memory не более 50 ГБ
    limits.cpu: "40"
    limits.memory: 100Gi
    pods: "30"                # Максимум 30 подов в этом namespace

2. LimitRange (Правила для каждого отдельного контейнера)

apiVersion: v1
kind: LimitRange
metadata:
  name: container-limits
  namespace: dev-team
spec:
  limits:
  - default:                  # Лимит по умолчанию, если разработчик забыл указать
      cpu: "1"
      memory: "1Gi"
    defaultRequest:           # Реквест по умолчанию
      cpu: "200m"
      memory: "256Mi"
    max:                      # Запретить контейнеры больше 4 CPU
      cpu: "4"
      memory: "4Gi"
    type: Container

🔴 Senior Level

Иллюзия безопасности: почему Namespace не является границей доверия

На архитектурных собеседованиях Senior-уровня распространен вопрос:

«Безопасно ли размещать в одном кластере в разных Namespace приложения публичного контура и закрытые банковские базы данных?»

Ответ: НЕТ, если не приняты дополнительные меры. Namespace изолирует только видимость через API Server, но:

  1. Общее ядро Linux (Shared Kernel): поды из dev и prod могут быть запущены шедулером на одной и той же физической ноде. Уязвимость ядра Linux (например, Dirty Pipe, Dirty COW или баги в подсистеме eBPF) позволяет процессу из ненадежного контейнера получить root-доступ к хосту и захватить соседние контейнеры prod.
  2. Плоская сеть (Flat Network): если в кластере не включен CNI с поддержкой NetworkPolicy (Cilium или Calico) и не объявлена политика «запретить всё по умолчанию» (Default Deny), контейнеры видят трафик друг друга.
  3. Решение для строгого Multi-Tenancy: физическое разделение на разные кластеры серверов, либо изоляция сред выполнения на базе виртуализации уровня гипервизора (Kata Containers, gVisor).

Зависание Namespace в статусе Terminating (Finalizers Trap)

Классическая аварийная ситуация: администратор выполняет kubectl delete namespace staging, но удаление зависает в статусе Terminating на несколько дней.

Механизм зависания:

  1. Контроллер NamespaceLifecycle ставит статус Terminating и запускает каскадное удаление всех вложенных ресурсов.
  2. В секции spec.finalizers у пространства имён по умолчанию стоит блокировщик kubernetes.
  3. Если хотя бы один вложенный ресурс содержит незавершенный финализатор (например, PVC ожидает ответа от отвалившегося облачного хранилища AWS EBS, или пользовательский CRD от оператора не может завершить graceful-очистку), удаление блокируется навечно.

Алгоритм реанимации:

# 1. Найти ресурс, блокирующий удаление
kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get --show-kind --ignore-not-found -n staging

# 2. Очистить финализаторы на проблемном объекте
kubectl patch pvc stuck-pvc -n staging -p '{"metadata":{"finalizers":null}}' --type=merge

# 3. Крайняя хирургическая мера: прямое удаление финализатора через Raw API
kubectl get namespace staging -o json | jq '.spec.finalizers=[]' | kubectl replace --raw "/api/v1/namespaces/staging/finalize" -f -

Pod Security Standards (PSA) на уровне Namespace

В Kubernetes 1.25+ устаревшие PodSecurityPolicy заменены на встроенный Admission Controller Pod Security Admission (PSA), который настраивается простыми лейблами на самом Namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: secure-prod
  labels:
    # Запретить запуск root-контейнеров, hostPath, privileged mode
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/warn: restricted

API Server автоматически отклонит создание любого пода, нарушающего стандарты безопасности CIS Benchmark!


4 Tricky Questions

1. Что произойдёт при попытке создать Deployment без блока resources.requests, если в данном Namespace активен объект ResourceQuota с ограничением по CPU?

Ответ: API-сервер немедленно отклонит создание пода с ошибкой валидации admission-контроллера:

Error from server (Forbidden): pods "order-app-xxx" is forbidden: failed quota: compute-quota: must specify cpu for: order-app

Если в ResourceQuota задано ограничение на суммарный объём requests.cpu, контроллер квот требует, чтобы абсолютно каждый контейнер в этом namespace имел явно объявленный requests.cpu. Единственный способ избежать этой ошибки без ручного прописывания ресурсов в каждом манифесте — создать в этом же пространстве имён объект LimitRange с секцией defaultRequest, который будет автоматически подставлять дефолтные значения во все новые контейнеры на этапе мутации манифеста.


2. Почему PersistentVolume (PV) является объектом кластерного уровня (Cluster-Scoped), в то время как PersistentVolumeClaim (PVC) привязан к конкретному Namespace?

Ответ: Это фундаментальное архитектурное разделение зон ответственности:

  • PersistentVolume (PV) представляет собой физический дисковый ресурс (LUN в СХД, том AWS EBS, локальный NVMe SSD). Им распоряжается администратор инфраструктуры кластера. Этот ресурс глобален и не должен быть привязан к изолированным проектам.
  • PersistentVolumeClaim (PVC) — это пользовательская заявка на ресурс от конкретного приложения разработчика (например: «Мне в проекте billing нужно 50 ГБ SSD»). Она создается разработчиком в рамках своего Namespace.
  • Kubernetes находит подходящий свободный глобальный PV и монопольно связывает (bind) его с локальным PVC. При удалении Namespace удаляется только заявка (PVC), а судьба физического тома (PV) определяется его глобальной политикой reclaimPolicy (Retain или Delete).

3. Каким образом злоумышленник, скомпрометировавший под в Namespace development, может получить доступ к базе данных в Namespace production при стандартной конфигурации Kubernetes?

Ответ: При развертывании кластера «из коробки»:

  1. Сетевой уровень: сетевая модель Kubernetes CNI по умолчанию является абсолютно плоской и полностью разрешительной (Allow-All). Злоумышленник из шелла пода в dev может запустить curl http://db.production.svc.cluster.local:5432 и получить доступ к открытому сокету базы данных.
  2. Уровень DNS: CoreDNS кластера резольвит имена сервисов из любых пространств имён для всех клиентов без ограничений. Защита: обязательное создание манифеста NetworkPolicy с типом Ingress, разрешающего подключение к БД в production только от подов, имеющих строго определенный namespaceSelector.

4. Можно ли перенести уже работающий Pod или Service из одного Namespace в другой с помощью команды kubectl?

Ответ: Нет, перенести работающий объект между пространствами имён невозможно. Поле metadata.namespace является неизменяемым (Immutable) с момента создания объекта. В базе данных etcd ключ ресурса жестко включает имя namespace: /registry/pods/<namespace>/<pod-name>. Чтобы переместить сервис, необходимо:

  1. Выгрузить его манифест: kubectl get deployment my-app -n old-ns -o yaml > app.yaml.
  2. Изменить в манифесте поле metadata.namespace: new-ns.
  3. Применить его в новом пространстве: kubectl apply -f app.yaml.
  4. Удалить старый ресурс в прежнем пространстве имён.

🎯 Шпаргалка для интервью

Главное о Namespace

  • Суть: виртуальное логическое разделение кластера; позволяет использовать одинаковые имена ресурсов в разных окружениях.
  • Главный миф: Namespace НЕ обеспечивает физическую и сетевую изоляцию по умолчанию.
  • Межсетевой DNS: service-name.namespace-name.svc.cluster.local.
  • ResourceQuota: суммарный лимит CPU/RAM/Pods на всё пространство имён.
  • LimitRange: дефолтные и граничные значения CPU/RAM на один контейнер.
  • Зависание в Terminating: вызвано блокировкой финализаторами (spec.finalizers) на дочерних ресурсах (PVC, CRD).
  • Безопасность: Pod Security Admission (restricted) настраивается через лейблы на Namespace.

Типы ресурсов по области видимости

| Область видимости | Примеры ресурсов | | :— | :— | | Namespaced | Pod, Service, Deployment, PVC, ConfigMap, Secret, ServiceAccount, Role | | Cluster-wide | Node, PersistentVolume, StorageClass, ClusterRole, Namespace |

Красные флаги на собеседовании (Чего говорить нельзя)

  • ❌ «Namespace изолирует сеть, поэтому поды из dev не могут подключиться к сервисам в prod» — сеть плоская, для изоляции обязательно нужен NetworkPolicy.
  • ❌ «Мы храним dev, stage и production в одном namespace default» — антипаттерн, приводящий к хаосу и риску случайного удаления данных.
  • ❌ «Чтобы перенести Pod в другой namespace, достаточно поменять его через kubectl edit pod» — поле namespace неизменяемо в etcd.

Связанные вопросы