Это перевод статьи Container runtimes Part 1: An Introduction to Container runtimes.
Автор оригинальной публикации: Ian Lewis.
Один из терминов, который вы часто слышите, имея дело с контейнерами — «container runtime» (далее «runtime» переводится как «среда запуска» — прим. переводчика). «Среда запуска контейнеров» может иметь различные значения для разных людей, так что нет ничего удивительного в том, что это такой сбивающий с толку и смутно понятный термин, даже в самом сообществе пользователей и разработчиков Docker.
Этот пост — первый в серии, которая состоит из 4 частей:
- Часть 1: Введение в среды запуска контейнеров: почему они так сбивают с толку?
- Часть 2: Глубокое погружение в низкоуровневые среды запуска (eng)
- Часть 3: Глубокое погружение в высокоуровневые среды запуска
- Часть 4: Среды запуска в Kubernetes и CRI
Этот пост объяснит что такое среды запуска контейнеров и откуда столько недопонимания. После этого я углублюсь в различные типы сред запуска контейнеров, что они делают и как они отличаются друг от друга.
(На картинке игра слов: Не уверен относится ли это к средам запуска Kubernetes контейнера, низкоуровневой среде запуска контейнера или продолжительности фильма — примечание переводчика)
По традиции, программист может понимать «runtime» либо как фазу жизненного цикла программы, во время которой она выполняется, либо как среду языка, которая поддерживает это выполнение. Примером здесь служит среда выполнения Java HotSpot. Последнее значения является ближайшим к «runtime» контейнера. Среда запуска контейнера ответственна за все фазы запуска контейнера, которые не занимаются непосредственным запуском самой программы. Как мы увидим далее в этой серии, среды запуска осуществляют различные уровни функций, но функция «запускает контейнер» для инструмента — в сущности всё, что нужно, чтобы назвать его средой запуска контейнера.
Если вы не слишком хорошо знакомы с контейнерами, познакомьтесь сначала с этими материалами и возвращайтесь:
- Что же именно такое контейнер: пространства имён и cgroups
- Cgroups, пространства имен и за их пределами: из чего сделаны контейнеры?
Почему среды выполнения контейнеров так сбивают с толку?
Docker был выпущен в 2013 и решил множество проблем разработчиков тем, что запускал контейнеры непрерывной цепочкой. Он включал в себя:
- Формат образа контейнера
- Метод для построения образов контейнеров (Dockerfile/docker build)
- Возможность управлять образами контейнеров (docker images, docker rm, etc.)
- Возможность управлять экземплярами контейнеров (docker ps, docker rm, etc.)
- Возможность делиться образами контейнеров (docker push/pull)
- Возможность запускать контейнеры (docker run)
Всё это время Docker был монолитной системой. Однако, ни одна из этих функций по-настоящему не зависела друг от друга. Каждая из них могла быть реализована в более мелких и специализированных инструментах, которые можно было бы использовать вместе. Каждый из инструментов мог работать вместе с остальными, используя общий формат, стандарт контейнера.
Из-за этого, Docker, Google, CoreOS и другие поставщики создали Open Container Initiative (OCI). После этого они отделили свой код для запуска контейнеров как инструмент и библиотеку, названную runc, и передали его OCI, как эталонную реализацию OCI спецификации среды запуска.
По началу вопрос что именно Docker передал OCI сбивал с толку. То что они передали было стандартным способом запуска контейнеров и больше ничем иным. Они не включили формат образа или протоколы получения/выгрузки образа контейнера из/в регистр образов (хранилище образов). Когда вы запускаете Docker контейнер, вот какие действия Docker на самом деле выполняет:
- Загрузка образа.
- Распаковка образа в «пакет» (bundle). Это действие выравнивает слои в одну файловую систему.
- Запуск контейнера из пакета.
Тем, что Docker стандартизировал был только шаг №3. Пока это не было прояснено, все воспринимали среду запуска контейнера как систему поддерживающую все функции, которые поддерживает Docker. Со временем, ребята из Docker пояснили, что оригинальная спецификация утверждает, что только часть с «запуском контейнера» образует «среду запуска». Это разобщение, которое продолжается даже сейчас, делает «среды запуска контейнеров» такой запутанной темой. Я надеюсь показать, что обе стороны в какой-то мере правы, и буду использовать этот термин довольно широко в этом посте.
Низкоуровневые и высокоуровневые среды запуска контейнеров.
Когда разработчики думают о средах запуска контейнеров, то, вот, список некоторых примеров, которые могут прийти в голову: runc, lxc, lmctfy, Docker (containerd), rkt, cri-o. Каждый из них разработан для различных ситуаций и осуществляет различные функции. Некоторые, такие как containerd и cri-o, на самом деле используют runc для запуска контейнера, но осуществляют управление образами и имеют API поверх этого. Вы можете думать об этих функциях — которые включают в себя перенос образов, управление образами, распаковка образов и API — как о высокоуровневых функциях по сравнению с низкоуровневой реализацией в runc.
Держа это в уме, вы можете увидеть, что область среды запуска контейнера довольно сложна. Каждая среда запуска покрывает разные части этого спектра от низкоуровневого к высокоуровневому. Вот очень субъективная диаграмма:
На практике, среды запуска контейнеров, которые фокусируются просто на запуске контейнеров, обычно упоминаются как «низкоуровневые среды запуска контейнеров». Другие же среды запуска, поддерживающие функции более высокого уровня, такие как управление образами и различные gRPC/Web API, обычно упоминаются как «высокоуровневые инструменты контейнера», «высокоуровневые среды запуска контейнеров» или обычно просто как «среды запуска контейнеров». Я буду ссылаться на них как на «высокоуровневые среды запуска контейнеров». Важно заметить, что низкоуровневые и высокоуровневые среды запуска фундаментально различные вещи, которые решают различные проблемы.
Контейнеры реализованы с помощью механизмов пространств имен и cgroups Linux. Пространства имен дают вам возможности виртуализации системных ресурсов, таких как файловая система или работа с сетью, для каждого контейнера. Cgroups предоставляет путь ограничения количества ресурсов, таких как CPU и память, которые каждый контейнер может использовать. На самом низком уровне среды запуска контейнеров ответственны за настройку этих пространств имен и cgroups. Поддержка низкоуровневых сред запуска использует именно эти функции операционной системы.
Обычно разработчики, которые хотят запускать приложения в контейнерах, нуждаются в больших возможностях, чем предоставляют низкоуровневые среды запуска. Им необходимы API и функции вокруг форматов образов, управление образами и возможность делиться образами. Эти функции предоставляют высокоуровневые среды запуска. Низкоуровневные среды запуска просто не имеют достаточно возможностей для подобных ежедневных нужд. По этим причинам единственными кто будут использовать низкоуровневыми средами запуска будут разработчики высокоуровневых сред запуска и инструментов для контейнеров.
Разработчики низкоуровневых сред запуска скажут, что высокоуровневые среды запуска, такие как containerd и cri-o, на самом деле не среда запуска контейнера, так как с их точки зрения они делегируют выполнение запуска контейнера runc. Но с точки зрения пользователя они являются полноценными инструментами, которые предоставляют возможность запускать контейнеры. Одна реализация может поменяться на другую, так что имеет смысл называть их средой запуска с этой точки зрения. Несмотря на то, что containerd и cri-o оба используют runc — это два очень разных проекта с поддержкой очень разных функций.
В следующий раз...
Я надеюсь, что помог разобраться в том, что такое среды запуска контейнеров и почему их так сложно понять. Не стесняйтесь оставлять мне комментарии к статье (на сайте автора — прим. переводчика) или на Twitter и дайте мне знать, что в средах запуска контейнеров было самым трудным для понимания.
В следующем посте я уйду с головой в низкоуровневые среды запуска контейнеров. В нём я расскажу о том, что именно делают низкоуровневые среды запуска контейнеров. Я буду говорить как о популярных низкоуровневых средах запуска (таких как runc и rkt), так и о непопулярных, но важных (таких как lmctfy). Я даже пройдусь по тому, как запустить простую низкоуровневую среду запуска. Убедитесь, что подписались на мою RSS ленту или Twitter, чтобы получить оповещение когда выйдет следующий пост.
До этих пор вы можете включиться в сообщество Kubernetes через эти каналы:
- Отправляя и отвечая на вопросы на Stack Overflow
- Подписавшись на Twitter @Kubernetesio
- Присоединившись к Kubernetes Slack и общаясь с нами. (Я ianlewis так что скажи «Привет»!)
- Сделав вклад в Kubernetes на GitHub
Спасибо Sandeep Dinesh, Mark Mandel, Craig Box, Maya Kaczorowski и Joe Burnett за проверку черновиков этого поста.
От переводчика: я в свою очередь выражаю благодарность за проверку черновиков перевода пользователю GDApsy.
Комментарии (3)
Hixon10
06.03.2018 22:19Спасибо за перевод!
P.S. Интересно, а надо ли переводить термины? Среды запуска контейнеров — звучит очень больно :(Burrex Автор
07.03.2018 00:23Понимаю, тоже боролся с желанием оставить термины английскими. :) Дело в том, что «runtime», как «среда выполнения», вполне себе переводится в Википедии. А т.к. автор указывает, что это не совсем «среда выполнения», но близко — пришел к «среде запуска». «Среда» вовсе слово не общеупотребительное, а уж его склонения, поэтому наверно режет слух. :)
Тем более, мне кажется, этот термин хорошо передает сам смысл «runtime контейнера» и, что самое характерное, не вызывает вышеупомянутого в статье смутного понимания. Это не «время выполнения», не «среда выполнения», а именно «среда запуска», которая минимум «запускает контейнер».
AlexPu
Прочитал статью и почуствовал себя дебилом… На всякий случай прочитал ее еще раз — не помогло… я дебил