Сетевое файловое хранилище для Kubernetes: NFS, EFS, Filestore

Файловое хранилище часто становится узким местом кластера: тома теряют доступность под нагрузкой, а сервисы простаивают в ожидании данных. Мы настраиваем NFS-сервер для Kubernetes под ключ — от проектирования схемы до регламентов сопровождения. Наши инженеры отвечают за отказоустойчивость и заметно сокращают время на запуск новых сервисов.
Часто задаваемые вопросы

NFS-сервер в Kubernetes: где ломается хранилище

Типовая схема выглядит так: один NFS-сервер в Kubernetes поднимают «на скорую руку» — единственный экспорт каталога, доступ по адресу узла, монтирование в общую папку для контейнеров. В тестовом контуре это работает, а в проде первым проявляется зависшее монтирование тома: процесс на узле не получает ответ и не может завершить операцию.

Зависшее монтирование тома — это не локальная проблема одного приложения. Под застревает в ожидании, узел не может корректно его завершить и уходит в недоступное состояние — вместе с ним встают соседние сервисы, которые к хранилищу вообще не обращались. При этом в журналах всё выглядит исправно: сервер отвечает, явных ошибок нет.

Вторая мина — потеря данных при рестарте пода. Если запись идёт в общий том без согласования блокировок, рестарт обрывает её на середине, и приложение после подъёма читает половину файла как целый. Несколько реплик, пишущих в одну директорию, добавляют гонки за именами и перезапись чужих результатов.

На пиковой нагрузке узкое место хранилища проявляется как растущая очередь запросов: сервер тратит время на операции с метаданными, приложение ждёт ответа и держит соединения. Добавление реплик в такой схеме не помогает — они упираются в тот же единственный узел.

Всё это лечится не «правильным сервером», а разделением ролей: режимами монтирования, уровнями доступа, лимитами и наблюдаемостью за томом. Разбираем, как это закрывается.

Что даёт управляемое файловое хранилище кластеру

Порядок в хранилище виден по скорости выдачи тома. При динамическом создании томов и декларативно описанном классе хранения том появляется в момент планирования пода, и контейнер стартует с уже примонтированным каталогом — без ручного экспорта на сервере и ожидания дежурного администратора. Задержка между «нужен том» и «том готов» перестаёт зависеть от человека.

Второй эффект — предсказуемый класс отказов хранилища. Одиночный NFS-сервер без репликации останавливает все поды, которые держат на нём данные: простой приложения равен времени восстановления сервера. Управляемое файловое хранилище Kubernetes разводит сбой узла и сбой сервиса — клиент переподключается к доступной точке, под переезжает и получает тот же том по тому же пути, а приложение не пересобирает состояние с нуля.

Третий — производительность записи под нагрузкой. Узкое место проявляется на метаданных раньше, чем на объёме: много мелких файлов, частая ротация журналов, одновременная запись из десятков подов. Режим доступа и параметры монтирования подбирают под профиль — общая запись для разделяемых каталогов, эксклюзивная для баз и очередей, отдельные тома под журналы, чтобы тяжёлая запись не тормозила чтение.

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

Свои NFS-узлы против облачного файлового сервиса

NFS в Kubernetes подключается как PersistentVolume через StorageClass и драйвер, а режим доступа решает, сколько узлов могут смонтировать том одновременно: ReadWriteMany — для общих каталогов, ReadWriteOnce — для одного потребителя. Ошибка в выборе проявляется не при деплое, а при масштабировании: новая реплика зависает в ожидании тома.

Вариант Когда подходит Ограничения
Свой NFS-узел Нужен контроль над экспортами, правами и снапшотами Единая точка отказа: упала машина — встали все поды с общим томом
Управляемый сервис провайдера, AWS EFS Несколько зон доступности, не хочется держать хранилище самим Выше задержка на мелких операциях, меньше настроек, зависимость от провайдера
Локальные диски узлов Базы, кэши, чувствительность к скорости ввода-вывода Только ReadWriteOnce, том привязан к узлу и не переезжает с подом
Блочный том с драйвером Одна реплика на запись, быстрый откат по снапшотам Общего доступа нет: второй под тот же том не смонтирует

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

Практическое правило: общие данные — на общем томе, базы и кэши — на локальных или блочных. Режим доступа проверяем до выката — на одном узле ReadWriteOnce работает, а на трёх репликах тот же манифест уже не поднимется.

