October 7, 2022

Контейнеризация приложений: что это такое и когда стоит использовать

Контейнеризация «позволяет писать приложения один раз и запускать их где угодно». (IBM)

Что такое контейнер и чем эта технология удобна для разработчиков приложений

Контейнер приложения — экземпляр исполняемого программного обеспечения (ПО), который объединяет двоичный код приложения вместе со всеми связанными файлами конфигурации, библиотеками, зависимостями и средой выполнения.

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

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

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

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

В качестве упражнения попробуйте выполнить без контейнеров процесс миграции ПО на с одной ОС на другую:
1. Развернуть на ВМ Centos 8 steam - MongoDB 4.4
2. Создать базу с одной коллекцией и одним документом с любым содержимым
3. Перенести на Ubuntu 22.04 - MongoDB и базу (Спойлер - MongoDB 4.4 не получится установить из-за openssl 3й версии. Требуется первая версия. Которую можно поставить, но процесс очень не простой и точно не рекомендуемый даже для среды разработки.)

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

Например, на сервере с Ubuntu Linux запущены контейнеры с приложениями, которым требуется Alpine Linux, а также другие контейнеры с приложениями, которым необходима определенная версия Debian.

Чтобы лучше понять, чем хороши контейнеры, стоит сравнить их с виртуальными машинами.

В чем разница между контейнерами и виртуальными машинами

1. Виртуальные машины — абстракция на уровне физического оборудования, превращает один сервер в несколько

На каждой виртуальной машине (ВМ) отдельная гостевая операционная система работает поверх операционной системы хоста с виртуализированным доступом к базовому оборудованию. Виртуальные машины с разными ОС могут работать на одном физическом сервере: ВМ UNIX может работать вместе с ВМ Linux и так далее. Микроядро и система виртуализации, которые создают и запускают виртуальные машины, называются гипервизорами или мониторами ВМ. Это то, что находится между оборудованием и ВМ и необходимо для виртуализации сервера, а также для изоляции операционных систем друг от друга

2. Контейнеры — абстракция на уровне приложения, объединяет код и зависимости

Контейнеры устанавливаются поверх физического сервера и его ОС, например Linux или Windows. Каждый контейнер отделяет свое содержимое от операционной системы. Контейнеры «легкие» — весят всего мегабайты и запускаются за секунды, ведь они берут лишь небольшую часть памяти при совместном использовании ОС.

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

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

Безопасность контейнеров

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

Здесь нужно использовать решения, повышающие безопасность контейнеров:

  1. Добиться изолированности процессов с помощью принципа «каждый контейнер — для решения только одной задачи», его еще формулируют как «одно приложение — один контейнер».
  2. Не загружать готовые к использованию контейнеры из ненадежных источников, а в особых случаях использовать исключительно собственные непубличные репозитории с контейнерами (Container Registry), которые интегрируются в CI/CD-среды.
  3. Использовать внутренние функции сервиса контейнеризации по поиску уязвимостей во всем вспомогательном ПО — такое тестирование тоже легко автоматизируется в CI/CD-средах и позволяет исключить развертывание уязвимых контейнеров в продакшене.

Для чего подходит и не подходит контейнеризация

Контейнеризация не подходит: если для работы приложения требуется другая ОС, а не та, что установлена на сервере.

Контейнеризация подходит:

  • для упрощения процесса развертывания и сопровождения приложений;
  • для запуска небезопасного или непроверенного кода с целью тестирования или отладки — для этого контейнеры подходят в 99% случаев;
  • для запуска приложений, требующих другого дистрибутива ОС (системные контейнеры);
  • для передачи отдельных компонентов приложения между членами команды в ходе цикла «разработка — тестирование — внедрение» и быстрого внесения изменений;
  • для микросервисов, которые можно разрабатывать и обновлять независимо;
  • для горизонтально масштабируемых приложений — когда запускается несколько одинаковых контейнеров на текущих ресурсах без увеличения стоимости этих ресурсов. В отличие от вертикального масштабирования, где увеличение количества ядер CPU, объемов RAM, размера HDD на сервере стоит денег;
  • для модернизации и миграции существующих приложений в более современные среды.