🐧 Проектирование контейнеров (часть 2): в чем важность пространства пользователя?

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

Продолжаем публикацию перевода цикла статей с сайта RedHat о проектировании контейнеров.

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

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

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

Уровни абстракции при виртуализации и контейнеризации.

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

Сейчас ИТ-инфраструктура часто базируется на виртуальных машинах. Когда люди собираются сотрудничать над проектом, у них есть два основных способа разделить работу. Можно поделиться копией кода или передать целую виртуальную машину. Оба метода похожи и у каждого есть преимущества и недостатки.

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

Программисты часто пишут код, требующий много дополнительных модулей (например, Ruby, PHP PECL, Python, Perl и т.д.). Некоторые из них установлены в операционной системе, но часто их нужно скачивать из внешних репозиториев, а некоторые даже компилировать из исходников на C/C++. Принимающие код разработчики, администраторы и архитекторы зачастую остаются один на один с проблемой установки соответствующих зависимостей. Чтобы облегчить эту задачу, были разработаны такие инструменты как RPM, RVM и Git , но сборка и развертывание – все еще довольно трудные задачи, требующие некоторых знаний и опыта вне сферы разработки приложений.

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

Вот почему как передача только кода и даже передача целой виртуальной машины не могут стать идеальным решением. Неудивительно, что были разработаны помогающие объединить преимущества обеих методов инструменты. Kickstart, Chef и Puppet делают настройку серверов больше похожим на программирование (архитектура как код), а Vagrant создан, чтобы облегчить развертывание целой виртуальной машины на железе разработчиков.

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

Контейнеры – действующий способ

Когда контейнер создается впервые, пространство пользователя хоста производит системные вызовы, чтобы создать специальные структуры данных внутри ядра (cgroups, svirt, namespaces). При этом на хосте может быть установлена полная версия RHEL, оптимизированный для контейнеризации вариант ELAH или любой другой дистрибутив GNU/Linux – системные вызовы одинаковы в любом случае.

Обратите внимание на иллюстрацию: когда создается контейнер, используется системный вызов clone(), чтобы появился новый процесс. Clone похож на fork(), но позволяет новому процессу расположится внутри пространства имен ядра. Это дает процессу свое собственное имя хоста, адрес IP, точки монтирования, PID и т.д. Для каждого контейнера может создаваться свое пространство имен, позволяя им выглядеть и работать как виртуальные машины.

Системный вызов clone()

После создания контейнера процесс или процессы выполняются в чистом пользовательском пространстве, созданном в результате монтирования образа контейнера. Процессы внутри контейнера выполняют системные вызовы как и обычно вне контейнера. То, что может делать процесс внутри контейнера, ограничивается ядром. На изображении ниже показано, как первая команда выполняет системный вызов open() напрямую из пространства пользователя хоста, вторая команда вызывает open() через примонтированное пространство имен (внутри контейнера), а третья вызывает getid() из пространства имен процесса (внутри контейнера).

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

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

Заключение

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

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

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

Источники

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ

Библиотека программиста
12 июля 2017

Что такое Docker, и как его использовать? Подробно рассказываем

Разберем по косточкам, ведь Docker – это мощный инструмент, и огромное коли...
Библиотека программиста
30 декабря 2016

10 лучших ресурсов для изучения хакинга с помощью Kali Linux

Подборка 10 отличных ресурсов для изучения хакинга с помощью Kali Linux.<em...