Добавить в корзинуПозвонить
Найти в Дзене
Цифровая Переплавка

🛠️ Создаём контейнерный образ вручную: магия слоёв и внутренняя кухня контейнеров

Многие разработчики привыкли использовать Docker, Podman и другие контейнерные инструменты как нечто само собой разумеющееся. Мы пишем Dockerfile, запускаем docker build и получаем готовый образ. Но что происходит под капотом этой команды? Как из нескольких строчек конфигурации получается полноценный контейнер с собственной файловой системой? Оказывается, собрать образ можно даже вручную, буквально «из ничего». Именно такой подход описал датский разработчик Дэниш Пракаш, решив продемонстрировать, как именно устроен контейнерный образ и что происходит при его создании. 🔍 Что на самом деле такое контейнерный образ? Начнём с небольшой предыстории. Раньше не было единого стандарта для контейнеров. Каждый инструмент работал по своим правилам, и это создавало проблемы совместимости. В 2015 году возникла Инициатива открытых контейнеров (Open Containers Initiative - OCI), которая стандартизировала форматы контейнеров и образов. Теперь большинство инструментов, таких как Docker и Podman, следу

Многие разработчики привыкли использовать Docker, Podman и другие контейнерные инструменты как нечто само собой разумеющееся. Мы пишем Dockerfile, запускаем docker build и получаем готовый образ. Но что происходит под капотом этой команды? Как из нескольких строчек конфигурации получается полноценный контейнер с собственной файловой системой?

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

🔍 Что на самом деле такое контейнерный образ?

Начнём с небольшой предыстории. Раньше не было единого стандарта для контейнеров. Каждый инструмент работал по своим правилам, и это создавало проблемы совместимости. В 2015 году возникла Инициатива открытых контейнеров (Open Containers Initiative - OCI), которая стандартизировала форматы контейнеров и образов. Теперь большинство инструментов, таких как Docker и Podman, следуют OCI-спецификации.

OCI-образ состоит из четырёх основных компонентов:

📦 Слои (layers) – изменения в файловой системе, представленные в виде архивов tar.gz. Каждый слой хранит только разницу с предыдущим слоем, что позволяет экономить место и ускорять загрузку образов.

⚙️ Конфигурация (config.json) – настройки запуска контейнера: точка входа (entrypoint), переменные окружения, открытые порты и другие параметры.

📑 Манифест (manifest.json) – карта, которая связывает слои и конфигурацию между собой, используя хеши (SHA256).

🗂️ Индекс (index.json) – верхнеуровневая структура, описывающая несколько манифестов (например, для поддержки разных архитектур).

Создание образа «Hello World» вручную

Чтобы понять внутреннее устройство контейнера, Дэниш предлагает сделать собственный простой образ на основе пустого образа (scratch):

FROM scratch
COPY ./hello /
ENTRYPOINT ["./hello"]

Здесь:

  • 📍 scratch – полностью пустой базовый образ.
  • 📍 COPY добавляет бинарный файл hello.
  • 📍 ENTRYPOINT указывает, что нужно выполнить этот бинарник при запуске контейнера.

🧩 Как формируются слои?

Слои – это просто архивы tar с изменениями файловой системы. Например, если мы хотим удалить файл /bin/ash и заменить его на /bin/bash, создаётся архив с файлами:

  • /bin/bash – новый файл
  • /bin/.wh.ash – специальный файл («whiteout»), показывающий удаление старого файла ash.

Эти архивы накладываются друг на друга, формируя единую файловую систему контейнера.

📂 Пошаговая структура образа OCI

Для нашего примера с «Hello World» необходимо:

🔨 Шаг 1: Скомпилировать простой статический бинарник на C:

#include <stdio.h>

int main(int argc, char *argv[]) {
if (argc < 2) {
printf("Usage: %s <name>\n", argv[0]);
return 1;
}
printf("Hello, %s!\n", argv[1]);
return 0;
}

Компиляция:

gcc -o hello hello.c -static
tar -czvf layer.tar.gz hello
sha256sum layer.tar.gz
mv layer.tar.gz <полученный-хеш>

🔨 Шаг 2: Создание конфигурационного файла (config.json):

{
"architecture": "amd64",
"os": "linux",
"config": {
"Entrypoint": ["./hello"]
}
}

Затем также делаем этот файл адресуемым по содержимому (SHA256):

sha256sum config.json
mv config.json <полученный-хеш>

🔨 Шаг 3: Создание манифеста (manifest.json), связывающего слой и конфигурацию по хешам:

{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"digest": "sha256:<хеш-config>",
"size": <размер-конфигурации>
},
"layers": [{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"digest": "sha256:<хеш-layer>",
"size": <размер-слоя>
}]
}

🔨 Шаг 4: Создание индекса (index.json), который ссылается на манифест:

{
"schemaVersion": 2,
"manifests": [{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:<хеш-манифеста>",
"size": <размер-манифеста>,
"annotations": {
"org.opencontainers.image.ref.name": "hello:scratch"
}
}]
}

🖥️ Тестирование созданного вручную образа

Собираем всё вместе в архив и загружаем через Podman:

tar -cf hello.tar blobs index.json
podman load < hello.tar
podman run localhost/hello:scratch world

Вывод:

Hello, world!

🔥 Личное мнение автора: зачем нам это нужно?

Казалось бы, зачем разбираться так подробно? Однако понимание того, как именно устроен образ контейнера, помогает лучше осознать, какие слои можно оптимизировать и как уменьшить размер итогового образа. Это особенно полезно:

✅ Для оптимизации ресурсов (экономия памяти, диска).
✅ Для безопасности (контроль содержимого каждого слоя).
✅ Для гибкости в CI/CD-процессах (кастомные сборки, проверки).

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

🚀 Итог и рекомендации

Изучение внутреннего устройства контейнеров – не просто интересный технический эксперимент, это ещё и путь к профессиональному росту. Разбираясь в OCI-образах, вы получите реальный контроль над тем, что происходит в ваших контейнерах, а значит, и в ваших приложениях.

Не бойтесь копать глубже – именно в таких деталях кроется истинное мастерство.

🔗 Оригинальная новость