ROCKER
ROCKER — это реализация «онлайн-распаковки» и процесса «песочницы», предназначенная для использования в системах интернета вещей (IoT), основанных на Linux, с ограниченными ресурсами. Цель проекта — повысить эффективность использования ресурсов и безопасность системы, а также избежать дополнительных потерь производительности.
С помощью сжатия файлов приложений и других подходящих файлов в формат squashfs можно добиться экономии дискового пространства более чем на 60%, что очень важно для систем IoT с ограниченными ресурсами. При этом, поскольку ядро Linux изначально поддерживает динамическое распаковывание по требованию, по сравнению с обычным режимом работы приложений не возникает дополнительных затрат памяти.
Безопасность функций песочницы обеспечивается базовыми средствами Linux, такими как пространства имён Linux namespaces, контрольные группы cgroups, оверлейная файловая система overlayfs, а также язык программирования Rust и многочисленные тестовые примеры. Автор благодарит Линуса Торвальдса, создателя Linux, и команду Rust за эти замечательные базовые инструменты.
1.1. Основные особенности и характеристики
— Более высокая производительность и эффективность использования ресурсов по сравнению с Docker, запуск контейнеров не требует дополнительных образов; — клиентская библиотека разработана на чистом C, без каких-либо зависимостей, кроме libc; — серверная часть (библиотека) разработана на языке Rust, обеспечивая стабильность, сравнимую с C/C++, и высокую эффективность выполнения и использования памяти; — использование инструментальной цепочки crosstool-ng обеспечивает хорошую устойчивость и надёжность; — единый стиль кода, чистота и элегантность; — акцент на документации и тестировании; — дополнительные особенности, рекомендуется изучить исходный код для более глубокого понимания.
1.2. Руководство пользователя
1.2.1. Структура кода (кратко)
Весь проект разделён на две части: клиентскую и серверную. Клиентская часть представлена библиотекой, которая используется вызывающей стороной.
..
├── core/ # [Rust 代码] 服务端核心逻辑实现
├── rocker_server/ # [Rust 代码] CS server 端实现
├── librocker_client/ # [C 代码] CS client 库实现
├── librocker_client_wrapper/ # [Rust 代码] 通过 ffi 封装的 librocker_client 库, 用于测试
├── tests/ # [Rust 代码] 测试用例
├── README.md # 项目主文档
└── tools/
1.2.2. Конфигурация среды и компиляция
Требования к среде:
Компиляция: Теоретически проект может быть скомпилирован и запущен на любой архитектуре, поддерживаемой crosstool-ng и Rust. Для платформ, отличных от x86(_x64), по умолчанию используется статическая компоновка библиотек musl или uclibc для упрощения зависимости от среды выполнения.
Пример для TARGET=armv7-linux-musleabihf:
# Компиляция и установка, путь установки находится в корневом каталоге проекта install_dir
make TARGET=armv7-linux-musleabihf release
# Функциональное тестирование
make TARGET=armv7-linux-musleabihf test
# Тестирование производительности
make TARGET=armv7-linux-musleabihf bench
1.2.3. Библиотека клиента
Пример вызова:
// Определяется вызывающей стороной, будет выполняться в ROCKER
void *your_args = NULL;
int start_your_APP(void *args){};
// Инициализация пустого RockerRequest
RockerRequest req = ROCKER_request_new();
// Назначение значений для RockerRequest
req.app_id = 1000;
req.uid = 1000;
req.gid = 1000;
req.app_pkg_path = "/tmp/your_APP.squashfs";
req.app_exec_dir = "/var/your_APP/execdir";
req.app_data_dir = "/var/your_APP/datadir";
req.app_overlay_dirs = { "/usr", "/var", "/etc", "/home", "/root" };
// Попытка запуска приложения в ROCKER
RockerResult res = ROCKER_enter_rocker(&req, start_my_APP, my_args);
if (ROCKER_ERR_success != res.err_no) {
// Обработка ошибок
}
// Завершение работы приложения, очистка среды
kill(res.guard_pid, SIGKILL);
// Более надёжный метод очистки
RockerResult res2 = ROCKER_get_guardname(res.guard_pid);
if (ROCKER_ERR_success == res2.err_no && \
0 == strcmp(res.guard_name, res2.guard.name)) {
kill(res.guard_pid, SIGKILL);
}
Подробности см. в librocker_client. Среда, в которой будет запущено приложение, описывается в разделе 1.3.1.3.
(7) PID of guard\App
После запуска приложения RockerClient возвращает AppMaster PID и другую связанную информацию о Guard и приложении, чтобы AppMaster мог осуществлять последующее управление. На этом RockerClient завершает свою работу во время однократного запуска приложения и больше не участвует в последующих этапах.
(8) stop all; (10) kill
У AppMaster есть два способа остановить приложение: один — это самостоятельное управление согласно обычной логике, а другой — автоматическое завершение через kill RockerGuard.
Оба метода имеют свои преимущества и недостатки:
(9) exit self
RockerGuard автоматически завершает работу, когда все остальные процессы в rocker-виртуальной песочнице завершаются. Если AppMaster пропускает какой-либо процесс, ресурсы этого rocker никогда не будут освобождены.
(11) send SIGCHLD
Когда RockerGuard завершает работу, RockerMaster получает сигнал SIGCHLD и может выполнять некоторые соответствующие внутренние логические операции.
(12) rocker's [PID 1] exited
Ядро обнаруживает выход процесса с номером 1 в определённом пространстве имён pid.
(13) broadcast SIGKILL(auto, very clean); (14) umount overlay; (15) destroy useless loop device
Ядро автоматически очищает все ресурсы (включая производные ресурсы), включая рекурсивное создание.
(0) clone(MNT|PID)
RockerMaster создаёт экземпляр RockerGuard с помощью интерфейса clone с флагами CLONE_MNT и CLONE_PID, как описано в man clone(2).
(1) create loop device
RockerGuard вызывает ioctl для получения доступного устройства loop, как указано в man loop(4).
(2) bind App.sqfs to loop; (3) mount loop to exec-path
Приложение упаковывается в формат squashfs и привязывается к новому устройству loop. RockerGuard монтирует устройство loop в путь выполнения, указанный AppMaster.
Создание App.sqfs и процесс привязки и монтирования аналогичны следующей командной строке:
#Упаковать файлы приложения в squashfs, сначала установить инструмент squashfs-tools
mksquashfs ./AppDir ./App.sqfs
#Привязать squashfs к устройству loop
losetup /dev/loop8 ./App.sqfs
#Смонтировать в указанный каталог
mount ./App.sqfs /mnt/AppExecDir
(4) build overlay {#1}
RockerGuard создаёт слой изоляции overlay чтения-записи, подробности описаны в разделе 1.3.1.2.
(5) remount /proc
Перемонтировать /proc, чтобы информация о pid в новом пространстве имён pid отображалась нормально.
(6) unshare(USER)
По завершении вышеуказанных работ RockerGuard переходит в новое пользовательское пространство имён user_namespace через вызов интерфейса unshare. После этого все операции в rocker выполняются в ограниченном пользовательском пространстве имён, как описано в man unshare(2).
(7) done
Подготовка RockerGuard завершена, и уведомление отправляется RockerMaster.
(8) set uid_map
RockerMaster устанавливает uid_map (требуется CAP_SETUID) и gid_map (требуется CAP_SETGID) для RockerGuard. Перед установкой gid_map необходимо записать «deny» в файл /proc/[RockerGuard PID]/setgroups, как описано в user_namespaces(7).
(0) get all visiable top-dir except /proc,/sys,/dev,/run
Пройтись по всем верхним каталогам и исключить динамические каталоги, такие как /proc, /sys, /dev и /run.
(1) top-dir act as 'lowerdir', and finally merged to themself
Все видимые верхние каталоги объединяются в независимые пространства имён mnt_namespace с наложением слоя изоляции overlay, так что каждое приложение имеет независимую читаемую и записываемую виртуальную файловую систему, как описано в документации ядра по overlayfs.
Например, если приложение с идентификатором 1000 монтирует /usr, то предполагается, что его upperdir и workdir — /private/1000/upperdir и /private/1000/workdir соответственно. Процесс монтирования overlay аналогичен следующей командной строке:
mount -t overlay overlay /usr \
-o lowerdir=/usr,upperdir=/private/1000/upperdir,workdir=/private/1000/workdir
(0) rocker created
После подготовки новой среды rocker RockerGuard уведомляет RockerClient.
(1) fork out a child process, (2) setns(USER|MNT|PID)
RockerClient создаёт дочерний процесс, который входит в новую среду rocker через системный интерфейс setns.
(3) run App in child's brother process
В дочернем процессе, созданном на шаге (1), создаётся ещё один дочерний процесс для запуска переднего плана приложения.
Этот новый дочерний процесс фактически является братом дочернего процесса, созданного на шаге (1). Он реализуется через клонирование с флагом CLONE_PARENT, и его родительский процесс совпадает с родительским процессом дочернего процесса на шаге (1). Таким образом, AppMaster может получать сигналы SIGCHLD при завершении процесса приложения, как описано в clone(2).
(4) PID of guard\App
RockerClient отправляет AppMaster информацию о PID RockerGuard и приложения.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )