Образы контейнеров и контейнеры, созданные на их основе, используют технологию многоуровневой файловой системы при работе с файлами, которые они содержат.
Многоуровневая файловая система представляет собой подход к созданию содержимого файловой системы, используемой контейнером. Принцип заключается в том, что содержимое файловой системы строится как набор уровней, каждый из которых содержит определенный набор каталогов и файлов, и все из них имеют общий корневой каталог. Каталоги и файлы передаются с каждого уровня по очереди, начиная с базового нижнего уровня и продвигаясь к верхним. Каждый последующий уровень может не только добавлять новые файлы, но также может заменять файл нижнего уровня файлом другой версии или даже удалять («уничтожать») файл нижнего уровня.
Наличие нескольких уровней в файловой системе позволяет эффективно работать с файлами в образах контейнеров. Такой принцип организации файлов также является хорошим решением для создания образов контейнеров, учитывая, что приложения, как правило, в качестве зависимостей используют программные стеки, которые позволяют их запускать.
В качестве примера рассмотрим приложение node.js. Программный код приложения node.js может находиться в файле сценария app.js, а также в других файлах сценария, файлах данных и файлах конфигурации. Приложение node.js имеет зависимость от среды выполнения node.js и ряда (внешних) пакетов. В свою очередь, среда выполнения node.js зависит от различных библиотек ОС.
В образе контейнера для приложения node.js это может быть отображено с помощью трех уровней (начиная с самого верхнего):
- сценарий app.js и связанные с ним программные компоненты составляют самый верхний уровень;
- среда выполнения node.js и связанные с ней пакеты образуют следующий уровень;
- библиотеки ОС образуют нижний уровень.
Следует отметить, что ядро ОС не обязательно должно присутствовать в образе контейнера. Ядро ОС предоставляется ОС хоста, на которой работают контейнеры.
Разделение на уровни позволяет организовать эффективный процесс построения (создания) образов контейнеров. Можно создать образ контейнера с одним уровнем, содержащим все необходимые файлы, но гораздо эффективнее будет разделить программный стек, используемый приложением, на отдельные уровни. Это связано с тем, что приложение и все его зависимости обычно представляют собой отдельные независимые наборы файлов, что описывается в примере на основе приложения node.js.
Образ контейнера может быть создан с использованием другого образа контейнера в качестве основы (или родительского объекта). Поэтому, если снова обратиться к примеру с приложением node.js, первым созданным образом контейнера может быть образ для ОС. Затем можно создать второй образ контейнера для среды выполнения node.js и связанных с ней пакетов, используя образ ОС в качестве родительского объекта. Наконец, третий образ контейнера может быть создан для приложения app.js с использованием в качестве родительского объекта среды выполнения node.js. Родительские образы создают нижние уровни для нового образа, построенного поверх них. Поэтому в этом примере библиотеки ОС становятся самым нижним уровнем, среда выполнения node.js — средним уровнем, а приложение app.js — самым верхним уровнем.
Такая модель организации позволяет каждому образу решать только свои собственные задачи. Например, если среде выполнения node.js не нужны все файлы из библиотек ОС, она может удалить ненужные файлы. Таким образом, при создании образа контейнера основной вопрос заключается в том, какой (какие) базовый(ые) образ(ы) использовать.
Многоуровневая организация файловой системы также применяется и к контейнерам, но с одним отличием. Когда контейнер создается из образа контейнера, формируются те же уровни файловой системы, что и в образе контейнера, но они рассматриваются как доступные только для чтения. Эти уровни называются уровнями образа. Приложение, работающее в контейнере, не может изменять файлы на уровнях образа. Однако поверх уровней, присутствующих в образе контейнера, добавляется дополнительный записываемый уровень — он называется уровнем контейнера (в отдельных контейнерных средах он называется уровнем «песочницы»). Все изменения в файлах, внесенные работающим в контейнере приложением, записываются на уровне контейнера, будь то создание новых файлов, изменение существующих или удаление ненужных файлов. Это подразумевает принцип копирования при записи для файлов в контейнере.
В результате использования уровней образа, предназначенных только для чтения, и принципа копирования при записи уровни образа могут совместно использоваться различными контейнерами. Это позволяет экономить на хранении данных и памяти во время выполнения и сократить время запуска контейнеров [из 7.3.2 Многоуровневая файловая система ГОСТ Р 70860—2023]