В наши дни практически ни один Интернет-сайт или сервис не может обойтись без серверной составляющей. Той частью экосистемы, которая отвечает за хранение и обработку данных. Чем больше спектр задач, решаемый сервисом, тем сложнее и больше программных компонент работает на его серверной стороне.
Для работы над установкой, настройкой и обновлением серверных компонент требуется большой уровень компетенции системного администратора, а также большое количество человеко-часов в случае возникновения следующих гипотетических ситуаций:
– Потеря данных на дисковом массиве — требуется инсталлировать всю систему заново;
– После обновления какого-либо компонента на новую версию появились сбои в работе;
– Руководство решило мигрировать на новые сервера или работать с другой хостинговой компанией.
В дополнении к вышеперечисленным сложностям, все компоненты системы работают в одном и том же окружении, и не изолированы друг от друга, что приводит к повышению рисков, связанных как с действиями самих разработчиков, так и с угрозами извне.
Одним из решений проблемы изоляции компонент системы друг от друга и, в том числе, от корневой операционной системы является использование виртуальных машин. Однако, здесь существует несколько основных недостатков:
- Производительность ивремя загрузки. Как известно, дополнительный слой виртуализации между физическими устройствами ввода-вывода добавляет дополнительную работу центральному процессору, и, как следствие, отрицательно влияет на производительность системы в целом;
- Размер образа. При каждом обновлении, пусть даже самом незначительном, например, изменении в одной строке файла исходного кода, требуется полная замена образа, что сказывается на времени развертывания и увеличении трафика при загрузки образа на сервер.
- Сложность совместного использовании ресурсов. Зачастую, не все виртуальные машины умеют и имеют возможность настройки совместного использования общих ресурсов между собой. Включая использование виртуальной сети между разными образами.
Решить, описанные выше проблемы помогает Docker, который позволяет использовать среду виртуализации на уровне операционной системы. [1]
Как и в случае виртуальной машины, Docker выполняет процессы в своей, заранее сконфигурированной операционной системе. Основное отличие в том, что процессы фактически работают на физическом Host сервере, разделяя доступные ресурсы с другими процессами, работающими в Host системе.
Подход докера находится посередине, между полной виртуализацией и выполнением задач на Host машине. Это подход называется контейнеризацией, а образы, используемые в Docker — контейнерами. На Рис. 1 показана структура и основные компоненты системы, характерные для Docker-архитектуры.
Рис. 1. Схема составляющих систем в Docker-архитектуре
Одним из основных понятий в терминологии докера является image (или образ). Для создания образа используются специальный файл — Dockerfile. В нем содержатся команды, необходимые для построения образа. Для примера, рассмотрим Dockerfile для образа Node.js [2] приложения (Рис. 2).
Рис. 2. Dockerfile образа Node.js приложения
На первой строке обычно указывается имя и версия образа для наследования. В этом примере мы берем за основу официальный образ с предустановленной платформой Node.js на базе Alpine Linux (самый популярный и нетребовательный к ресурсам дистрибутив Linux сегодня) [3]. На 5–6 строках мы копируем необходимые файлы проекта в образ при помощи директивы ADD. Далее, используя директиву RUN, мы можем исполнять любые команды, которые поддерживает операционная система образа, в итоге, на 10 строке устанавливаем NPM зависимости проекта.
После того как нами был построен docker image можно приступать к созданию из него контейнеров на любом физическом сервере, где установлен Docker. Если image — это тиражируемый образ некоторой «машины», то container это уже сама «машина», которую можно запускать и останавливать.
При запуске, контейнеру можно передавать разнообразные параметры. Самым распространенным является передача переменных окружения, которые будут доступны программному компоненту, работающему внутри контейнера.
Представим, что наше Node.js приложение — это WEB-сервис, главной задачей которого является обработка запросов пользователя. Обычно, такой сервис включает в себя:
– Базу данных;
– Гибко настраиваемый HTTP сервер;
– Само приложение.
Для удобства оркестрации и совместного использования нескольких контейнеров в рамках одного Docker хоста, обычно используется утилита docker-compose. Она позволяет нам хранить конфигурацию в YML файле и выполнять операции с группой контейнеров. Рассмотрим пример docker-compose.yml файла (Рис. 3) для нашего сервиса.
Рис. 3. Пример файла docker-compose.yml
В контейнер приложения передается ссылка на внутренний IP адрес сервера базы данных, там образом мы используем функциональность сетевого взаимодействия между контейнерами, которую даем нам Docker. На строке 25 мы привязываем порт HTTP сервера Nginx из контейнера на интерфейс Host машины, тем самым делая его доступным извне. На строках 11 и 18 мы указываем версии контейнеров Nginx и MongoDB, которые соответствуют соответствующим версиям сервисов.
Для запуска всех контейнеров из YML файла достаточно выполнить команду: ”docker-compose up -d”, а для остановки “docker-compose stop”.
Таким образом, используя контейнерную архитектуру на сервере, мы получаем ряд важнейших преимуществ:
- Контролируемость. Все операции с контейнерами и набор команд в Docker-файле, позволяет разработчику видеть, из чего именно состоит система, контролировать процесс шагов для построения образа.
- Удобное версионирование. Очень просто изменить версию сторонних сервисов и перезапустить Docker контейнер. Более того, Docker-файлы могут храниться в системе контроля версий (например GIT) и быть неотъемлемой частью разработки.
- Предсказуемость. Сборка образов из Docker-файла позволяет избавиться от человеческих ошибок в процессе настройки сервисов.
- Гибкость. Использование и замена программных компонент между различными стадиями разработки: qa, staging и production может быть достигнуто простым изменением конфигурационных файлов, нет необходимости пересобирать весь образ целиком.
Литература:
- Docker. // What is Docker. URL: https://www.docker.com/what-docker (дата обращения: 23.11.2017)
- Alpine Linux. // Alpine Linux. URL: https://www.alpinelinux.org/about/ (дата обращения: 09.12.2017)
- Node.js. // About Node.js®. URL: https://nodejs.org/en/about/ (дата обращения: 02.11.2017).