Новости

Что такое контейнеризация: разбираемся

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

Обратимся к истории

Первые реализации идеи появились еще в 1980-х на системах UNIX, тогда предлагалось переопределить корневой каталог. Дальнейшее развитие технология получила вместе с распространением интернета. В 2000-х годах сначала частные компании, а затем разработчики ядра Linux предложили инструменты для создания изолированных сред для отдельного пользователя, тогда же появился сам термин «контейнер». Массовое внедрение контейнеризации в ИТ началось с появлением системы Docker в 2013 году. На текущий момент использование контейнеров в ИТ-инфраструктуре составляет около 90%.

Для чего нужна контейнеризация

Контейнеризация избавляет разработчиков от проблем с зависимостями от внешних библиотек: при запуске программы создается полноценная изолированная среда для выполнения приложения. Такой подход преследует сразу множество целей.

Задачи контейнеризации

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

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

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

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

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

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

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

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

Типы контейнеров

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

Контейнеры приложений

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

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

Контейнеры операционной системы

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

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

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

Инструменты для контейнеризации

Инструменты для сборки и запуска образов:

Docker — самая популярная платформа для запуска и сборки контейнеров.

Podman — главный конкурент Docker от Red Hat, основное отличие — отсутствие управляющего фонового процесса (демона).

Buildah — инструмент для создания образов, в отличие от Docker собирает образ без его запуска.

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

CRI-O — легковесный движок для оркестратора Kubernetes.

Оркестраторы:

Docker Swarm — часть платформы Docker, позволяет создавать кластеры контейнеров, подходит для небольших и средних проектов.

Kubernetes — продвинутый оркестратор для больших проектов, умеет работать с несколькими движками одновременно.

OpenShift — оркестратор для платформы Red Hat.

Совместимость между образами, движками и оркестраторами возможна благодаря общим стандартам консорциума OCI.

Как устроен контейнер

Контейнер — это образ, содержащий в себе не только основное приложение, но и все необходимые библиотеки. Для запуска приложения используется контейнерный движок: он создает необходимую среду для выполнения, изолированную от основной системы. За управление отвечает контейнерный клиент или оркестратор.

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

Преимущества контейнеризации

Скорость развертывания и разработки. Контейнеризация позволяет запускать одно и то же приложение без предварительной настройки и установки зависимостей. Такой подход сокращает время на разработку, отладку и тестирование приложения.

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

Безопасность. Изоляция приложений повышает защищенность, а также поддерживает принцип «один контейнер — один сервис». При правильной настройке атака на одну программу не выйдет за пределы изолированной среды и не затронет другие приложения и операционную систему.

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

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

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

Недостатки контейнеризации

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

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

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

Запуск тяжеловесных приложений. Развертывание сложных программ, таких как большие базы данных или системы управления, иногда невозможно, так как требует доступа к системным функциям и аппаратным ресурсам.

Чем контейнеризация отличается от виртуализации

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

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

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

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

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

Безопасность контейнеров: риски и способы защиты

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

Основные угрозы для контейнерных сред

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

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

Атака на интерфейсы взаимодействия контейнеров. Ряд атак бывает направлен на преодоление изоляции контейнеров, а также на управляющие элементы — контейнерный движок и оркестратор.

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

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

Как обеспечить безопасность контейнеров

Настроить права пользователей

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

Ограничить взаимодействие контейнера с окружением

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

Использовать проверенный источник образов

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

Задействовать средства мониторинга

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

Ограничить доступ к управлению контейнерами

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

Своевременно обновлять контейнеры и движок

Использование актуальных версий библиотек внутри контейнера сокращает количество уязвимостей. Обновление управляющих элементов также повышает безопасность.

Где применяется контейнеризация: основные кейсы

Контейнер в ИТ предусматривает множество сценариев использования. Большая их часть связана с применением на серверах и рабочих станциях. Воспроизводимость и портативность дает возможность реализовать идеи, невыполнимые другими методами.

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

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

Мониторинг и управление. Изолированность контейнеров позволяет настраивать и управлять каждой единицей в отдельности. Для этого существует несколько программ, самый популярный инструмент для масштабных проектов — оркестратор, вроде Kubernetes. Книга Джиджи Сайфана «Осваиваем Kubernetes» поможет разобраться с работой на уровне кластеров контейнеров и управлением ими.

Масштабируемость и облачные сервисы. Воспроизводимость контейнеров дает использовать их для развертывания целых кластеров небольших сервисов, что применимо в облачных технологиях. Каждый сервис может иметь необходимое количество запущенных копий для покрытия текущей нагрузки. Частный случай — использование обучаемых моделей ИИ.

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

Автоматизация обновлений ПО. К контейнеризации применима методология разработки CI/CD, при которой часть задач автоматизирована. Проверку на уязвимости, тестирование, доставку и развертывание приложений, использующих контейнеры, можно выполнять без непосредственного участия человека.

Написание приложений для IoT. Контейнеры применимы для использования и распространения на устройствах с урезанной версией операционной системы — таких как хабы умного дома, роутеры, умные колонки и другое.

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

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