← Kubernetes: рабочие нагрузки
5 мин · просто · Урок 1 из 11

ReplicaSet: держим N реплик

Контроллер, который сам восстанавливает нужное число копий Pod, и почему его почти никогда не пишут напрямую.

Зачем нужен ReplicaSet

Pod - наименьшая единица, которую запускает Kubernetes, одна копия приложения. Если узел упал или процесс завершил OOM-killer (механизм ядра Linux, который останавливает процессы при нехватке памяти), Pod без контроллера просто перестаёт существовать. Никто его не восстановит. Для разовой задачи это нормально, но веб-сервису нужно что-то, что будет держать нужное число копий.

ReplicaSet - контроллер, который держит ровно N копий Pod. Контроллер здесь - процесс, который постоянно сверяет реальность с планом. Если Pod меньше, чем нужно, ReplicaSet создаёт новые из шаблона. Если больше, удаляет лишние. Кто удалил Pod, не важно: человек руками или упавший узел. ReplicaSet тут же поднимет замену.

Поля манифеста

ReplicaSet · spec.selector matchLabels: app: web template · metadata.labels labels: app: web совпадение строк
Контроллер ищет свои Pod по строке из selector, шаблон обязан её отдавать.
apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: web-rs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginxinc/nginx-unprivileged:1.25
          ports:
            - containerPort: 8080

apiVersion: apps/v1 - ReplicaSet живёт в группе apps, не в core. Если написать просто v1, kubectl выдаст no matches for kind "ReplicaSet" in version "v1". То же касается Deployment и StatefulSet.

spec.replicas - сколько копий держать. Можно поставить 0: тогда контроллер уберёт все Pod, но сам объект останется. Удобно для временного выключения.

spec.selector - как контроллер находит свои Pod. matchLabels - набор пар ключ-значение. Все условия складываются через И. Label - это метка на ресурсе вида ключ-значение. Запись app: web означает «считаю своими все Pod с меткой app=web в этом namespace».

Селектор обязан совпадать с метками в template.metadata.labels. Если в селекторе app: web, а в шаблоне app: webapp, apply упадёт с selector does not match template labels. Контроллер создаёт Pod по шаблону, потом ищет их по селектору и должен находить.

Есть тонкость. ReplicaSet считает своими все Pod с подходящими метками, даже созданные не им. Если руками создать Pod с меткой app: web в том же namespace, ReplicaSet его подхватит. А если из-за этого реплик станет больше N, удалит случайный, чтобы вернуться к плану.

ReplicaSet владеет любым Pod с подходящей меткой, а не только теми, которые создал сам. Лишняя копия с app: web заставит контроллер удалить случайную реплику, чтобы вернуться к spec.replicas.

spec.template - шаблон Pod, по которому контроллер создаёт копии. Внутри обычная спека Pod, без apiVersion и kind.

Что показывает kubectl

kubectl get rs web-rs
# NAME     DESIRED   CURRENT   READY   AGE
# web-rs   3         3         3       12s

Если три числа сошлись, ReplicaSet здоров. Если READY меньше DESIRED, причину смотрят через kubectl describe rs web-rs и kubectl get pod.

Как выглядит самовосстановление

Один Pod удаляют руками и сразу смотрят список:

kubectl get pod -l app=web
kubectl delete pod <одно из имён>
kubectl get pod -l app=web -w

Через пару секунд появится новый Pod с другим случайным суффиксом в имени. Это и есть работа ReplicaSet.

Число реплик меняют на лету, без правки YAML:

kubectl scale rs/web-rs --replicas=5

ReplicaSet и Deployment

На практике ReplicaSet в манифестах пишут редко. Поверх него ставят Deployment - контроллер, который умеет обновлять версию образа без простоя (rolling update) и откатывать её назад. Но Deployment под капотом всё равно создаёт ReplicaSet, поэтому его поля надо понимать.

Домашка

Теорию закрепляет задание на своём кластере: 3 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.

./run.sh start k8s-replicaset     # развернуть стартовое состояние
./run.sh verify k8s-replicaset    # проверить текущий шаг

Коротко

Прошли материал до конца? Отметьте урок пройденным.