Понимание слоев докера и будущих изменений - PullRequest
0 голосов
/ 15 марта 2019

Итак ,

enter image description here

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

и,

enter image description here

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

и также ,

Слои образа Docker - это, по сути, просто файлы, созданные при выполнении какой-либо команды. Вы можете просмотреть содержимое каждого слоя на хосте Docker на /var/lib/docker/aufs/diff.

Теперь вопросы

  • Скажем, я строю свои докеры слой за слоем . A < B < C < D и т. Д.
  • Теперь, если я обновлю свой образ докера A, увидят ли остальные остальные образы докера B, C, D также изменения, если они не будут затронуты при их создании? Например, добавив /etc/apt/sources.list.d/somethingnew, которого никогда не было раньше.
  • Если бы я построил другой набор изображений докеров слой за слоем. A < X < Y < Z, тогда вышеуказанные изменения будут отражены и в X, Y, Z, верно?
  • Теперь, если, однако, будущее изменится на A, будет ли внесено в тот же файл , который будет изменен при сборке B, C, D, что тогда произойдет? Например, давайте упростим то, что каждый образ docker B, C, D добавляет только pkgB, pkgC и pkgD в свой слой. Что будет, если я добавлю pkgA в A после сборки B, C, D? - Я полагаю, что должна быть одна единственная версия истины, в которой содержатся пакеты, для одной системы, так что же будет в этом случае?
  • Что если я только обновляю пакеты в A? Это должно быть хорошо, верно? Будут ли остальные образы докера также видеть изменения?

1 Ответ

1 голос
/ 15 марта 2019

В целом, каждое изображение содержит свое родительское изображение, либо в виде встроенных байтов, либо в виде "жесткой" ссылки на изображение в локальном кэше, если оно уже там.

Под «родителем» я подразумеваю инструкцию FROM: someimage в вашем Dockerfile.

Я также написал "hard", поскольку ссылка на самом деле представляет собой sha246-дайджест родительского изображения. Если какой-либо бит родительского изменится, дайджест будет другим.

Здесь есть три основных случая:

  1. Вы начинаете с очистки кэша (docker image ls -a ничего не показывает). Если у вас docker pull ... какое-то изображение из публичного реестра, в него будет встроен родительский образ. A docker ps -a должен показывать только одно изображение.

  2. Если, однако, у вас уже есть родительское изображение в вашем кэше, docker pull ... больше не будет загружать родительский образ. В этом случае вытащенное изображение имеет ссылку на родителя в вашем кэше.

  3. Если вы строите локально из прозрачного кэша, 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

Для проверки отношений.

Еще немного информации.

При создании изображения выполняются следующие шаги:

  1. Контекст сборки отправляется хосту с помощью демона docker. Это в основном все файлы в каталоге, в котором находится ваш Dockerfile. Поэтому важно использовать .dockerignore для отправки только тех файлов, которые скопированы в вашем Dockerfile с помощью COPY.
  2. Демон docker создает временный контейнер, используя инструкцию FROM в Dockerfile. Это импортированное изображение, включая собственные импортированные изображения. Затем каждая инструкция в Dockefile выполняется внутри этого контейнера. Когда во временном контейнере вносятся постоянные изменения (например, в COPY), он сохраняет свое состояние. Это эффективно добавляет слой к окончательному изображению.
  3. По завершении выполнения инструкций DOCKERFILE временный контейнер уничтожается. Вы остались с окончательным изображением.

Вы можете увидеть все слои на изображении, используя docker history <image-id>

Обратите внимание, что это удобный способ отладки Dockerfile. Вы должны увидеть идентификатор для слоев, которые соответствуют постоянным инструкциям в вашем Dockerfile. Вы можете создать новый контейнер из любого слоя, используя docker run --rm -it <id next to layer> sh и вручную выполнить следующие инструкции Dockerfile.

...