Зачем нужен containerd и почему его отделили от Docker

В середине марта стало известно, что компания Docker предложила свой проект containerd независимому фонду Cloud Native Computing Foundation (кстати, произошло это одновременно с rkt от CoreOS). Событие последовало за обещанием компании, данным в декабре прошлого года, когда containerd был официально отделён от Docker Engine. Что же это за компонент и зачем его отделили?

0e4f3168824a4e5fbceb6f5ce88ef024.png

Как устроен containerd


containerd — это бывшая часть Docker, а ныне самостоятельное решение, реализующее исполняемую среду для запуска контейнеров. При его создании, как утверждают разработчики, они стремились к простоте, надёжности и портируемости.

«Физически» это демон на хост-системе, который управляет всем жизненным циклом контейнера: от получения и хранения образа до запуска контейнера (через runC — подробнее см. ниже) и контролирования его работы. С демоном containerd можно взаимодействовать по низкоуровневому gRPC API через локальный UNIX-сокет, а для экспериментов и отладки также доступна консольная утилита ctr (она тоже использует gRPC API). Исходный код написан на Go и доступен на GitHub под лицензией Apache License 2.0.

457dcd6e65cc42f0ad1df986341d8eec.png

Основные примитивы, с которыми работает containerd, — это bundles («комплекты») и контейнеры. Запуском контейнеров занимается runC — утилита, написанная на Go, использующая libcontainer и отделённая от Docker в 2015 году. Она работает в соответствии со спецификацией OCI Runtime Specification и запускает контейнеры как свои дочерние процессы. Для запуска требует только корневую файловую систему и конфигурацию (всё остальное: получение образа, его распаковка и т.п. — остаётся для неё «за кадром»).

Bundles содержат конфигурацию, метаданные и данные корневой файловой системы. Они являются дисковым представлением запущенного контейнера (в простейшем случае — это обычный каталог в ФС), которое можно переносить на другие системы, упаковывать и распространять. По сути всё устройство containerd заключается в том, чтобы координировать создание и запуск bundles.

Подробнее об архитектуре


Компоненты containerd образуют следующие подсистемы:
  1. Distribution — сервис, обеспечивающий получение образов контейнеров.
  2. Bundle — сервис, позволяющий извлекать (и упаковывать) bundles из дисковых образов.
  3. Runtime — сервис для запуска bundles (вызывает runC для запуска контейнеров с переданными им параметрами).

Каждая подсистема имеет один или несколько компонентов, реализующих её поведение. Именно к сервисам, предоставляемым подсистемами, и обращаются пользователи containerd через gRPC API.

Компоненты containerd, работающие одновременно с разными подсистемами, называются модулями и представлены следующими:

  • Executor, реализующий непосредственный запуск контейнера.
  • Supervisor, контролирующий и отражающий статус контейнера.
  • Metadata, хранящий метаданные в графовой базе данных.
  • Content, предоставляющий доступ к адресуемому хранилищу контента (постоянных данных).
  • Snapshot, управляющий снапшотами файловой системы для образов контейнера. Аналог graphdriver в сегодняшнем Docker. Слои распаковываются в снапшоты.
  • Events, реализующий событийное поведение и возможность аудита.
  • Metrics, обеспечивающий доступность (по API) метрик различных компонентов.

Всё вместе это выглядит так:
b7d8390cdd994fde91507ed849f9e1b8.png

Как это работает


Схема и её описание взяты из документа containerd/design/architecture:
image
  • В контроллер подсистемы Distribution приходит запрос забрать нужный образ. Он помещает содержимое образа в хранилище контента (Content store), а указатели на имя образа и корневой манифест регистрируются в хранилище метаданных (Metadata store).
  • Когда образ получен, пользователь может (через контроллер Bundle) распаковать образ в bundle. Слои этого образа (полученные из хранилища контента) распаковываются в модуль Snapshot.
  • Когда снапшот корневой системы контейнера готов, контроллер Bundle, используя манифест и конфиг образа, формирует конфигурацию для запуска (в частности, готовится список mount’ов, полученных из модуля Snapshot).
  • Подготовленный bundle передаётся в подсистему Runtime для запуска. Она считывает готовую конфигурацию для создания работающего контейнера.

Роль в Docker, связь с другими компонентами


Вынесение containerd в отдельный проект началось около года назад, когда разработчики Docker предприняли попытку »сделать Docker Engine компактнее, лучше, быстрее и сильнее» и так объясняли свои действия: «Имея автономную среду исполнения вроде runc, мы нуждались ещё в аккуратной точке для интеграции, чтобы добавить runc к общему стеку и управлять сотнями контейнеров».

На момент выделения containerd из Docker (1.12) в плане развития проекта значился «рефакторинг кодовой базы Docker Engine для выноса большей части логики размещения, сетевой работы и хранения на единственном хосте в компонент, предназначенный для многократного использования, который будет применяться в Docker и которым смогут пользоваться другие проекты оркестровки контейнеров и сервисы размещения контейнеров».

Набор функций, выполнение которых поручили containerd, получился следующим:

  • размещение образов в Docker Registry;
  • поддержка сети для создания системных интерфейсов и API для управления сетевым пространством имён контейнера;
  • хранилище (на уровне хоста) для файловых систем образа и контейнера;
  • gRPC API (именно по нему и сам Docker Engine общается с containerd);
  • новый API для метрик в формате Prometheus, используемых внутри и на уровне контейнера;
  • полная поддержка спецификации образов OCI (Open Container Initiative) и эталонной реализации runC.

Так в Docker видят использование будущего containerd 1.0 (его релиз запланирован на июнь 2017 года) внутри Docker Engine:

814df05373c64bac9c361c8e57e35239.png

Подводя итог, авторы утверждают, что в containerd сосредоточены возможности, в которых «нуждается любая ориентированная на контейнеры платформа», и ничего лишнего. По факту это достаточно низкоуровневое решение, взаимодействовать с которым предлагается не конечным разработчикам и пользователям, а более крупным системам, таким как Kubernetes (в рамках Kubelet) и Mesos, а также сервисам вроде Amazon ECS и Google Container Engine. Встраивание в продукты предлагается всё через тот же gRPC API (утилита ctr предназначена только для отладки и экспериментов).

P.S. На прошлой неделе Cloud Native Computing Foundation формально подтвердила принятие containerd в число своих проектов. И в тот же день такая участь постигла проект rkt, который решает аналогичные containerd задачи в CoreOS: является реализацией открытой спецификации App Container (appc) и использует формат ACI (Application Container Image) для образов. CNCF будет поддерживать развитие обоих проектов.

Комментарии (0)

© Habrahabr.ru