В целом, каждое изображение содержит свое родительское изображение, либо в виде встроенных байтов, либо в виде "жесткой" ссылки на изображение в локальном кэше, если оно уже там.
Под «родителем» я подразумеваю инструкцию FROM: someimage
в вашем Dockerfile.
Я также написал "hard", поскольку ссылка на самом деле представляет собой sha246-дайджест родительского изображения. Если какой-либо бит родительского изменится, дайджест будет другим.
Здесь есть три основных случая:
Вы начинаете с очистки кэша (docker image ls -a
ничего не показывает). Если у вас docker pull ...
какое-то изображение из публичного реестра, в него будет встроен родительский образ. A docker ps -a
должен показывать только одно изображение.
Если, однако, у вас уже есть родительское изображение в вашем кэше, docker pull ...
больше не будет загружать родительский образ. В этом случае вытащенное изображение имеет ссылку на родителя в вашем кэше.
Если вы строите локально из прозрачного кэша, Docker загрузит родительское изображение и создаст дочернее изображение со ссылкой на родителя.
Это все тот же результат в конце. Если вы замените родительское изображение более новой версией, дайджест не будет таким же.
Docker не позволит вам удалить изображение, если на него ссылается другое изображение. Когда вы помещаете свое изображение в реестр, родительский элемент внедряется (здесь я экономлю на поведении кэширования на стороне реестра). Я думаю, что вы также можете встроить родителя с помощью docker export
и docker import
, но я не пробовал. Например, docker export B
, затем удалите A и B из кеша докера, и docker import B
должно показать только одно изображение.
Вы можете получить фактические родительские отношения, используя
docker image inspect <image-id> | grep -E "Id|Parent"
объедините это с
docker image ls -a --digests
Для проверки отношений.
Еще немного информации.
При создании изображения выполняются следующие шаги:
- Контекст сборки отправляется хосту с помощью демона docker. Это в основном все файлы в каталоге, в котором находится ваш Dockerfile. Поэтому важно использовать
.dockerignore
для отправки только тех файлов, которые скопированы в вашем Dockerfile с помощью COPY.
- Демон docker создает временный контейнер, используя инструкцию FROM в Dockerfile. Это импортированное изображение, включая собственные импортированные изображения. Затем каждая инструкция в Dockefile выполняется внутри этого контейнера. Когда во временном контейнере вносятся постоянные изменения (например, в COPY), он сохраняет свое состояние. Это эффективно добавляет слой к окончательному изображению.
- По завершении выполнения инструкций DOCKERFILE временный контейнер уничтожается. Вы остались с окончательным изображением.
Вы можете увидеть все слои на изображении, используя
docker history <image-id>
Обратите внимание, что это удобный способ отладки Dockerfile. Вы должны увидеть идентификатор для слоев, которые соответствуют постоянным инструкциям в вашем Dockerfile. Вы можете создать новый контейнер из любого слоя, используя docker run --rm -it <id next to layer> sh
и вручную выполнить следующие инструкции Dockerfile.