Блог Лаборатории

Изменение ресурсов контейнера в Поде без перезагрузки

Ресурсы контейнера - ядра ЦПУ и оперативная память - в Kubernetes регулируются через requests и limits.
  • Requests - это то количество ресурсов, которые контейнер в Поде скорей всего будет потреблять. Оркестратор использует эти значения, чтобы определить на какой сервер поместить Под.
  • Limits - это жесткий лимит, который на уровне операционной системы выставляет cgroup на контейнер. Больше этих значений контейнер не сможет потребить ресурсов.
Проблема в том, что если необходимо изменить количество ресурсов, то Под нужно перезагрузить. Особенно это проблематично, если речь идет об автоматическом изменении ресурсов (VPA - Vertical Pod Autoscaler). В этом блоге мы рассмотрим in-place Pod resize, который впервые был добавлен в Kubernetes 1.27. Претерпев существенные изменения, он все так же остается в альфа стадии в 1.29. Но уже сейчас можно попробовать изменить ресурсы, не перезагружая Под.

Создание кластера

In-place доступен только через feature gates, поэтому есть вероятность что попробовать его на каком-нибудь сервисе не будет возможности. Например, только недавно Google Kubernetes Engine (GKE) разрешил протестировать этот функционал. Чтобы вы могли легко воспроизвести мои шаги, я буду использовать kind. Его можно развернуть локально или на любой виртуальной машине.
Перед установкой kind нужно установить docker (или podman) и kubectl. Самый быстрый способ установить kind, это скачать бинарник:
curl -L "https://kind.sigs.k8s.io/dl/v0.22.0/kind-$(uname)-amd64" -o /usr/local/bin/kind
chmod +x /usr/local/bin/kind
Запустим простейший кластер из следующего манифеста:
# cat kind.yaml 
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  image: kindest/node:v1.29.0
- role: worker
  image: kindest/node:v1.29.0

# kind create cluster --config kind.yaml

Без InPlacePodVerticalScaling

Запустим тестовый под с nginx:
# cat nginx.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: resize-test
spec:
  containers:
  - name: nginx
    image: nginx:1.25.4
    resources:
      requests:
        cpu: "250m"
        memory: "128Mi"
      limits:
        cpu: "500m"
        memory: "256Mi"

# kubectl apply -f nginx.yaml
Если мы попробуем изменить, например, requests.cpu, то получим ошибку:
resources:
      requests:
-     cpu: "250m"
+     cpu: "300m"
        memory: "128Mi"

# kubectl apply -f nginx.yaml
The Pod "resize-test" is invalid: spec: Forbidden: pod updates may not change fields other than `spec.containers[*].image`,`spec.initContainers[*].image`,`spec.activeDeadlineSeconds`,`spec.tolerations` (only additions to existing tolerations),`spec.terminationGracePeriodSeconds` (allow it to be set to 1 if it was previously negative)
...
Если бы у нас был Deployment или StatefulSet, то при их изменении был бы создан новый Pod, а старый уничтожен.

Включаем InPlacePodVerticalScaling

Уничтожим кластер:
kind delete cluster
Создаем новый кластер с включением нужного feature gate:
# cat kind.yaml 
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  "InPlacePodVerticalScaling": true
nodes:
- role: control-plane
  image: kindest/node:v1.29.0
- role: worker
  image: kindest/node:v1.29.0

# kind create cluster --config kind.yaml
Создаем тот самый Pod nginx:
kubectl apply -f nginx.yaml
Попробуем теперь изменить requests.cpu:
    resources:
      requests:
-     cpu: "300m"
+     cpu: "350m"
        memory: "128Mi"

# kubectl apply -f nginx.yaml
Изменения применятся без ошибок. Проверяем, что под не перезагружался и новые параметры на месте:
# kubectl describe pod resize-test
...
    Limits:
      cpu:     500m
      memory:  256Mi
    Requests:
      cpu:        350m
      memory:     128Mi
...
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  2m59s  default-scheduler  Successfully assigned default/resize-test to kind-worker
  Normal  Pulling    2m58s  kubelet            Pulling image "nginx:1.25.4"
  Normal  Pulled     2m53s  kubelet            Successfully pulled image "nginx:1.25.4" in 5.292s (5.292s including waiting)
  Normal  Created    2m53s  kubelet            Created container nginx
  Normal  Started    2m53s  kubelet            Started container nginx
В Events никаких новых событий с запуска Пода.

Заключение

В заключение, функционал in-place Pod resize в Kubernetes открывает новые возможности для управления ресурсами контейнеров, значительно упрощая процесс масштабирования приложений в реальном времени без необходимости перезапуска Подов. Это особенно ценно для динамических сред, где требования к ресурсам могут часто изменяться. Хотя функция все еще находится в альфа-версии, ее потенциал и удобство использования уже очевидны, и она обещает стать важным инструментом в арсенале разработчиков Kubernetes.
Нужна помощь с Kubernetes? Свяжитесь с Лабораторией.