[Из песочницы] VM или Docker?
Как понять, что вам нужен Docker, а не VM? Нужно определить, что именно вы хотите изолировать. Если требуется изолировать систему с гарантированно выделенными ресурсами и виртуальным аппаратным обеспечение, тогда выбор должен пасть на VM. При необходимости изолировать работающие приложения как отдельные процессы системы, вам потребуется Docker.
Так в чём же отличие Docker-контейнеров от VM?
Виртуальная машина (VM) — это виртуальный компьютер со всеми виртуальными устройствами и виртуальным жёстким диском, на который и устанавливается новая независимая ОС вместе с виртуальными драйверами устройств, управлением памятью и другими компонентами. Т. е. мы получаем абстракцию физического оборудования, позволяющую запускать на одном компьютере множество виртуальных компьютеров.
Установленная VM может по-разному занимать место на диске компьютера:
- фиксированное место на жёстком диске, что позволяет осуществлять более быстрый доступ к виртуальному жёсткому диску и позволяет избежать фрагментации файла;
- динамическое выделение памяти. При установке дополнительных приложений память будет динамически выделяться под них, пока не достигнет максимального объема, отведенного ей.
Чем больше виртуальных машин на сервер, тем больше места они занимают, а также требуют постоянной поддержки окружения, требующегося для работы вашего приложения.
Docker — это ПО для создания приложений на основе контейнеров. Контейнеры и виртуальные машины имеют схожие преимущества, но работают по-разному. Контейнеры занимают меньше места, т.к. переиспользуют большее количество общих ресурсов хост-системы чем VM, т.к. в отличие от VM, виртуализируют ОС, а не аппаратное обеспечение. Такой подход обеспечивает меньший объем занимаемой памяти, быстрое развертывание и более простое масштабирование.
Контейнер даёт более эффективный механизм инкапсуляции приложений, обеспечивая необходимые интерфейсы хост-системы. Данная возможность позволяет контейнерам разделить ядро системы, где каждый из контейнеров работает как отдельный процесс основной ОС, у которого есть свой собственный набор областей памяти (собственное виртуальное адресное пространство). Так как виртуальное адресное пространство каждого контейнера является собственным, то данные, принадлежащие разным областям памяти, не могут быть изменены.
Нативной ОС для Docker является Linux (Docker можно использовать также и на Windows, и на MacOS), он использует её основные преимущества, которые и позволяют ему организовать разделение ядра. Запуск Docker-контейнеров на Windows будет происходить внутри виртуальной машины с ОС Linux, т.к. контейнеры разделяют ОС хост-системы и основной ОС для них является Linux.
Контейнер — как это работает?
Контейнер — это абстракция на уровне приложения, объединяющая код и зависимости. Контейнеры всегда создаются из образов, добавляя доступный для записи верхний слой и инициализирует различные параметры. Т. к. контейнер имеет свой собственный слой для записи и все изменения сохраняются в этом слое, несколько контейнеров могут совместно использовать доступ к одному и тому же основному образу.
Каждый контейнер можно настроить через файл в проекте docker-compose, включенного в основное решение — docker-compose.yml. Там можно задать различные параметры такие как имя контейнера, порты, идентификаторы, лимиты ресурсов, зависимости между другими контейнерами. Если в настройках не задавать имя контейнера, то Docker каждый раз будет создавать новый контейнер, присваивая ему имя случайным образом.
Когда контейнер запускается из образа, Docker монтирует файловую систему для чтения и записи поверх любых слоев ниже. Именно здесь будут выполняться все процессы, которые мы хотим, чтобы наш контейнер Docker выполнял.
Когда Docker впервые запускает контейнер, начальный слой чтения-записи пуст. Когда происходят изменения, они применяются к этому слою; например, если вы хотите изменить файл, этот файл будет скопирован из слоя только для чтения ниже в слой для чтения и записи.
Версия файла, доступная только для чтения, все еще будет существовать, но теперь она скрыта под копией. Для хранения данных, независимо от жизненного цикла контейнера, используются тома. Тома инициализируются при создании контейнера.
Как образ связан с контейнером?
Образ — основной элемент для каждого контейнера. Образ создаётся из Dockerfile, добавленного в проект и представляет собой набор файловых систем (слоёв) наслоённых друг на друга и сгруппированных вместе, доступных только для чтения; максимальное число слоёв равно 127.
В основе каждого образа находится базовый образ, который указывается командой FROM — входная точка при формировании образа Dockerfile. Каждый слой является readonly-слоем и представлен одной командой, модифицирующей файловую систему, записанной в Dockerfile.
Для сочетания этих слоёв в один образ Docker использует union file system (UnionFS), позволяя ранзным файлам и директориям из разных файловых систем прозрачно накладываться, создавая связанную файловую систему.
Слои содержат метаданные, позволяющие сохранять сопутствующую информацию о каждом слое во время выполнения и сборки. Каждый слой содержит ссылку на следующий слой, если слой не имеет ссылки, значит это самый верхний слой в образе.
Dockerfile может содержать такие команды как:
- FROM — входная точка при формировании образа;
- MAINTAINER — имя владельца образа;
- RUN — выполнения команды в ходе сборки образа;
- ADD — копирование файла хоста в новый образ, если указать URL-файла, Docker загрузит его в заданную директорию;
- ENV — переменные среды;
- CMD — запускает создание нового контейнера на основе образа;
- ENTRYPOINT — команда выполняется при запуске контейнера.
- WORKDIR — рабочий каталог для выполнения команды CMD.
- USER — устанавливает UID для создаваемого на основе образа контейнера.
- VOLUME — монтирует директорию хоста в контейнер.
- EXPOSE — набор прослушиваемых в контейнере портов.
Как работает UnionFS?
UnionFS — служебная стэковая файловая система (ФС) для Linux и FreeBSD. Данная ФС реализует механизм копирования при записи (Copy-On-Write, COW). Рабочей единицей UnionFS является слой, каждый слой следует рассматривать как отдельную полноценную файловую систему с иерархией директорий от самого корня. UnionFS создаёт объединенное монтирование для других файловых систем и позволяет прозрачно для пользователя объединять файлы и каталоги различных файловых систем (называемых ветвями) в единую связанную файловую систему.
Содержимое каталогов с одинаковыми путями будет отображаться вместе в одном объединенном каталоге (в едином пространстве имён) полученной файловой системы.
UnionFS объединяет слои, руководствуясь следующими принципами:
- один из слоёв становится слоем верхнего уровня, второй и последующие — слоями нижнего уровня;
- пользователю объекты слоёв доступны «сверху вниз», т.е. если запрошенный объект есть в «верхнем» слое, возвращается он, независимо от наличия объекта с таким именем в «нижнем» слое; иначе возвращается объект «нижнего» слоя; если запрошенного объекта нет ни там, ни там, возвращается ошибка «Нет такого файла или каталога»;
- рабочим слоем является «верхний», то есть все действия пользователя по изменению данных отражаются только на слое верхнего уровня, не влияя на содержимое слоёв нижних уровней.
Docker наиболее распространенное технология использования контейнеров в работе приложения. Он стал стандартом в этой области, строясь на основе cgroups и пространстве имён, которые обеспечивает ядро Linux.
Docker позволяет нам быстро разворачивать приложения и максимально оптимально использовать файловую систему за счет разделения ядра ОС между всеми контейнерами, работая как отдельные процессы ОС.