При создании локального кластера Kubernetes легкость работы с в основном сконфигурированным облачным решением сменяется мощностью (и ответственностью) более сложного решения, которое можно адаптировать к конкретным локальным требованиям. Это также требует относительно глубоких знаний о сети, хранилище и вычислениях, но также дает свободу настраивать и оптимизировать кластер для конкретных случаев использования, таких как машинное обучение.

Существует несколько вариантов начальной загрузки локального кластера Kubernetes для машинного обучения, 2 из которых используются очень часто:

Kubespray — набор Ansible playbooks, которые позволяют обеспечивать и управлять конфигурацией для готового к работе кластера.

Kubeadm — утилита для создания минимально работоспособного кластера Kubernetes.

Оба этих подхода устанавливают и настраивают основные компоненты плоскости управления Kubernetes:

  • Менеджер контроллера
  • Планировщик
  • API-сервер

А также компонент, работающий на каждом узле, управляющий временем выполнения контейнера:

  • Кубелет

Этот последний компонент (Kubelet) имеет несколько конфигураций, которые могут быть очень полезны для настройки машинного обучения. Вот несколько причин и шаги по их настройке:

  1. Образы докеров машинного обучения могут неожиданно заполнить дисковое пространство

Рассмотрите образы докеров ML, на которых запущена выбранная вами платформа (например, Tensorflow или Pytorch), набор инструментов CUDA, дополнительные библиотеки Python и т. д. Такие образы могут легко увеличиваться в размере более 10 ГБ, а иногда даже до более чем 15 ГБ. Это может не быть проблемой, когда имеющийся пул хранения достаточно велик, однако, учитывая меньший диск, который использует образы докеров совместно с другими процессами (например, диск ОС), есть вероятность, что диск заполнится из нескольких источников перед сборкой мусора. (GC) срабатывает должным образом, и происходят неожиданные события. Простая контрмера — вынести образы докеров из пространства ОС на отдельный диск, где Kubelet полностью контролирует и может задействовать GC без других процессов, также записывающих на этот диск.

Если отдельный диск недоступен, Kubelet также можно настроить для выполнения GC с заданным пользователем порогом. В кластере Kubernetes вы можете настроить Kubelet с помощью переменной KUBELET_EXTRA_ARGS environment.

Эта переменная получена из:

  • /etc/default/kubelet (в дистрибутивах на основе DEB)
  • /etc/sysconfig/kubelet (в дистрибутивах на основе RPM)

Варианты настройки GC: --image-gc-low-thresholdи
--image-gc-high-threshold, которые определяют % использования диска, до которого образ GC пытается освободить (по умолчанию 80%), и % использования диска, который запускает образ GC (по умолчанию 85%), соответственно. Сборка мусора будет удалять изображения, которые использовались последними, пока не будет достигнуто нижнее пороговое значение.

Чтобы настроить порог использования диска на 70 %, при включении сборщика мусора на уровне 80 %, вы добавляете следующее содержимое в файл конфигурации Kubelet на узлах:

KUBELET_EXTRA_ARGS="--image-gc-low-threshold 70 --image-gc-high-threshold 80"

После этого нужно перезагрузить конфигурацию и перезапустить процесс Kubelet, чтобы изменения вступили в силу:

systemctl daemon-reload && systemctl restart kubelet 

2. Извлечение образа докера ML может быть преждевременно прервано

Следуя рекомендациям Dockerfile, вы, скорее всего, используете многоэтапные сборки и минимизируете количество слоев. Этот последний подход может означать, что когда вы извлекаете образ из своего репозитория, в нем очень мало слоев или даже один очень большой слой. Это может быть проблематично для Kubelet, так как он настроен по умолчанию для «небольших» микросервисов, где образы докеров «размера ML» являются исключениями, и обычно ожидается, что образ даже при относительно медленном интернет-соединении сможет натяните хотя бы 1 слой в течение нескольких минут. Для загрузки одного слоя «размера ML» может потребоваться гораздо больше времени, и в течение этого времени Kubelet не получает обновлений, поэтому в конечном итоге он помечает извлечение как неудачное.

Предупреждающее сообщение Kubelet при неудачном извлечении большого изображения также не очень информативно:

Failed to pull image "private-registry/big-ml-image:latest": rpc error: code = Canceled desc = context canceled

Kubelet может избежать этой случайности с некоторой дополнительной настройкой. По умолчанию он отменяет извлечение образа докера, если в течение 1 минуты не происходит никакого прогресса (% загруженного слоя не рассматривается как прогресс, только полностью загруженные слои считаются как прогресс). Это можно настроить с помощью опции --image-pull-progress-deadline

Опция устанавливается в файле конфигурации kubelet со временем в минутах (время, конечно, должно быть настроено на используемую пропускную способность интернета):

KUBELET_EXTRA_ARGS="--image-pull-progress-deadline 30m"

Объединение конфигураций крайнего срока выполнения сборщика мусора и извлечения будет выглядеть следующим образом:

KUBELET_EXTRA_ARGS="--image-gc-low-threshold 70 --image-gc-high-threshold 80 --image-pull-progress-deadline 30m"

Заключительные замечания

С такой дополнительной конфигурацией можно избежать двух очень распространенных проблем kubernetes, связанных с рабочими нагрузками машинного обучения.

Эти шаги настройки — не единственный способ настройки Kubelet. Также можно использовать такие инструменты, как Kubeadm и Kubespray, для предварительной настройки Kubelet уже во время процесса начальной загрузки. Документация обоих инструментов объясняет, как это сделать, а также предлагает другие варианты дальнейших настроек Kubelet. Вы также можете заглянуть в Справочник по API Kubelet для получения подробной информации о других различных параметрах конфигурации.