Многие DevOps-инженеры и системные администраторы, особенно успевшие поработать с Kubernetes, уже слышали про проект CRI-O, озаглавленный как «легковесная исполняемая среда для контейнеров в Kubernetes». Однако зачастую представления о его назначении, возможностях и статусе весьма размыты — из-за молодости проекта, отсутствия опыта практического применения и растущего числа изменений в области стандартов для контейнеров. Эта статья — ликбез о CRI-O, рассказывающая о появлении проекта, его особенностях и актуальном статусе.
История появления
Следуя за растущей популярностью применения Linux-контейнеров, в середине 2015 года некоммерческая организация The Linux Foundation при содействии CoreOS, Docker, Red Hat и ряда других компаний представила проект Open Container Project, который ныне известен как Open Container Initiative (OCI). Его цель — «создание открытых индустриальных стандартов для форматов и исполняемой среды контейнеров».
Предполагалось, что проект объединит базу конкурирующих продуктов для контейнеров, таких как runc от Docker и appc от CoreOS, в единые стандарты. Актуальным же итогом деятельности OCI стал выпуск минувшим летом версии 1.0 для двух стандартов:
- для исполняемой среды контейнеров (Runtime Specification, runtime-spec) — определяет, как запускается «комплект файловой системы» (filesystem bundle) с содержимым контейнера (эталонная реализация — тот самый runc);
- для формата образов контейнеров (Image Specification, image-spec) — определяет формат, из которого образ контейнера будет распакован в filesystem bundle (для дальнейшего запуска).
В то же самое время и независимо от Open Container Initiative, но «с акцентом на продвижение стандартов для контейнеров через OCI», компания Red Hat занялась созданием OCID (Open Container Initiative Daemon), поместив его в инкубатор проекта Kubernetes и анонсировав в сентябре 2016 года.
В рамках OCID инженеры Red Hat собирались развивать инновации в области контейнеров: исполняемой среды, распространения образов, хранилища, их подписи и т.п. При этом проект позиционировался как «не конкурирующий с Docker», потому что «в действительности он использует ту же исполняемую среду OCI runc, что применяется в Docker Engine, тот же формат образов и позволяет использовать docker build
и относящиеся к нему инструменты».
Уже тогда OCID назывался «реализацией стандартного интерфейса для исполняемой среды для контейнеров в Kubernetes», в котором следуют философии UNIX, когда одна утилита выполняет одну задачу. Поэтому функциональность OCID была сразу разбита по следующим компонентам:
- OCI Container Runtime Environment (runc);
- OCI Runtime Tools (развиваемый в OCI набор утилит для работы с runtime-spec);
- containers/image (набор библиотек на языке Go для работы с образами контейнеров и реестрами — эти возможности также доступны через консольную утилиту skopeo, созданную в Red Hat для Project Atomic);
- containers/storage (библиотека на Go, предоставляющая методы для хранения слоёв файловой системы, образов контейнеров и самих контейнеров; включает в себя обёртку с консольным интерфейсом);
- CNI (Container Network Interface) (спецификация и библиотеки для управления сетевыми интерфейсами в контейнерах — подробнее о CNI мы писали в этой статье).
Однако название «OCID», напрямую ссылающееся на инициативу OCI, не получило одобрения в самой Open Container Initiative, поскольку к списку официальных проектов OCID не относился. И уже вскоре после первого анонса, по требованию OCI, проект получил новое название — CRI-O («CRI» расшифровывается как «Container Runtime Interface»).
По существу можно сделать вывод, что OCI стала необходимой предтечей для CRI-O, а в Red Hat воспользовались трендом стандартизации, способствуя ему с одной стороны и преследуя свои цели (низкоуровневый стек для Project Atomic и OpenShift) — с другой. Сообщество Linux и Open Source от этого скорее только выиграло, получив конкуренцию и разнообразие среди свободных продуктов, да и в OCI подчеркнули, что их недовольство было связано исключительно с названием проекта, но не самим его назначением:
«Open Container Initiative (OCI) сосредоточена на создании формальной спецификации для исполняемой среды и формата образов контейнеров, поскольку стандартизация в этих областях будет способствовать и другим инновациям. Любые другие проекты на данный момент выходят за рамки OCI, однако мы поощряем своих участников, продолжающих работу над спецификацией для исполняемой среды и формата образов, поскольку это полезно для всей индустрии. Инновации быстро происходят на уровне реализации, и мы намерены интегрировать все уместные улучшения в спецификации. Наша цель — поддерживать эффективный рост и здоровье технологии контейнеров и всего сообщества Open Source».
По сей день Red Hat продолжает продвигать CRI-O в мире ИТ-специалистов, примером чему может служить недавняя (июнь 2017 г.) публикация «6 причин, почему CRI-O — лучшая исполняемая среда для Kubernetes» в блоге Project Atomic. В качестве таких причин авторы называют:
- Открытая схема управления проектом и его развитие в рамках сообщества «родительского» Kubernetes.
- «По-настоящему открытый проект», что подтверждается приятной цитатой от Intel:
… а также активностью контрибьюторов, переносом некоторых улучшений в кодовую базу самого Kubernetes. - Минимальная кодовая база (доступная для простого аудита и достаточно надёжная), остальные компоненты к которой подключаются от других проектов.
- Стабильность, достигаемая благодаря полной ориентированности на Kubernetes, использованию upstream-тестов из K8s (node-e2e и e2e) перед принятием патчей (если релиз CRI-O ломает что-то в K8s, он блокируется), а также своих интеграционных тестов.
- Безопасность, т.к. в нём доступны все необходимые для Kubernetes функции вроде SELinux, Apparmor, seccomp, capabilities.
- Использование стандартизированных компонентов, т.к. проект следует спецификациям OCI.
Другой пример технологического евангелизма в этом направлении — совсем свежий (сентябрь 2017 г.) доклад «Понимая стандарты для контейнеров» (видео, слайды) в исполнении Scott McCarty из Red Hat:
Но вернёмся к технологической составляющей CRI-O. Как же устроен этот проект?
Архитектура и особенности CRI-O
На сегодня, благодаря усилиям Red Hat, Intel, SUSE, Hyper и IBM (все они числятся среди основных компаний-разработчиков CRI-O), мы получили альтернативу Docker для Kubernetes, позволяющую запускать поды с использованием любой исполняемой среды для контейнеров, совместимой со спецификацией OCI. Официально при этом поддерживаются всем известная runc, а также Clear Containers от Intel (являются частью более глобального проекта Clear Linux; в прошлом месяце выпустили их версию 3.0, переписанную на Go).
Компоненты CRI-O практически не изменились со времён анонса OCID: помимо исполняемой среды (совместимой с OCI) это прежние OCI Runtime Tools, containers/storage, containers/image, CNI, а также новая небольшая утилита conmon, предназначенная для мониторинга контейнеров (включая обнаружение ошибок нехватки памяти — OOM) и обработки журналирования из процесса контейнера.
Общая же архитектура CRI-O и его место в Kubernetes представляется следующим образом:
Принцип функционирования Kubernetes в связке с CRI-O сводится к следующей схеме:
- Kubernetes обращается к kubelet для запуска пода, а kubelet перенаправляет этот запрос к демону CRI-O через интерфейс Kubernetes CRI.
- CRI-O с помощью библиотеки containers/image забирает образ из реестра.
- CRI-O с помощью библиотеки containers/storage распаковывает загруженный образ в корневую файловую систему контейнера (хранимую в COW).
- Создав rootfs для контейнера, CRI-O с помощью утилиты generate из OCI Runtime Tools готовит JSON-файл, соответствующий спецификации OCI runtime и содержащий описание, как запустить контейнер.
- CRI-O запускает исполняемую среду (например, runc) с использованием созданной спецификации.
- Контейнер попадает в поле зрения мониторинга, осуществляемого с помощью утилиты conmon (отдельный процесс в системе), которая также обслуживает логирование для контейнера и записывает код завершения процесса контейнера.
- Сеть для пода настраивается с помощью любого из плагинов CNI.
Статус
Последний публичный релиз CRI-O — 1.0.0-rc3, выпущенный на прошлой неделе. Среди его изменений выделяются поддержка Minikube (для запуска CRI-O с локальным кластером Kubernetes), лимиты для размера лога контейнера, поддержка квоты для overlay, возможность запуска на файловых системах на базе tmpfs. Его анонс завершается фразой, что «теперь мы близки к выпуску 1.0, как только количество багов уменьшится».
Релиз Kubernetes 1.8, который состоялся в конце сентября, «повысил» статус поддержки CRI-O до стабильного, поскольку были пройдены все тесты e2e.
Для перевода вашей инсталляции Kubernetes с Docker на CRI-O потребуется:
- Установить и настроить CRI-O (
/etc/crio/crio.conf
,/etc/containers/policy.json
и т.п.; сам сервис запускается как системная служба — рекомендуется в связке с systemd) на каждом узле, где осуществляется миграция. - Исправить требования службы kubelet в systemd (
/etc/systemd/system/kubelet.service
) и настроить её параметры (/etc/kubernetes/kubelet.env
). - Подготовить плагин CNI.
- Запустить сервис crio и перезапустить kubelet.
Более подробную инструкцию можно найти здесь.
cri-containerd
Напоследок, нельзя не упомянуть параллельную активность со стороны компании Docker под названием cri-containerd. Это ещё одна Open Source-реализация уже упомянутого интерфейса Kubernetes CRI для тех, кто выбрал containerd в качестве единственной исполняемой средой для контейнеров (вместе с теми же runc и CNI для решения соответствующих задач). Имея статус альфа-версии, cri-containerd поддерживает Kubernetes 1.7+, прошла все тесты на валидацию с CRI и все тесты node e2e.
На недавнем выступлении Liu Lantao (Google) и Abhinandan Prativadi (Docker) было объявлено, что бета-версию ожидают к концу года (слайды доклада):
P.S.
А в завершении такой статьи не могу не привести цитату Kelsey Hightower, хорошо известного в DevOps-сообществе как минимум благодаря «Kubernetes The Hard Way»:
cri-o, containerd, rkt или docker? С нетерпением жду дня, когда ответом будет: «Всё равно».
Читайте также в нашем блоге:
- «Зачем нужен containerd и почему его отделили от Docker»;
- «В чём суть проекта Moby и почему главным репозиторием Docker вдруг стал moby/moby?»;
- «Container Networking Interface (CNI) — сетевой интерфейс и стандарт для Linux-контейнеров»;
- «Наш опыт с Kubernetes в небольших проектах» (видео доклада, включающего в себя знакомство с техническим устройством Kubernetes).
Автор: shurup