Память внутри Linux-контейнеров (LXC)
Проблема
К несчастью /proc/meminfo, /proc/vmstat и ко. не контейнеризированы. Это к тому, что они не знают о cgroups. Они всегда отображают числа о памяти машины-хоста, что неудобно в современных linux-контейнерах. Процессы внутри контейнера не могут опираться на free, top, и другие программы для того, чтобы определить сколько памяти им доступно, но они подчиняются ограничениям, установленным их cgroups и не могут использовать всю память, доступную в хосте.
Это вводит в смятение многих пользователей linux-контейнеров. Почему free говорит, что доступно 32GB ОЗУ, когда как контейнеру позволено использовать только 512MB?
С популяризацией технологий, основанных на linux-контейнерах - Heroku, Docker, LXC, CoreOS, Imctfy, systemd - всё больше и больше пользователей сталкиваются с данной проблемой.
Почему это важно?
Более того, всё больше и больше людей пытаются максимизировать использование ресурсов контейнера, применяя автоматическое масштабирование числа рабочих процессов или потоков. Обычно применяется функция от доступной к использованию оперативной памяти. В этих случай наличие верной информации внутри контейнера особенно важно.
Подробнее о /proc
Некоторые элементы файловой системы /proc всё же контейнеризированы должным образом, например пространства имён /proc/PID/* и /proc/net/*, но не все. К сожалению, в целом в /proc с этим полный бардак. Вот цитата из замечательной статьи Создание виртуальных файловых систем Linux на LWN:
Линус и множество других разработчиков ядра не любят системный вызов ioctl(), видя в нём неконтролируемый способ добавления новых системных вызовов в ядро. Добавление новых файлов в /proc также не рекомендуется, так как это пространство вносит много неразберихи. Разработчикам, наводнившим свой код вызовами ioctl() или использованием /proc файлов, рекомендуется создать и использовать автономную виртуальную файловую систему.Эксперименты с с виртуальными файловыми системами, такими как progc, монтируемыми внутри контейнера и подменяющими файл /proc/meminfo версией, берущей информацию из cgroups, не завершаются успехом, потому что функции ядра для чтения статистики по памяти из cgroups (linux/memcontrol.h и mm/memcontrol.c) не публичные.
Некоторые пробуют аналогичные вещи, изменяя файловую систему /proc напрямую, но вряд ли их правки будут замержены в основное ядро, если они затрагивают всех пользователей файловой системы /proc. Решением должна стать либо кастомная файловая система (как procg), либо кастомная опция монтирования, например:
mount -t proc -o meminfo-from-cgroup none /path/to/container/proc
FUSE
Есть группа разработчиков ядра, отстаивающих мнение, что возможно было бы лучше вынести обработку из ядра в пользовательское пространство, сделав /proc/meminfo виртуальным файлом, который собирает информацию и форматирует её соответствующим образом.
Для реализации файловой системы в пространстве пользователя может быть использован FUSE. По этому пути можно найти либу libvirt c libvirt-lxc драйвером. Попытки интеграции FUSE-версии файла /proc/meminfo в LXC также имели место.
Несмотря на то что есть прекрасная реализация FUSE на чистом GO, предложение использовать FUSE в продакшен натыкается на значительное сопротивление. В основном оно связано с негативным опытом использования файловых систем FUSE (sshfs, s3fs) и увеличением пространства для атак. К тому же в таком методе есть и некоторые другие проблемы.
Также не даёт покоя мысль, что контейнеры зависят от демона из пользовательского пространства, обслуживающего FUSE запросы. Что будет, если демон упадёт? Все контейнеры останутся без доступа к их /proc/meminfo.
/proc не единственная проблема: sysinfo
Даже если мы сможем найти решение по контейнеризации /proc/meminfo, которое устроит всех, этого будет недостаточно.
Linux предоставляет системный вызов sysinfo(2), который возвращает информацию о системных ресурсах (например о памяти). Так же как и в случает с /proc/meminfo, он не контейнеризирован и всегда возращает метрики хоста.
Например сюрпризом при тестировании реализации замены для proc (procg) может оказаться, что решение не работает для Busybox. Выясняется, что реализация free от Busybox не использует /proc/meminfo. Она использует sysinfo(2). Что ещё может использовать этот вызов и оказаться сломанным внутри контейнера?
ulimit, setrlimit
На вершине лимитов cgroups, процессы linux также подчиняются ресурсным ограничениям, применяемым к ним индивидуально посредством setrlimit(2). И cgroups ограничения и rlimit применяются, когда память выделяется процессом.
systemd
Вскоре cgroups будут управляться через systemd. Все операции на cgroups будут выполняться через вызовы API к systemd посредством DBUS (или shared библиотеки). Это позволяет надеяться, что systemd предоставит процессам полноценный API, чтобы те смогли запросить доступную память. Но до тех пор...
Решение?
Некоторые разработчики ядра верят, что наилучший вариант - библиотека уровня пространства пользователей, которую бы могли использовать процессы. Новый код легко получит преимущество от использования такой библиотеки, но вряд ли такие программы как free или top когда-нибудь перейдут на неё. Возможно нужно поощрять прекращение использования этих утилит внутри контейнеров.
--
Вольный перевод статьи:
Комментарии
Отправить комментарий