Все мы знаем, что технология контейнеров на самом деле появилась давно, но только в последнее десятилетие она постепенно стала достоянием общественности благодаря развитию облачных вычислений. Для среды выполнения контейнера в традиционном смысле он представляет собой весь жизненный цикл контейнера от извлечения образа до запуска и работы до завершения, что больше похоже на среду выполнения горячей точки Java в Java. В этой статье я представлю связанные концепции и принципы работы компонентов среды выполнения контейнеров и разберу взаимосвязь между терминами, которые мы часто слышим, такими как OCI, runc и containerd.
Что такое среда выполнения контейнера
Как следует из названия, среда выполнения контейнера должна контролировать весь жизненный цикл работы контейнера.В качестве примера докер, как система в целом, предоставляет следующие основные функции:
- Сформулировать формат образа контейнера
- Создайте образ контейнера
docker build
- Управление образами контейнеров
docker images
- Управление экземплярами контейнера
docker ps
- запустить контейнер
docker run
- Зеркалирование Достичь общего контейнера
docker pull/push
Однако эти функции могут быть реализованы небольшими компонентами независимо, и нет взаимозависимости. Затем Docker вместе с COREOS и Google создали OCI (открытый контейнер начальный) и предоставил два спецификация:
- Спецификация времени выполнения (https://github.com/opencontainers/runtime-spec)
опишите как запуститьfilesystem bundle
- Спецификация изображения (https://github.com/opencontainers/image-spec)
Разработать формат изображения, операцию и т. д.
пакет файловой системы: определяет формат для кодирования контейнера как пакета файловой системы, набора файлов, организованных определенным образом и содержащих необходимые данные для всех соответствующих исполняющих сред для выполнения над ним всех стандартных операций и метаданных, т.е. config.json с корневой файловой системой .
После этого Docker, Google и другие компании открыли исходный код инструмента и библиотеки runc для запуска контейнеров в качестве эталона реализации для OCI. После этого также потихоньку появлялись различные runtime-инструменты и библиотеки, такие как rkt, containerd, cri-o и т. д. Однако у этих инструментов разные функции, некоторые только запускают контейнеры (runc, lxc), а кроме того, некоторые еще и могут управлять изображения (контейнеры, кри-о). Более популярный аргумент заключается в том, что среда выполнения контейнера делится на две категории: низкоуровневую и высокоуровневую.
низкоуровневый: относится только к среде выполнения контейнера, которая запускает контейнер, вызывает операционную систему и использует пространства имен и контрольные группы для достижения изоляции и ограничения ресурсов. высокий уровень: включает дополнительные функции верхнего уровня, такие как вызовы grpc, управление хранилищем изображений и т. д.
Соотношение между различными инструментами следующее:
low-level runtime
Низкоуровневая среда выполнения фокусируется на том, как взаимодействовать с операционной системой для создания и запуска контейнеров. В настоящее время распространенными низкоуровневыми средами выполнения являются:
- lmctfy — это проект Google, представляющий собой среду выполнения контейнера, используемую Borg.
- runc — наиболее широко используемая на сегодняшний день среда выполнения контейнеров. Первоначально он был разработан как часть Docker, а затем был выделен как отдельный инструмент и библиотека. Он реализует спецификацию OCI и содержит файл config.json и корневую файловую систему контейнера.
- rkt — популярная альтернатива Docker/runc, разработанная CoreOS, предоставляющая все функции, предлагаемые другими низкоуровневыми средами выполнения, такими как runc.
Контейнеры используют nameapce для реализации изоляции ресурсов в Linux и используют cgroup для реализации ограничений ресурсов.Основы k8s — контейнерные статьиЭтот принцип подробно описан в , и здесь повторяться не буду. Здесь мы подробно опишем, как создать простую среду выполнения.
Мы используем образ busybox в качестве корневой файловой системы для среды выполнения, сначала создаем временный каталог и извлекаем все файлы из busybox в каталог.
CID=$(docker create busybox)
ROOTFS=$(mktemp -d)
docker export $CID | tar -xf - -C $ROOTFS
Ограничение нам нужно создать cgroup для ограничения памяти и процессора
UUID=$(uuidgen)
cgcreate -g cpu,memory:$UUID
# 内存限制设置为 100MB
cgset -r memory.limit_in_bytes=100000000 $UUID
# cpu 限制设置为 512m
cgset -r cpu.shares=512 $UUID
надcpu.shares
это ЦП по отношению к другим процессам, работающим в то же время. Контейнеры, работающие в одиночку, могут использовать весь ЦП, но если другие контейнеры работают, они будут распределять ресурсы ЦП пропорционально. Кроме того, вы также можете ограничить использование количества ядер процессора:
# 设置检查CPU使用情况的频率,单位是微秒
cgset -r cpu.cfs_period_us=1000000 $UUID
# 设置任务在一个时间段内在一个核心上运行的时间量,单位是微秒
cgset -r cpu.cfs_quota_us=2000000 $UUID
Затем мы используемunshare
Команда выполняет команду в cgroug, что может обеспечить изоляцию пространства имен.
cgexec -g cpu,memory:$UUID \
> unshare -uinpUrf --mount-proc \
> sh -c "/bin/hostname $UUID && chroot $ROOTFS /bin/sh"
/ echo "Hello from in a container"
Hello from in a container
Наконец, после завершения выполнения очистите среду с помощью следующей команды
cgdelete -r -g cpu,memory:$UUID
rm -r $ROOTFS
Практика этой части в основном относится к статье https://www.ianlewis.org/en/container-runtimes-part-2-anatomy-low-level-contai
high-level runtime
Среды выполнения высокого уровня находятся выше по стеку, чем среды выполнения низкого уровня. Среды выполнения низкого уровня отвечают за фактический запуск контейнера, в то время как среды выполнения высокого уровня отвечают за передачу и управление образом контейнера, распаковку образа и передачу его средам выполнения низкого уровня для запуска контейнера. Текущие основные высокоуровневые среды выполнения:
- docker
- containerd
- rkt
Здесь мы берем containerd в качестве примера для анализа всей архитектуры и принципа работы.
containerd
Схема архитектуры containerd показана на рисунке
Среди них модуль grpc предоставляет сервисный интерфейс для верхнего уровня, а metrics предоставляет данные мониторинга (данные, связанные с cgroup), оба из которых предоставляют услуги для верхнего уровня. В containerd есть демон, который предоставляет интерфейс grpc через локальный сокет UNIX.
Часть хранения отвечает за хранение образа, управление, извлечение и другое управление метаданными контейнера и метаданными образа, которые хранятся на диске через задачу bootio — управляет логической структурой контейнера, взаимодействует с низкоуровневыми событиями — событиями, которые работают в контейнерах Верхний уровень может узнать, что произошло, подписавшись.
Основной процесс containerd выглядит следующим образом:(Картинка взята из общедоступного курса Alibaba Cloud)
containerEngine на рисунке — это компонент docker-containerd в докере, который создает метаданные записи контейнера и запрашивает модуль задачи containerd.Модуль задачи создаст экземпляр задачи во время выполнения, который будет добавлен в список задач и контролировать контрольные группы и другие операции.Каждая задача Экземпляр вызывает оболочку для создания контейнера.
containerd-shim
containerd-shim — это компонент containerd, в основном используемый для удаления демона containerd и процесса контейнера. containerd запускает контейнер, вызывая функцию пакета runc через файл shim. когда мы выполняемpstree
команда, вы можете увидеть следующие отношения процесса:Введите shim, чтобы разрешить запуск runc после создания и запуска контейнера, и используйте shim в качестве родительского процесса контейнера вместо containerd в качестве родительского процесса. Цель этого состоит в том, что когда процесс containerd зависает, поскольку прокладка все еще работает нормально, контейнер может быть гарантированно не затронут. Кроме того, прокладка также может собирать и сообщать о статусе выхода контейнера без необходимости для containerd ждать процесса контейнера.
Когда нам нужно заменить библиотеку инструментов времени выполнения runc, например, заменить контейнер kata контейнера безопасности или gViser, разработанный Google, нам нужно добавить соответствующую прокладку (kata-shimд.), оба из которых имеют собственную реализацию прокладки.
В настоящее время существует две версии shim v1 и shim v2.Что касается того, как K8s использует CRI для взаимодействия с containerd и shim, эта часть будет представлена в следующем посте блога. Если вам это нравится, пожалуйста, подпишитесь на мою официальную учетную запись или проверьте мой блог http://packyzbq.coding.me, Я буду время от времени присылать свои собственные учебные записи, и каждый может учиться друг у друга и общаться друг с другом ~