Зачем переписывать контейнерный рантайм на Си

26 авг 2026
4,076
438
52
2 недели

Попробуйте запустить Docker или Podman с ограничением по памяти в 512 килобайт. Стандартный рантайм runc на таком лимите просто упадёт с ошибкой. Ему не хватит памяти даже на то, чтобы поднять базовые структуры процесса и прочитать файловые дескрипторы.

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

Проект crun от организации Containers решает эту задачу в лоб. Это легковесная реализация спецификации OCI (Open Container Initiative), полностью написанная на чистом Си.

Что даёт переход на чистый Си

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

Реклама

Потребление памяти и запуск на грани лимитов

В бенчмарках разработчиков видна показательная разница:

# Запуск через runc падает
$ podman --runtime /usr/bin/runc run --rm --memory 4M fedora echo it works
Error: container_linux.go:346: starting container process caused "process_linux.go:327: getting pipe fds for pid 13859 caused \"readlink /proc/13859/fd/0: no such file or directory\"": OCI runtime command not found error

# Запуск через crun отрабатывает без запинки
$ podman --runtime /usr/bin/crun run --rm --memory 512k fedora echo it works
it works

Контейнер с crun стабильно запускается даже с жестким лимитом памяти в 512 КБ, тогда как runc спотыкается даже на 4 МБ. Для тяжелых микросервисов в облаке разница в мегабайт может показаться мелочью, но на IoT-устройствах, роутерах и edge-серверах такая экономия освобождает драгоценную память под полезную нагрузку.

Скорость последовательного старта

Когда требуется часто запускать короткоживущие задачи (например, в serverless-платформах или CI/CD раннерах), время инициализации контейнера становится узким местом. В тесте на последовательный запуск 100 контейнеров с командой /bin/true разница во времени почти двукратная:

| Рантайм | Время выполнения (100 контейнеров) | Разница | | :--- | :--- | :--- | | crun | 0:01.69 | -49.4% | | runc | 0:03.34 | базовый уровень |

Си-реализация стартует в два раза быстрее за счёт отсутствия оверхеда инициализации среды Go и лишних системных вызовов.

Использование в виде библиотеки

Большинство рантаймов существуют только как отдельные исполняемые файлы. Если вам нужно запустить OCI-контейнер из своей программы, обычно приходится делать fork/exec и вызывать внешнюю утилиту.

В crun есть возможность собрать разделяемую библиотеку libcrun. Это открывает прямой C API для работы с контейнерами:

  • встраивание запуска изолированных окружений внутрь собственных демонов
  • отсутствие накладных расходов на вызовы отдельных процессов
  • работа с биндингами для Python и Lua прямо из коробки

Сборка и установка

Утилита доступна в большинстве дистрибутивов через штатные пакетные менеджеры, но собрать её из исходников тоже несложно.

Для сборки на Ubuntu понадобятся базовые заголовочные файлы:

$ sudo apt-get install -y make git gcc build-essential pkgconf libtool \
   libsystemd-dev libprotobuf-c-dev libcap-dev libseccomp-dev libjson-c-dev \
   go-md2man autoconf python3 automake

Сам процесс компиляции стандартный:

$ ./autogen.sh
$ ./configure
$ make
$ sudo make install

Если планируете использовать библиотеку в коде, флаг конфигуратора изменится на ./configure --enable-shared.

Для воспроизводимых окружений и серверов без лишних зависимостей проект поддерживает статическую сборку через Nix Flakes:

$ nix --extra-experimental-features "nix-command flakes" build "path:.#crun-static-amd64"
$ ./result/bin/crun --version

На выходе получается компактный статический бинарник под x86_64 с glibc, который готов работать на любой целевой машине.

Кому пригодится

Переключаться на crun имеет смысл в нескольких сценариях:

  1. Edge computing и IoT. Когда на устройстве распаяно 256 МБ или 512 МБ оперативной памяти, отдавать мегабайты под рантайм непозволительно.
  2. Serverless и Functions-as-a-Service. В средах с частым созданием и уничтожением изолированных контейнеров ускорение старта на 50% напрямую снижает задержки cold start.
  3. Плотная упаковка контейнеров. Если на одном хосте крутятся сотни мелких воркеров, суммарная экономия RAM исчисляется гигабайтами.

Подменить рантайм в Podman можно буквально одним флагом --runtime /usr/bin/crun или изменением параметра в /etc/containers/containers.conf. Никаких правок в манифестах или образах при этом не требуется.

🍪 Мы используем файлы cookie и сервис аналитики Яндекс.Метрика, чтобы сайт работал лучше. Продолжая пользоваться devtrends.ru, вы соглашаетесь с обработкой данных согласно Политике конфиденциальности.