Как в Kubernetes контролируется скорость и порядок завершения Pod’ов (например, при обновлении Deployment)?

«Как в Kubernetes контролируется скорость и порядок завершения Pod’ов (например, при обновлении Deployment)?» — вопрос из категории Kubernetes, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Скорость и порядок завершения Pod'ов контролируются в основном стратегией обновления Deployment (spec.strategy) и настройками graceful shutdown на уровне Pod.

1. Стратегия обновления Deployment: Она определяет, как новые Pod'ы заменяют старые.

  • RollingUpdate (по умолчанию): Позволяет точно задать темп обновления.
    • maxUnavailable: Максимальное количество Pod'ов, которые могут быть недоступны во время обновления (например, 25% или 1).
    • maxSurge: Максимальное количество Pod'ов, которые могут быть созданы сверх желаемого количества реплик (например, 25% или 1).

2. Graceful Shutdown на уровне Pod: Обеспечивает корректное завершение каждого отдельного Pod'а.

  • terminationGracePeriodSeconds: Общее время, отведенное Pod'у на завершение после получения SIGTERM (по умолчанию 30 секунд).
  • Хук lifecycle.preStop: Позволяет выполнить произвольную команду (например, снять нагрузку с балансировщика, завершить транзакции) до отправки SIGTERM основному процессу.

Пример манифеста Deployment с тонкой настройкой:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1  # Одновременно может быть недоступен только 1 Pod
      maxSurge: 1        # Одновременно может быть создан 1 новый Pod сверх реплик
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: app
        image: my-app:v2
        lifecycle:
          preStop:
            exec:
              # Пример: уведомление приложения о необходимости завершения
              command: ["sh", "-c", "curl -X POST http://localhost:8080/health/stop && sleep 10"]
        readinessProbe: # Важно для плавного обновления
          httpGet:
            path: /health/ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5

Как это работает на практике при kubectl rollout restart deployment/my-app:

  1. Создается 1 новый Pod (maxSurge:1), общее количество Pod'ов временно становится 5.
  2. Когда новый Pod проходит readinessProbe, один из старых Pod'ов получает SIGTERM и запускает хук preStop.
  3. Старый Pod удаляется только после успешного завершения preStop или истечения terminationGracePeriodSeconds.
  4. Количество недоступных Pod'ов в любой момент времени не превышает 1 (maxUnavailable:1).
  5. Процесс повторяется, пока все 4 реплики не будут обновлены. Это обеспечивает нулевое время простоя для пользователей.