Как мы внедряем файловое хранилище: этапы работ

Порядок работ выстраиваем так, чтобы каждый следующий шаг опирался на подтверждённые данные предыдущего. Сначала аудит хранилища: смотрим, какие тома уже смонтированы в кластер, какие заявки на тома остались от удалённых приложений, кто пишет в общий каталог и с какими режимами доступа. На этом этапе обычно всплывают два-три молчаливых узких места — перегруженный экспорт и приложение, держащее монтирование в режиме жёстких ожиданий.

  1. Аудит хранилища. Инвентаризация томов, профилей доступа, точек монтирования и прав; замер задержек чтения и записи под реальной нагрузкой приложений.
  2. Проектирование схемы. Выбор между общим экспортом и отдельными на приложение, разбиение по классам хранения, расчёт запаса по ёмкости и пропускной способности.
  3. Подготовка серверной части. Развёртывание службы, экспорты с ограничением по подсети, режим синхронной записи для критичных каталогов, квоты на пользователя.
  4. Подключение к кластеру. Драйвер хранилища, классы хранения и политики освобождения томов, чтобы удалённый том возвращал место, а не оставался висеть.
  5. Проверка отказоустойчивости. Гасим узел с приложением, рвём связь с хранилищем, смотрим, как ведут себя поды: переезд на другой узел, повторное монтирование, скорость возврата в работу.
  6. Нагрузочные прогоны. Смотрим, при какой параллельной записи начинаются очереди, и подбираем параметры монтирования под профиль приложения.
  7. Передача в эксплуатацию. Метрики по задержкам и заполнению томов, оповещения о сбоях, регламент расширения и краткая инструкция для дежурной смены.

Аудит занимает больше времени, чем настройка, и мы это не скрываем: переделка схемы после запуска обходится дороже, чем два дня инвентаризации до него. По итогу у команды остаётся рабочий стенд, воспроизводимая конфигурация и понятный порядок действий при отказе узла или самого хранилища.

Конфигурации, схемы и регламенты: что вы получаете

На выходе вы получаете не набор разрозненных манифестов, а комплект, по которому хранилище разворачивают, проверяют и передают дежурной смене. Всё лежит в репозитории рядом с приложениями: изменения проходят ревью, а состояние классов хранения и томов воспроизводится без ручных правок на узлах.

  • Конфигурации томов — StorageClass и описания PVC под разные профили доступа: ReadWriteMany для общих данных, ReadWriteOnce для нагруженных баз; параметры монтирования, каталог внутри тома и лимит по объёму.
  • Политики доступа к хранилищу — правила экспорта на стороне сервера, разграничение по подсетям и пространствам имён, отдельные права на чтение и запись, закрытый анонимный доступ.
  • Схема размещения — какой узел NFS отдаёт какие каталоги, в какой зоне он живёт, как том попадает в под, где точки отказа и как они разведены между собой.
  • Регламент резервного копирования — что копируется, с какой периодичностью, сколько хранятся копии, кто запускает восстановление и как проверяется, что копия действительно читается.
  • Документация по инфраструктуре — порядок подключения нового тома, действия при недоступности сервера хранилища, карта метрик, чек-лист приёма смены.
  • Наблюдаемость — метрики задержки операций, занятого объёма и ошибок на клиентах, пороги срабатывания и маршруты оповещений.
  • План миграции и отката — как перенести данные с текущего хранилища без простоя и как вернуться на прежнюю схему, если поведение приложения разойдётся с ожиданиями.

Кейс: перевели хранилище без простоя сервиса

До переезда все пространства имён в кластере Kubernetes работали с одной точкой монтирования NFS. Тома выдавались вручную: заявка, правка списка экспортов, ожидание инженера — от нескольких часов до суток. Отказ единственного сервера означал зависшие тома: поды не перезапускались, а очередь заявок копилась, пока дежурный разбирался с конфигурацией.

Что изменили

Собрали два узла хранилища с репликацией экспортов и автоматическим переключением, классы хранения описали декларативно — том создаётся и монтируется без участия человека. Добавили квоты на пространство имён, мониторинг задержек ввода-вывода и регламент замены узла, проверенный на учебном отказе.

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

Результат в цифрах

Выдача тома сократилась с 4-6 часов ручной работы до 30 секунд автоматической. Сбоев доступа к данным не было за полгода наблюдений — до переезда их набиралось 2-3 в месяц. Ручные операции с экспортами уменьшились примерно на 90%, остались расширение квот и плановые обновления. Время восстановления после отказа узла — с 40 минут ручного разбора до автоматического переключения за минуту.

