Поскольку виртуальные машины уже хорошо изучены, начнем сравнение. Это удобный способ упаковать виртуальное железо, ядро и пространство пользователя. Контейнер же включает в себя только пространство пользователя, в нем нет виртуального железа и ядра.
Уровни абстракции при виртуализации и контейнеризации.
Виртуальные машины
Обычно разработчики делятся только копией кода или бинарника (вместо виртуальной машины). Делиться целой виртуальной машиной с другим разработчиком не так удобно из-за ее формата и размера. Передача только кода эффективнее, но влечет за собой неудобства из-за необходимости выполнения дополнительных настроек при развертывании программного обеспечения в среду разработки.
Программисты часто пишут код, требующий много дополнительных модулей (например, Ruby, PHP PECL, Python, Perl и т.д.). Некоторые из них установлены в операционной системе, но часто их нужно скачивать из внешних репозиториев, а некоторые даже компилировать из исходников на C/C++. Принимающие код разработчики, администраторы и архитекторы зачастую остаются один на один с проблемой установки соответствующих зависимостей. Чтобы облегчить эту задачу, были разработаны такие инструменты как RPM , RVM и Git , но сборка и развертывание – все еще довольно трудные задачи, требующие некоторых знаний и опыта вне сферы разработки приложений.
С другой стороны, многие системные администраторы и архитекторы предпочитают передавать виртуальные машины – это позволяет сохранить всю проделанную работу. Виртуальная машина обычно состоит из двух файлов: один для копии ядра и пространства пользователя, а второй включает определяющие ресурсы железа (ЦП, ОП, видеоадаптер и т.д.) метаданные, которые используются при запуске. При таком подходе для развертывания требуется проделать всего несколько шагов, но через некоторое время становится трудно отслеживать, что находится внутри образа виртуальной машины. Когда продавец ПО выпускает образ виртуальной машины, пользователи часто интересуются методологией ее создания, а также способами ее обслуживания, настройки и обновления. У каждого продавца могут быть различные способы входа в систему, смены пароля, настройки сервисов времени и настройки сетей. Хуже всего то, что почти всегда все эти настройки необходимо выполнять вручную.
Вот почему как передача только кода и даже передача целой виртуальной машины не могут стать идеальным решением. Неудивительно, что были разработаны помогающие объединить преимущества обеих методов инструменты. Kickstart, Chef и Puppet делают настройку серверов больше похожим на программирование (архитектура как код), а Vagrant создан, чтобы облегчить развертывание целой виртуальной машины на железе разработчиков.
Контейнеры – действующий способ
Обратите внимание на иллюстрацию: когда создается контейнер, используется системный вызов clone() , чтобы появился новый процесс. Clone похож на fork() , но позволяет новому процессу расположится внутри пространства имен ядра. Это дает процессу свое собственное имя хоста, адрес IP, точки монтирования, PID и т.д. Для каждого контейнера может создаваться свое пространство имен, позволяя им выглядеть и работать как виртуальные машины.
Системный вызов clone()
После создания контейнера процесс или процессы выполняются в чистом пользовательском пространстве, созданном в результате монтирования образа контейнера. Процессы внутри контейнера выполняют системные вызовы как и обычно вне контейнера. То, что может делать процесс внутри контейнера, ограничивается ядром. На изображении ниже показано, как первая команда выполняет системный вызов open() напрямую из пространства пользователя хоста, вторая команда вызывает open() через примонтированное пространство имен (внутри контейнера), а третья вызывает getid() из пространства имен процесса (внутри контейнера).
Системные вызовы из разных пространств имен
После достижения равенства инфраструктуры (ЦП, память, сетевые настройки, совместимость ядра) между окружениями, один и тот же образ контейнера можно запускать на ноутбуках разработчиков, серверах в датацентрах или на виртуальных машинах облачных провайдеров. Контейнеры обеспечивают преимущества для сотрудничества разработчиков, архитекторов, инженеров по тестированию и выпуску, а также системных администраторов в виде целого пространства пользователя, упакованного и доставленного в удобном и простом виде.
Заключение
Пространство пользователя очень важно, потому что находится в центре внимания большинства разработчиков и архитекторов. Независимо от того, пишете ли вы приложения на Ruby on Rails, Java или PHP PECL, которым требуются дополнительные библиотеки, контейнеры – это удобный способ упаковки и доставки приложения и всех его зависимостей в пространстве пользователя.
При разработке и развертывании традиционных приложений или современных микросервисов, использование образа контейнера (пользовательского пространства) в качестве основного способа взаимодействия при совместной работе дает всем, от разработчиков и системных администраторов до архитекторов и инженеров по выпуску, большую гибкость и возможность работать более эффективно.