Из чего состоит Docker-образ и какова его структура?

Ответ

Docker-образ — это неизменяемый (immutable) шаблон, который содержит все необходимое для запуска приложения: код, рантайм, системные инструменты, библиотеки и настройки. Его структура основана на концепции слоев (layers).

Ключевые компоненты Docker-образа:

  1. Файловые слои (Filesystem Layers)

    • Образ состоит из набора слоев, доступных только для чтения (read-only).
    • Каждая инструкция в Dockerfile (например, FROM, RUN, COPY, ADD) создает новый слой поверх предыдущего.
    • Каждый слой представляет собой изменения в файловой системе (добавленные, измененные или удаленные файлы) по сравнению с нижележащим слоем.
    • Эта слоистая архитектура позволяет эффективно кэшировать сборку и экономить дисковое пространство, так как разные образы могут использовать общие слои.
  2. Манифест образа (Image Manifest)

    • Это JSON-файл, который описывает образ. Он действует как "оглавление".
    • Манифест содержит ссылки на все слои, из которых состоит образ, а также на его конфигурационный объект.
  3. Конфигурация образа (Image Configuration)

    • Это еще один JSON-объект, который хранит метаданные, необходимые для запуска контейнера из этого образа.
    • Включает в себя такие параметры, как:
      • Cmd и Entrypoint: команда, которая будет выполнена при запуске контейнера.
      • Env: переменные окружения.
      • ExposedPorts: порты, которые приложение слушает внутри контейнера.
      • WorkingDir: рабочая директория по умолчанию.

Пример связи с Dockerfile

# 1. Базовый слой (содержит ОС Alpine)
FROM alpine:3.14

# 2. Новый слой: копирование файлов приложения
COPY app /app

# 3. Новый слой: установка пакета curl
RUN apk add --no-cache curl

# 4. Метаданные (часть конфигурации образа)
CMD ["/app/run"]

Когда из этого образа запускается контейнер, Docker создает поверх всех read-only слоев образа новый, записываемый слой (writable layer), также известный как "контейнерный слой". Все изменения, которые происходят во время работы контейнера (создание, изменение, удаление файлов), записываются в этот верхний слой.

Ответ 18+ 🔞

Давай разберем, что это за зверь такой — Docker-образ. Представь себе, что это как законсервированная банка с твоим приложением, которую можно открыть и запустить где угодно, и там внутри уже всё есть: код, софт, настройки — полный комплект, сука. И самое главное — он неизменяемый, то есть как отлили, так и стоит, никто внутри по пьяни ничего не накосячит.

А состоит эта банка из слоёв, как торт "Наполеон", только для гиков.

1. Слои файловой системы (Filesystem Layers) Каждая строчка в инструкции Dockerfile — это новый слой. Скачал базовую систему (FROM) — слой. Скопировал файлы (COPY) — ещё слой. Установил какую-нибудь хуйню типа curl (RUN) — опять слой. И все эти слои только для чтения, их не перепишешь. Зато это гениально: если у двух образов одинаковые нижние слои, они не дублируются на диске. Экономия, блядь, места — святое дело.

2. Манифест образа (Image Manifest) Это типа оглавления к этому многослойному торту. JSON-файлик, который говорит: "эй, Docker, чтобы собрать этот образ, тебе нужны вот эти вот слои, в таком порядке". Без него — пиздец, непонятно, что куда складывать.

3. Конфигурация образа (Image Configuration) А это уже настройки запуска, тоже в JSON'е. Тут прописано, что делать с этой банкой, когда её откроешь:

  • Какую команду выполнить (Cmd / Entrypoint) — типа "запусти сервер, блядь".
  • Какие переменные окружения выставить (Env).
  • Какие порты слушать (ExposedPorts).
  • В какой папке внутри работать (WorkingDir).

Как это всё вместе собирается, на живом примере

Смотри, вот простой Dockerfile:

# 1. Базовый слой (содержит ОС Alpine)
FROM alpine:3.14

# 2. Новый слой: копирование файлов приложения
COPY app /app

# 3. Новый слой: установка пакета curl
RUN apk add --no-cache curl

# 4. Метаданные (часть конфигурации образа)
CMD ["/app/run"]

Собираем образ. Получается торт из трёх read-only слоёв (Alpine, файлы, curl) и конфигурации сверху.

А теперь магия: когда ты из этого образа запускаешь контейнер, Docker накидывает поверх всех этих статичных слоёв ещё один, последний, записываемый слой. Вот в него-то и пишется всё, что происходит в работающем контейнере: создал файл, изменил конфиг, нахуямирил логи. Живёт этот слой ровно столько, сколько живёт контейнер. Убили контейнер — и этот верхний слой, как душа грешника, испаряется к хуям. А базовый образ остаётся чистеньким и неизменным. Красота, ёпта!