Що таке 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 з мітками sel. │
└──────────────────┬─────────────────────┘
│
┌───────────────────┴───────────────────┐
│ │
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).