Продвинутый уровень
Основы освоены — переходим к инструментам, которые превращают учебный кластер в production-платформу: управление правами доступа, публикация сервисов через Ingress, пакетный менеджер Helm, операторы, автомасштабирование и StatefulSet для приложений с состоянием.
RBAC — кто и что может в кластере
RBAC (Role-Based Access Control, управление доступом на основе ролей) — встроенный механизм авторизации Kubernetes. Он отвечает на вопрос: какому субъекту (пользователю, группе или сервисному аккаунту) какие действия над какими ресурсами разрешены. Модель строго разрешительная: всё, что не разрешено явно, — запрещено.
Четыре объекта RBAC
| Объект | Область действия | Назначение |
|---|---|---|
Role |
Один namespace | Набор разрешений внутри конкретного пространства имён |
ClusterRole |
Весь кластер | Разрешения на кластерные ресурсы (узлы, PV) или на объекты во всех namespace |
RoleBinding |
Один namespace | Привязывает Role или ClusterRole к субъекту внутри namespace |
ClusterRoleBinding |
Весь кластер | Привязывает ClusterRole к субъекту на уровне всего кластера |
Пример: роль «только чтение подов» и её привязка
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: team-payments
name: pod-reader
rules:
- apiGroups: [""] # пустая строка = core API
resources: ["pods", "pods/log"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods-binding
namespace: team-payments
subjects:
- kind: User
name: ivan # имя пользователя из сертификата/токена
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
ServiceAccount — удостоверение для приложений
Приложениям внутри кластера тоже нужны права — например, контроллеру, который читает список подов через API. Для этого служит ServiceAccount:
apiVersion: v1
kind: ServiceAccount
metadata:
name: app-sa
namespace: team-payments
---
# в Deployment указываем, под каким аккаунтом работают поды:
spec:
template:
spec:
serviceAccountName: app-sa
# проверить, есть ли право у субъекта:
kubectl auth can-i create deployments --as=ivan -n team-payments
kubectl auth can-i list secrets --as=system:serviceaccount:team-payments:app-sa
cluster-admin приложениям и не используйте wildcard-правила ("*" в resources и verbs) в боевых кластерах. Каждому ServiceAccount — ровно те права, которые нужны его приложению, и не больше.
Ingress — публикация HTTP-сервисов наружу
Service типа LoadBalancer удобен, но создаёт отдельный облачный балансировщик на каждый сервис — дорого и негибко. Ingress решает это иначе: один внешний вход (ingress-контроллер) принимает весь HTTP/HTTPS-трафик и маршрутизирует его по внутренним сервисам на основе доменного имени и пути URL. Плюс здесь же терминируется TLS.
Ingress-манифест — это только правила. Исполняет их ingress-контроллер, который нужно установить в кластер отдельно: популярны ingress-nginx, Traefik, HAProxy Ingress, а также реализации на базе Gateway API.
Манифест Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: main-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
tls:
- hosts:
- app.example.ru
secretName: app-tls # Secret с сертификатом
rules:
- host: app.example.ru
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
Helm — пакетный менеджер Kubernetes
Реальное приложение — это десяток манифестов: Deployment, Service, Ingress, ConfigMap, ServiceAccount... Копировать их между окружениями и править руками неудобно. Helm упаковывает набор манифестов в чарт (chart) — шаблонизированный пакет с параметрами.
Ключевые понятия
| Термин | Определение |
|---|---|
| Chart | Пакет: шаблоны манифестов + файл значений по умолчанию values.yaml + метаданные |
| Release | Экземпляр чарта, установленный в кластер. Один чарт — много релизов (dev, stage, prod) |
| Repository | Хранилище чартов (HTTP-сервер с индексом), например репозитории проектов и venдоров |
| Values | Параметры релиза: количество реплик, теги образов, домены — переопределяются при установке |
Типичный рабочий процесс
# добавить репозиторий чартов и обновить индекс
# (URL берите из документации проекта-владельца чарта)
helm repo add example <URL-репозитория-чартов>
helm repo update
# поискать чарт
helm search repo postgresql
# установить релиз со своими значениями
helm install mydb example/postgresql \
--namespace databases --create-namespace \
--set auth.database=appdb \
--set primary.persistence.size=20Gi
# посмотреть релизы и историю
helm list -n databases
helm history mydb -n databases
# обновить релиз новой версией чарта/значений
helm upgrade mydb bitnami/postgresql -f my-values.yaml -n databases
# откатиться на ревизию 1
helm rollback mydb 1 -n databases
Фрагмент values.yaml
replicaCount: 3
image:
repository: registry.example.ru/myapp
tag: "1.4.2"
service:
type: ClusterIP
port: 80
ingress:
enabled: true
host: app.example.ru
resources:
requests:
cpu: 200m
memory: 256Mi
kubectl apply -k) работает через наложение «патчей» на базовые манифесты без шаблонов. Часто их комбинируют: чарт рендерят Helm-ом, а окружение-специфичные правки вносят Kustomize.
Операторы — автоматизация сложных приложений
Оператор — это паттерн (и программа), который расширяет Kubernetes знаниями о конкретном приложении. Оператор вводит собственный тип объекта — CRD (Custom Resource Definition), например PostgreSQL или KafkaCluster, — и контроллер, который следит за такими объектами и выполняет операционную логику: развёртывание, бэкапы, обновление версий, восстановление после сбоев.
# Пример декларативного заказа кластера PostgreSQL через оператор
# (схема зависит от конкретного оператора)
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
name: main-db
namespace: databases
spec:
teamId: "main"
numberOfInstances: 3 # оператор сам настроит репликацию
postgresql:
version: "16"
volume:
size: 50Gi
Идея оператора — перенести знания опытного администратора в код контроллера. Существуют зрелые операторы для PostgreSQL, MySQL, Kafka, Redis, Elasticsearch, мониторинга (Prometheus Operator) и многого другого. Пишут операторы на Go с библиотекой client-go, а также через фреймворки Operator SDK и Kubebuilder.
HPA и VPA — автомасштабирование
Kubernetes умеет подстраивать ресурсы под нагрузку автоматически, в трёх независимых измерениях:
| Механизм | Что меняет | По какому сигналу |
|---|---|---|
| HPA (Horizontal Pod Autoscaler) | Количество реплик пода | CPU, память, внешние и пользовательские метрики (например, длина очереди) |
| VPA (Vertical Pod Autoscaler) | Requests/limits контейнеров | История фактического потребления |
| Cluster Autoscaler | Количество узлов кластера | Наличие подов в состоянии Pending из-за нехватки ресурсов |
Манифест HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60 # целевая загрузка CPU, % от requests
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 75
behavior:
scaleDown:
stabilizationWindowSeconds: 300 # не спешить уменьшать
resources.requests — utilization считается именно от них. Без requests HPA работать не будет.
StatefulSet — приложения с состоянием
Deployment идеален для stateless-приложений: реплики взаимозаменяемы. Но базы данных, очереди и распределённые системы требуют стабильной идентичности: предсказуемого имени, постоянного сетевого адреса и закреплённого тома. Это даёт StatefulSet:
- поды получают порядковые имена:
db-0,db-1,db-2; - создание и удаление идут строго по порядку: сначала
db-0, потомdb-1; - каждый под получает собственный PersistentVolumeClaim из шаблона
volumeClaimTemplates; - стабильные DNS-имена через headless-сервис:
db-0.db-headless.ns.svc.cluster.local.
Манифест StatefulSet с headless-сервисом
apiVersion: v1
kind: Service
metadata:
name: db-headless
spec:
clusterIP: None # headless: без виртуального IP
selector:
app: db
ports:
- port: 5432
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
spec:
serviceName: db-headless
replicas: 3
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates: # у каждого пода — свой том
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 20Gi
DaemonSet, Job и CronJob
DaemonSet — по поду на каждом узле
DaemonSet гарантирует, что на каждом (или выбранном селекторами) узле кластера работает ровно один экземпляр пода. Классические применения: агенты сбора логов (Fluent Bit), мониторинга (Node Exporter), сетевые плагины, агенты безопасности.
Job — разовая задача до завершения
Job запускает под и дожидается его успешного завершения, при необходимости перезапуская. Подходит для миграций БД, пакетной обработки, разовых вычислений.
apiVersion: batch/v1
kind: CronJob
metadata:
name: nightly-backup
spec:
schedule: "0 3 * * *" # каждую ночь в 03:00, формат cron
concurrencyPolicy: Forbid # не запускать, пока не завершился предыдущий
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2 # две попытки при сбое
template:
spec:
restartPolicy: Never
containers:
- name: backup
image: backup-tool:1.2
args: ["--target", "s3://backups"]
Свой Helm-чарт шаг за шагом
Чужие чарты устанавливать вы уже умеете. Следующий шаг — упаковать собственное приложение: чарт превращает набор манифестов в параметризуемый пакет, который ставится одной командой и обновляется без ручной правки YAML.
Шаг 1. Создать скелет чарта
# генерация типового чарта
helm create myapp
# структура каталогов
myapp/
├── Chart.yaml # имя, версия, описание чарта
├── values.yaml # значения параметров по умолчанию
├── charts/ # зависимости (другие чарты)
└── templates/ # шаблоны манифестов
├── deployment.yaml
├── service.yaml
├── ingress.yaml
├── serviceaccount.yaml
├── _helpers.tpl # вспомогательные шаблонные функции
└── NOTES.txt # подсказка, выводимая после установки
Сгенерированный чарт — рабочий пример: он сразу устанавливает nginx. Удалите из templates/ лишнее и адаптируйте под своё приложение.
Шаг 2. Параметризовать шаблоны
В шаблонах доступны значения из values.yaml через .Values и служебные данные релиза через .Release:
# values.yaml
replicaCount: 2
image:
repository: myregistry/myapp
tag: "1.4"
# templates/deployment.yaml (фрагмент)
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
Шаг 3. Проверить рендер без установки
# линт: синтаксис и типовые ошибки чарта
helm lint myapp
# отрендерить манифесты и посмотреть глазами
helm template myapp ./myapp
# пробный прогон против реального кластера
helm install myapp ./myapp --dry-run
Шаг 4. Установить, обновить и при необходимости откатить
# установка релиза
helm install myapp ./myapp -n myapp --create-namespace
# список релизов и состояние
helm list -n myapp
# обновление с переопределением параметров
helm upgrade myapp ./myapp -n myapp --set replicaCount=3
# обновление из файла значений для окружения
helm upgrade myapp ./myapp -n myapp -f values-prod.yaml
# история ревизий релиза
helm history myapp -n myapp
# откат на предыдущую ревизию
helm rollback myapp -n myapp
# откат на конкретную ревизию
helm rollback myapp 2 -n myapp
# удаление релиза
helm uninstall myapp -n myapp
values.yaml, а не захардкожены в шаблонах; значения по умолчанию должны давать рабочую установку «из коробки»; файлы значений для окружений (values-dev, values-prod) хранятся в git рядом с чартом. И помните: каждый helm upgrade — новая ревизия, поэтому любая неудачная правка откатывается одной командой helm rollback.
Итог: карта контроллеров нагрузки
| Задача | Объект |
|---|---|
| Stateless-приложение, N реплик, обновления без простоя | Deployment |
| СУБД, очередь — стабильные имена и тома | StatefulSet |
| Агент на каждом узле: логи, метрики, сеть | DaemonSet |
| Разовая задача до успешного завершения | Job |
| Периодическая задача по расписанию | CronJob |
| Публикация HTTP/HTTPS с маршрутизацией и TLS | Ingress + контроллер |
| Права пользователей и приложений | Role / ClusterRole + bindings |
| Автоматическое число реплик по нагрузке | HPA |
Следующий логичный шаг — понять, как устроена сеть, связывающая всё это воедино: раздел «Сети в Kubernetes».