Namespaces, логические разделы кластера:
Namespace делит один кластер на изолированные по именам части. Deployment с именем api может существовать и в dev, и в prod одновременно, это разные объекты. Типовые сценарии: по неймспейсу на окружение (dev, staging, prod) или по неймспейсу на команду.
Из коробки есть четыре служебных: default (туда попадает всё, если не указать другое), kube-system (компоненты самого Kubernetes, CoreDNS например), kube-public и kube-node-lease. В kube-system руками лучше не лазить.
Код: Выделить всё
kubectl create namespace staging
kubectl get pods -n staging
kubectl config set-context --current --namespace=staging
Сеть между неймспейсами не изолирована. Service из главы 5 доступен из чужого namespace по полному имени, например api.staging.svc.cluster.local, а внутри своего хватает короткого api. И не всё в кластере вообще привязано к неймспейсам: ноды и PersistentVolume из главы 8 глобальные. Полный список таких объектов выдаёт kubectl api-resources --namespaced=false.
Requests и limits:
requests это сколько ресурсов шедулер резервирует под контейнер, когда выбирает ноду. limits это жёсткий потолок. CPU меряется в millicores, 500m это половина ядра. Память в Mi и Gi.
Код: Выделить всё
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: staging
spec:
replicas: 2
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: ghcr.io/cyberlake/api:1.4.2
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
От сочетания requests и limits зависит QoS-класс пода: Guaranteed (requests равны limits по CPU и памяти), Burstable (что-то задано, но не всё и не поровну) и BestEffort (не задано ничего). Когда ноде не хватает памяти, первыми на выселение идут BestEffort.
Откуда брать цифры: смотрите реальное потребление через kubectl top pod (нужен metrics-server, в minikube включается командой minikube addons enable metrics-server). Лимит по памяти ставьте всегда, а лимит по CPU тема холиварная: многие его не ставят вовсе, чтобы под мог разово взять свободные циклы ноды вместо троттлинга.
ResourceQuota и LimitRange:
Чтобы один namespace не сожрал кластер целиком, на него вешают квоту:
Код: Выделить всё
apiVersion: v1
kind: ResourceQuota
metadata:
name: staging-quota
namespace: staging
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "30"
Код: Выделить всё
apiVersion: v1
kind: LimitRange
metadata:
name: staging-defaults
namespace: staging
spec:
limits:
- type: Container
defaultRequest:
cpu: 100m
memory: 128Mi
default:
cpu: 500m
memory: 256Mi
Типичные грабли:
memory: 100m вместо 100Mi. Конфиг валидный, m означает милли, и вы только что запросили десятую часть байта. Шедулер радостно разместит такой под куда угодно, а реальное потребление никто не учтёт.
Под висит в Pending. Почти всегда это requests больше, чем свободно на любой ноде. kubectl describe pod покажет событие FailedScheduling с Insufficient cpu или Insufficient memory. На локальном minikube с парой ядер ловится на раз.
OOMKilled по кругу. Лимит памяти ниже реального потребления, контейнер убивают, он рестартует, счётчик RESTARTS растёт. Смотрите Last State: Terminated в kubectl describe pod.
Забытый -n. Деплой "пропал", хотя он просто в другом неймспейсе. kubectl get all -A показывает объекты во всех неймспейсах сразу.
Удаление namespace сносит всё содержимое: поды, сервисы, секреты, PVC. kubectl delete namespace staging это не уборка папки, а снос целого этажа.
Итог:
Теперь вы умеете резать кластер на неймспейсы, задавать контейнерам requests и limits, а неймспейсам квоты с дефолтами через LimitRange. Следующая глава про liveness и readiness пробы, без них Kubernetes не отличает живой под от зависшего. А если после внедрения лимитов поды начали вести себя странно, глава 11 про отладку как раз об этом.