Динамические тома или статическое подключение: что выбрать

В Kubernetes том можно выдать двумя способами, и разница не в удобстве, а в точке контроля. При динамическом режиме заявка ссылается на класс хранилища, и компонент, отвечающий за выдачу, сам создаёт том нужного размера, привязывает его к заявке и монтирует в под. При статическом подключении экспорт готовят заранее, а в кластер попадает описание тома с точным адресом и параметрами — приложение находит его по метке.

Выбор зависит от того, кто владеет данными и как долго они живут.

Вариант Когда подходит Ограничения
Динамические тома Сервисы с переменной нагрузкой, очереди, кеши, много однотипных окружений Нужен рабочий класс хранилища и права на создание томов; жизнью тома управляет политика возврата
Статическое подключение Общий экспорт для группы сервисов, данные, переживающие пересоздание кластера, внешние массивы Размер и адрес фиксированы; расширение и ротация — вручную

Ключевая деталь — управление жизненным циклом тома. Класс хранилища задаёт политику возврата: при удалении заявки том либо освобождается вместе с данными, либо сохраняется и требует ручного подключения. Для баз и очередей это решает, переживёт ли состояние пересоздание окружения.

На практике оба режима сосуществуют: динамический — для сервисов без состояния и временных окружений, статический — для данных, которые должны пережить кластер. Мы раскладываем их по классам хранилища так, чтобы ни один том не оставался бесхозным.

Технические вопросы перед внедрением хранилища

Перед внедрением у инженерной команды остаётся короткий список сомнений, от которых зависит судьба проекта: совместимость томов, одновременная запись, права доступа и поведение при отказе. Разбираем те, что всплывают на согласовании чаще всего.

Тома совместимы с текущими манифестами?

Проверяем на стенде тот же манифест, что пойдёт в продуктив: под получает каталог и видит обычную файловую систему. Отличие от блочного тома одно — нет форматирования, поэтому перенос и откат делаются копированием каталога, а не восстановлением снимка состояния.

Два пода пишут в один каталог — это безопасно?

Режим ReadWriteMany разрешает монтирование на несколько узлов, но согласованность обеспечивает приложение, а не хранилище. Для общих загрузок и артефактов это нормально; там, где важен порядок записи, оставляем одного писателя или разносим данные по подкаталогам с блокировками.

Как выдаются права доступа?

Через идентификаторы пользователя внутри пода и режим отображения прав root на сервере. Если их не настроить, контейнер пишет от непривилегированной учётки и получает отказ. Задаём владельца каталога и группу в шаблоне один раз — новые сервисы наследуют рабочую схему.

Что будет при отказе узла или сервера хранилища?

При отказе узла том отцепляется и переезжает вместе с подом — важно, чтобы точка монтирования была доступна с нового узла. При недоступности самого сервера поды уходят в ожидание ввода-вывода и не удаляются штатно, поэтому таймауты и режим возврата задаём заранее.

Обсудим задачу: что подготовить к разговору

План работ складывается из нескольких вводных: как устроен доступ к томам сейчас, какой профиль нагрузки и какие ограничения среды. Чем конкретнее ответы, тем меньше уточняющих кругов — оценка и план приходят за один проход, а не после трёх созвонов. Полное ТЗ готовить заранее не нужно.

Что полезно держать под рукой:

  • версия кластера Kubernetes, способ установки, число узлов и зон доступности;
  • текущая схема хранения — NFS-сервер, облачное файловое хранилище или локальные тома — и что в ней не устраивает;
  • профиль нагрузки: размеры томов, число одновременных читателей и писателей, нужен ли общий том на несколько подов;
  • чувствительность к задержке и пропускной способности на конкретных сценариях;
  • требования к отказоустойчивости: что должно пережить падение узла или зоны, допустимое время простоя и объём потерь;
  • ограничения среды: сетевые политики, приватные подсети, требования аудита, доступы к инфраструктуре;
  • сроки и окно, в которое допустимо менять прод.

С этим набором мы возвращаемся с оценкой и планом работ: этапы, риски и порядок подключения хранилища без остановки сервисов. Если часть данных пока неизвестна — разберём на разговоре и дополним по ходу.

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1394
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1369
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    816
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1142