Docker-образ и контейнер: слои, теги и жизненный цикл
Основы4 минРедакция Innovialabs
Коротко
Docker-образ — неизменяемый шаблон из read-only слоёв, а контейнер — запущенный экземпляр этого образа с собственным тонким слоем для записи; контейнеры создаются, запускаются, останавливаются и удаляются независимо от образа.
Образ и контейнер в одном предложении
Образ (image) — это шаблон: упакованная файловая система плюс метаданные (команда по умолчанию, переменные окружения, порты). Контейнер — процесс, запущенный из этого шаблона, со своим состоянием. Отношение как у класса и объектов: один образ — много контейнеров.
- Собранный образ не меняется.
- Каждый контейнер получает поверх образа слой для записи (writable layer), куда попадают все его изменения файлов.
- Удаление контейнера удаляет этот слой, но не образ.
Слои: из чего состоит образ
Каждая инструкция Dockerfile, меняющая файловую систему (RUN, COPY, ADD), создаёт новый read-only слой. Слои накладываются друг на друга и переиспользуются между образами.
FROM node:20-alpine # слои базового образа
WORKDIR /app
COPY package*.json ./ # слой: манифесты зависимостей
RUN npm ci # слой: node_modules
COPY . . # слой: код приложения
CMD ["node", "server.js"] # только метаданные, без нового слоя
Почему это важно на практике:
- Кэш сборки: если изменился только код, Docker пересоберёт лишь последний слой
COPY. Поэтому файлы зависимостей копируют раньше остального кода. - Экономия места: десять образов
FROMодной базы хранят её один раз. - Удалённые файлы всё равно весят: удаление файла в следующем слое лишь скрывает его, но не уменьшает предыдущие. Чистите в том же
RUN, где файлы появились, или используйте multi-stage сборку.
Посмотреть слои образа:
docker history myapp:1.4
docker image inspect myapp:1.4 --format '{{json .RootFS.Layers}}'
Слой для записи
При запуске контейнера Docker добавляет тонкий writable-слой поверх read-only слоёв образа (copy-on-write). Любой файл, который контейнер меняет, копируется в этот слой.
Что из этого следует:
- Данные, записанные внутри контейнера, пропадают при его удалении. Для баз данных, загрузок и всего, что должно сохраниться, используйте volumes или bind mounts.
- Два контейнера из одного образа не видят изменений друг друга.
docker diff <container>показывает, что изменилось относительно образа.
Теги и digest
Тег — удобное для человека и подвижное имя: nginx:1.27, myapp:latest. Завтра тот же тег может указывать на другой образ.
Digest — хэш содержимого образа: nginx@sha256:.... Он неизменяем: один и тот же digest всегда означает одни и те же байты.
| Тег | Digest | |
|---|---|---|
| Пример | myapp:1.4 | myapp@sha256:3f1a... |
| Может измениться | Да, можно перезалить | Нет |
| Для чего | Людям, названия релизов | Воспроизводимые деплои, аудит |
Практические правила:
- Не используйте
latestв продакшене — непонятно, что реально запущено. - Тегируйте образы версией или SHA коммита из CI.
- Фиксируйте digest, когда важна воспроизводимость, например в манифестах Kubernetes для критичных сервисов.
docker images --digests
docker inspect --format '{{index .RepoDigests 0}}' myapp:1.4
Жизненный цикл контейнера
Контейнер проходит понятные состояния: created → running → (paused) → exited → removed.
docker create --name web myapp:1.4 # создан, не запущен
docker start web # работает
docker stop web # SIGTERM, затем SIGKILL по таймауту: exited
docker start web # снова работает, тот же writable-слой
docker rm web # удалён, writable-слой исчез
docker run — это просто create + start одной командой. Флаг --rm удалит контейнер автоматически после завершения.
Как проверить каждый этап:
docker ps # запущенные контейнеры
docker ps -a # все, включая остановленные
docker inspect web # состояние, mounts, сеть, код выхода
docker logs web # stdout/stderr основного процесса
docker image ls # локальные образы
Частые ошибки
- Относиться к контейнеру как к серверу: ставить пакеты внутри работающего контейнера. При пересоздании изменения исчезнут. Меняйте Dockerfile и пересобирайте.
- Хранить данные без volumes и терять их после
docker rmили нового деплоя. - Полагаться на
latestи получать на другой машине другой образ. - Копить остановленные контейнеры и «висячие» образы. Регулярно чистите через
docker container pruneиdocker image prune, предварительно проверив, что будет удалено.