Материал переведен. Ссылка на оригинал

В первой статье из серии "Архитектура контейнеров" (перевод, оригинал на англ.) мы рассмотрели разницу между пользовательским пространством и пространством ядра. Сегодня мы продолжим изучение этой темы и посмотрим подробнее на пользовательское пространство.

Виртуальные машины и контейнеры

Виртуальная машина — это удобный способ упаковки виртуального оборудования, ядра (kernel space) и пользовательского пространства (user space). Контейнер, с другой стороны, абстрагирует только пользовательское пространство. В контейнере нет своего ядра или виртуального оборудования.

Виртуальные машины

Для совместной работы над проектом есть два основных подхода: использовать копии исходного кода или преднастроенные виртуальные машины. Хотя оба способа довольно распространены, у каждого из них есть преимущества и недостатки.

Разработчики обычно используют код и бинарные файлы вместо общей виртуальной машины, так как виртуальные машины неудобны из-за их размера и формата. Исходный код выигрывает с точки зрения размера, но при развертывании требует выполнения дополнительных действий. Разработанное программное обеспечение часто зависит от библиотек и фреймворков (например, Ruby, PHP PECL, Python, Perl и т.д.). Некоторые из них распространяются в виде пакетов операционной системы и часто загружаются из внешних репозиториев. Но бывают ситуации, когда их приходится компилировать. Другим разработчикам, администраторам и архитекторам нужно изучать установку этих зависимостей. 

Для упрощения жизни были разработаны такие инструменты, как RPM, git, RVM и др. Но процессы сборки и развертывания могут быть совсем нетривиальными и требовать дополнительных знаний (за рамками разработки приложения).

С другой стороны, архитекторы и системные администраторы часто используют виртуальные машины. Они позволяют легко сохранить выполненные настройки в виде готовых образов. 

Виртуальная машина обычно состоит из двух файлов: первый — это копия пользовательского пространства и ядра (виртуальный диск), второй — метаданные, определяющие доступные ресурсы (процессор, память, видеокарта и т.д.). Преимущество такого подхода заключается в очень простом деплое, а недостаток — со временем легко забыть, что находится внутри образа виртуальной машины. 

Когда вендор распространяет приложение в виде образов виртуальных машин, часто возникает вопрос о методологии их создания, а также об их поддержке, конфигурировании и обновлении. В каждом приложении используются свои подходы к аутентификации, изменению паролей, настройке служб и сети. Хуже того, эти настройки почти всегда выполняются вручную.

Таким образом, получается, что ни совместное использование "только кода", ни распространение "преднастроенных виртуальных машин" не является идеальным решением. Неудивительно, что появились инструменты, сближающие эти методологии. Kickstart, Puppet и Chef пытаются подойти к развертыванию серверов как к управлению кодом (инфраструктура как код, infrastructure as code). В то время как Vagrant предназначен для упрощения развертывания готовых виртуальных машин на компьютерах разработчиков.

И все-таки что использовать для совместной работы: код или полную виртуальную машину? Возможно есть другой способ? Читайте дальше!

Контейнеры

При запуске контейнера пользовательское пространство хоста, на котором запущен контейнер, выполняет системные вызовы в ядро для создания специальных структур (cgroups, svirt, namespaces). Контейнеры можно запускать как на полноценной Red Hat Enterprise Linux 7, так и на операционной системе, оптимизированной для контейнеров, например, Red Hat Enterprise Linux Atomic Host. В любом случае системные вызовы одинаковые.

На рисунке ниже показано, что при создании контейнера используется системный вызов clone(), который создает новый процесс. Clone похож на fork, но позволяет настроить пространство имен (namespace) для нового процесса. Благодаря пространствам имен каждый процесс может иметь собственное сетевое имя, IP-адрес, точки монтирования, идентификатор процесса и другие ресурсы. Для каждого контейнера можно создавать свое пространство имен, что делает их похожими на виртуальные машины.

После запуска экземпляра контейнера процесс или процессы выполняются в пользовательском пространстве, созданном в результате монтирования образа контейнера. Процессы внутри контейнера выполняют системные вызовы, как и прежде. Контролем того, что процессы могут делать в контейнере занимается ядро.

На рисунке ниже первая команда выполняет системный вызов open() из пользовательского пространства хоста, вторая — open() из контейнера в пространстве имен mount, а третья — getpid() также из контейнера, используя  пространство имен PID.

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

До тех пор, пока сохраняется инфраструктурный паритет (процессор, память, сеть, совместимость ядер) один и тот же образ контейнера можно запустить и на ноутбуке разработчика, и на серверах в датацентре и на виртуальных машинах в облаке. Преимущество контейнеров в том, что они предоставляют разработчикам, архитекторам, QA-инженерам, release-инженерам и системным администраторам удобный инструмент совместной работы, при котором все пользовательское пространство упаковывается и распространяется в простом и удобном виде.

Заключение

Большинство разработчиков и архитекторов работают в пространстве пользователя (user space). Независимо от того, разрабатываете ли вы приложения Ruby on Rails, Java или модули PHP PECL, которым требуются библиотеки C, контейнеры — это удобный способ упаковки и поставки приложения со всеми зависимостями пользовательского пространства.

Еще одним важным моментом является то, что в пользовательском пространстве работают все инструменты управления контейнерами.

И при разработке/развертывании монолитных приложений и при использовании современной микросервисной архитектуры, ориентация на контейнеры (на пользовательское пространство) позволяет всем — от разработчиков и системных администраторов до архитекторов и release-инженеров — получить большую гибкость и возможность более эффективной работы.

В следующей части этой серии (оригинал на англ. Architecting Containers Part 3: How the User Space Affects Your Application) мы рассмотрим, как связь между пользовательским пространством и пространством ядра влияет на ваше приложение.

Материал переведен. Ссылка на оригинал


Перевод материала подготовлен в рамках курса «Administrator Linux. Professional». Если вам интересно узнать о курсе подробнее, приглашаем на день открытых дверей онлайн. РЕГИСТРАЦИЯ

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