Что такое ReplicaSet
Если в спецификации указано replicas: 3:
🟢 Junior Level
30-секундный ответ
ReplicaSet (RS) — это системный контроллер Kubernetes, единственная задача которого — гарантировать постоянное наличие заданного количества идентичных копий (реплик) пода в кластере в любой момент времени.
Если в спецификации указано replicas: 3:
- Контроллер непрерывно следит: «Сколько подов работает прямо сейчас?»
- Если один из подов упал с ошибкой или сервер под ним сгорел, ReplicaSet немедленно запускает новый под взамен выбывшего.
- Если вы вручную подняли лишний под с такими же метками, ReplicaSet удалит лишний, чтобы сохранить точное число 3.
Наглядная аналогия из жизни
Представьте старшего смены на кассах супермаркета:
- По регламенту в зале должно всегда работать строго 4 открытые кассы.
- Если один кассир заболел или ушёл на обед, старший смены немедленно сажает на кассу свободного сотрудника из резерва.
- Если наплыв покупателей схлынул и кассиров стало 5, старший смены отправляет лишнего сотрудника на склад.
Базовый манифест ReplicaSet
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: order-service-rs
spec:
replicas: 3 # Желаемое количество реплик
selector:
matchLabels:
app: order-service # Контролировать поды с этой меткой
template:
metadata:
labels:
app: order-service
spec:
containers:
- name: order-app
image: order-service:1.0
ports:
- containerPort: 8080
[!IMPORTANT] Золотое правило: в реальном продакшене ReplicaSet практически никогда не создаётся вручную! Вместо него всегда создаётся Deployment, который автоматически управляет жизненным циклом ReplicaSet под капотом.
🟡 Middle Level
Внутренний механизм: Цикл согласования (Reconciliation Loop)
ReplicaSet работает по принципу бесконечного автомата контроля с обратной связью:
┌────────────────────────────────────────┐
│ Чтение desired count из spec.replicas │
└──────────────────┬─────────────────────┘
│
▼
┌────────────────────────────────────────┐
│ Подсчёт actual Pods с метками selector │
└──────────────────┬─────────────────────┘
│
┌───────────────────┴───────────────────┐
│ │
actual < desired actual > desired
│ │
▼ ▼
[ API Call: Создать Pod ] [ API Call: Удалить лишний Pod ]
ReplicaSet vs Deployment: В чём разница?
Почему индустрия использует Deployment, а не «чистый» ReplicaSet?
| Возможность | ReplicaSet | Deployment |
|---|---|---|
| Поддержание $N$ реплик | 🟢 Да | 🟢 Да (через RS) |
| Самоисцеление при падении пода | 🟢 Да | 🟢 Да (через RS) |
| Rolling Update (Обновление без простоя) | ❌ Нет | 🟢 Да |
| Автоматический откат (Rollback) | ❌ Нет | 🟢 Да |
| Хранение истории релизов (Revisions) | ❌ Нет | 🟢 Да |
Как Deployment использует ReplicaSet при обновлении
Когда вы меняете версию образа в Deployment с v1 на v2:
- Deployment НЕ переписывает старый ReplicaSet. Он создаёт второй новый ReplicaSet для версии
v2. - Постепенно Deployment уменьшает реплики у
RS-v1($3 \to 2 \to 1 \to 0$) и параллельно наращивает реплики уRS-v2($0 \to 1 \to 2 \to 3$). - Старый
RS-v1остаётся в кластере со значениемreplicas: 0. Благодаря этому при командеkubectl rollout undoоткат происходит мгновенно:RS-v1масштабируется обратно до 3, а сбойныйRS-v2гасится в 0.
Set-Based Selectors vs ReplicationController
Исторический предшественник ReplicationController (из K8s v1.0) поддерживал только простое равенство меток (app = order-service).
Современный ReplicaSet поддерживает селекторы на основе множеств (Set-based Selectors):
selector:
matchExpressions:
- key: env
operator: In
values: [production, staging]
- key: tier
operator: NotIn
values: [frontend]
- key: release
operator: Exists
🔴 Senior Level
Усыновление (Adoption) и Сиротство (Orphaning) Подов
ReplicaSet связывается с подами не через жёсткие ссылки, а через динамическое сопоставление меток:
- Adoption (Усыновление):
- Если вы создадите под вручную (
kubectl run standalone-pod --labels="app=order-service"), а затем примените манифест ReplicaSet с селекторомapp: order-service, контроллер обнаружит этот под, посчитает его частью своей квоты и пропишет в метаданные пода полеmetadata.ownerReferences(указав свой UID и флагcontroller: true).
- Если вы создадите под вручную (
- Orphaning (Осиротение):
- Если удалить ReplicaSet с флагом каскадного удаления
kubectl delete rs my-rs --cascade=orphan, сам объект ReplicaSet будет стёрт изetcd, но все запущенные поды останутся работать как независимые поды-сироты!
- Если удалить ReplicaSet с флагом каскадного удаления
Хэш-метки Deployment (pod-template-hash)
Чтобы несколько ReplicaSet одного приложения не конфликтовали между собой из-за одинаковых меток app: order-service, контроллер Deployment автоматически вычисляет 32-битный хэш от содержимого spec.template (алгоритм FNV-1a) и инжектирует его как обязательную метку:
labels:
app: order-service
pod-template-hash: "6876878b9b" # Инжектировано автоматически!
Благодаря этой метке селектор каждого ReplicaSet изолирован, и контроллеры не пытаются удалить поды соседней версии.
Изменение шаблона: Ловушка spec.template
Критический вопрос на собеседованиях Senior уровня:
«Что произойдёт с работающими подами, если мы выполним
kubectl edit rsи заменим образ контейнера сapp:1.0наapp:2.0прямо в ReplicaSet?»
Ответ: Абсолютно ничего не произойдёт!
- Шаблон
spec.templateв ReplicaSet используется контроллером ТОЛЬКО в момент создания новых подов (когдаactual < desired). - Уже запущенные поды НЕ перезапускаются и НЕ обновляются, так как контроллер ReplicaSet проверяет только КОЛИЧЕСТВО подов, а не их внутреннее соответствие шаблону!
- Новые поды с образом
2.0появятся только тогда, когда старый под упадёт или будет удалён вручную. Именно поэтому для обновлений кода всегда используют Deployment, а не ReplicaSet.
4 Tricky Questions
1. Если изменить spec.template.spec.containers[0].image напрямую в запущенном ReplicaSet, обновятся ли текущие работающие Pod’ы?
Ответ:
Нет, текущие поды продолжат работать на старом образе.
Контроллер ReplicaSet следит исключительно за счётчиком количества живых подов (spec.replicas), соответствующих селектору matchLabels. Он не отслеживает drift (расхождение) конфигурации уже запущенных подов с текущим шаблоном template.
Пока количество работающих подов равно числу replicas, ReplicaSet не предпринимает никаких действий. Новый образ применится только к тем подам, которые будут созданы в будущем (например, при масштабировании или взамен случайно удалённого пода).
2. Что произойдёт, если два разных манифеста ReplicaSet будут иметь пересекающиеся селекторы меток (Overlapping Selectors), например app: myapp?
Ответ: Возникнет опасное состояние гонки (Race Condition / Flapping Loop):
- Если у обоих RS задано
replicas: 2, а в кластере запущено 2 пода с меткойapp: myapp, оба контроллера будут считать эти 2 пода «своими». - Но если контроллеры имеют разные
ownerReferences, контроллер A может попытаться «усыновить» поды контроллера B, удаляя и создавая их заново. - Если же подов станет 4, каждый из RS решит, что в кластере превышен лимит реплик, и оба контроллера одновременно начнут удалять поды, снижая их число до нуля, затем одновременно создавать новые, вводя поды в бесконечный шторм пересозданий. Kubernetes не блокирует дублирующиеся селекторы, ответственность лежит на инженере.
3. Чем отличаются стратегии каскадного удаления Foreground, Background и Orphan при удалении ReplicaSet?
Ответ:
При выполнении команды kubectl delete rs <name> --cascade=<policy>:
Background(по умолчанию): Kubernetes немедленно удаляет объект ReplicaSet из базы etcd. Затем сборщик мусора K8s (Garbage Collector) в фоновом режиме находит и удаляет все дочерние поды с соответствующимownerReference.Foreground: ReplicaSet переходит в статусdeletionTimestamp, получает финализаторforegroundDeletionи остаётся в etcd до тех пор, пока все дочерние поды не будут полностью остановлены и удалены. Только после этого стирается сам ReplicaSet.Orphan: ReplicaSet удаляется из etcd, но с дочерних подов предварительно снимаются меткиownerReferences. Все поды продолжают спокойно работать в кластере как неуправляемые одиночные поды.
4. В каком порядке ReplicaSet выбирает, какой именно Pod удалить, если мы уменьшаем число реплик с 5 до 2 (Scale Down)?
Ответ: Контроллер ReplicaSet использует строгий детерминированный приоритетный алгоритм сортировки кандидатов на удаление:
- Поды в фазе
Pending(ещё не запустившиеся) удаляются в первую очередь. - Поды в фазе
UnknownилиFailed(нездоровые). - Поды с непрошедшей проверкой готовности (
Ready=False). - Поды, работающие на нодах с наибольшим числом подов этого же ReplicaSet (для сохранения равномерного распределения по серверам кластера).
- Если все поды одинаково здоровы: удаляется самый молодой под (с самым поздним временем создания
creationTimestamp), так как более старые поды уже прогреты (JIT-компиляция в Java) и закэшированы.
🎯 Шпаргалка для интервью
Главное о ReplicaSet
- Суть: низкоуровневый контроллер, гарантирующий наличие $N$ реплик подов.
- Reconciliation Loop: сверяет
spec.replicasс фактическим числом подов по селектору. - Deployment vs ReplicaSet: Deployment управляет ReplicaSet’ами для Rolling Updates и Rollbacks.
- Шаблон
template: изменения шаблона в RS не перезапускают текущие поды. - Селекторы: поддерживает Set-based выражения (
In,NotIn,Exists). - Связь с подами: динамическая через
metadata.ownerReferences. - Каскадное удаление: флаг
--cascade=orphanоставляет поды жить после удаления RS.
Scale-Down приоритет (Кого убивают первым?)
1. Pending / CrashLoopBackOff поды
2. Поды с Ready=False
3. Поды с перегруженных нод (балансировка)
4. Самые «молодые» поды (сберегая прогретую JVM в старых подах)
Красные флаги на собеседовании (Чего говорить нельзя)
- ❌ «Для обновления версии микросервиса я редактирую образ в ReplicaSet» — поды не обновятся, нужно использовать Deployment.
- ❌ «В продакшене мы деплоим приложения манифестами с kind: ReplicaSet» — грубая ошибка, всегда используется
Deployment. - ❌ «ReplicaSet удаляет поды случайным образом при scale down» — существует строгий приоритетный алгоритм (Pending $\to$ Unready $\to$ Youngest).