Как обеспечивается отказоустойчивость узлов (нод) в Kubernetes?

Ответ

Отказоустойчивость узлов в Kubernetes обеспечивается за счёт архитектуры самого кластера и дополнительных практик.

1. Архитектура Control Plane:

  • Разворачиваю кластер с несколькими нодами control plane (минимум 3 для кворума). В управляемых сервисах (EKS, GKE) это обеспечивается провайдером.
  • Компоненты control plane (API Server, etcd, Scheduler, Controller Manager) реплицированы и распределены по нодам.

2. Отказоустойчивость рабочих нод (Worker Nodes):

  • Группы нод (Node Groups): Использую Managed Node Groups в EKS или Instance Groups в GKE, которые автоматически пересоздают упавшие ноды.
  • Распределение по зонам: Размещаю ноды как минимум в двух, а лучше в трёх Availability Zones (AZ) облачного провайдера. Это защищает от падения целой зоны.
  • Anti-affinity для системных подов: Настраиваю PodAntiAffinity для критичных системных компонентов (Ingress-контроллеры, операторы), чтобы они не оказались на одной ноде.
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: nginx-ingress
    spec:
    replicas: 3
    selector:
    matchLabels:
      app: ingress
    template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - ingress
            topologyKey: kubernetes.io/hostname

3. Мониторинг и самовосстановление:

  • Настраиваю алерты в Prometheus на метрики нод: kube_node_status_condition{condition="Ready",status="false"} или node_cpu_utilisation > 90%.
  • Использую Pod Disruption Budgets (PDB) для гарантии доступности приложения во время плановых работ (обновление нод, масштабирование). PDB указывает, сколько реплик приложения могут быть недоступны одновременно.
    apiVersion: policy/v1
    kind: PodDisruptionBudget
    metadata:
    name: app-pdb
    spec:
    minAvailable: 2  # Минимум 2 пода должны оставаться доступными
    selector:
    matchLabels:
      app: my-critical-app

4. Стратегия обновления нод:

  • Использую механизм rolling update для групп нод, который последовательно дренирует (cordon & drain) и пересоздаёт ноды с новым образом, минимизируя влияние на поды.

Ответ 18+ 🔞

Да ты посмотри, какая тема интересная! Ну, про отказоустойчивость в кубересе. Это ж, ёпта, целая наука, чтобы твоё приложение не накрылось медным тазом, когда какая-нибудь нода решит сыграть в ящик.

1. Архитектура Control Plane: Вот тут, бля, основа основ. Нельзя же разворачивать мастер-ноду в единственном экземпляре — это ж пизда рулю сразу. Надо минимум три штуки для этого самого кворума, чтобы они между собой болтали. В нормальных managed-сервисах (типа EKS, GKE) за тебя уже всё сделали, не парься. А так-то все эти штуки — API Server, etcd и прочая — должны быть размножены и раскиданы по разным машинам. Чтобы если одна ебанько, остальные работали.

2. Отказоустойчивость рабочих нод (Worker Nodes): А вот с рабочими нодами уже твоя головная боль. Первое — группы нод (Node Groups). В том же EKS есть Managed Node Groups — золотая вещь. Упала нода — система сама, без твоего участия, создаст новую. Во-вторых, зоны доступности (AZ). Ты что, все яйца в одну корзину сложишь? Раскидывай ноды хотя бы по двум, а лучше по трём зонам! Чтобы если в одной дата-центр сгорел, в других твои поды жили-поживали. И третье — не дай боже всем твоим критичным подам (типа ingress-контроллеров) впихнуться на одну ноду. Надо им запретить это делать через PodAntiAffinity. Смотри, как это выглядит в деле:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-ingress
spec:
  replicas: 3
  selector:
    matchLabels:
      app: ingress
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - ingress
            topologyKey: kubernetes.io/hostname

Видишь? Говорим: «ребята, вы с одним лейблом app: ingress не смейте садиться на одну ноду (hostname)». Вот и вся магия.

3. Мониторинг и самовосстановление: А как ты узнаешь, что нода легла? По наитию? Надо мониторинг, чувак! Настраиваешь Prometheus на метрики вроде kube_node_status_condition{condition="Ready",status="false"} — и сразу видишь, кто откинулся. Или node_cpu_utilisation > 90% — овердохуища нагрузки, скоро кирдык. И ещё одна хитрая жопа — Pod Disruption Budgets (PDB). Это такая бумажка, которая говорит: «окей, администратор, ты там ноды обновляешь, но смотри — у меня минимум два пода моего критичного приложения должны оставаться живыми, не трогай их всех разом!»

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: app-pdb
spec:
  minAvailable: 2  # Минимум 2 пода должны оставаться доступными
  selector:
    matchLabels:
      app: my-critical-app

Без этого твоё обновление кластера может превратиться в настоящую хиросиму для приложения.

4. Стратегия обновления нод: Ну и наконец, как эти ноды обновлять, чтобы не получить волнение ебать у всей команды. Используй rolling update для групп нод. Система берёт ноду, переводит её в режим «не трогать» (cordon), аккуратно выгоняет с неё все поды (drain), а потом пересоздаёт с новым образом. И так по одной. Приложения даже не заметят, если всё правильно настроено. Главное — чтобы PDB не нарушалось, а то будет тебе нигерсраки вместо плановых работ.

Вот, коротко и по делу. А то некоторые думают, что запустил кластер — и можно спать спокойно. Хуй с горы! За ним глаз да глаз нужен.