Подтвердить что ты не робот

Что такое "слои" изображения "Докер"?

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

Из официальных документов Docker:

Мы уже видели, что образы Docker - это шаблоны только для чтения, из которых запускаются контейнеры Docker. Каждое изображение состоит из серии слоев. Docker использует объединенные файловые системы для объединения этих слоев в одно изображение. Объединенные файловые системы позволяют прозрачно накладывать файлы и каталоги отдельных файловых систем, называемых ветвями, образуя единую согласованную файловую систему.

Поэтому я спрашиваю, что такое слой (точно); кто-нибудь может привести несколько конкретных примеров из них? И как эти слои "слипаются", образуя изображение?

4b9b3361

Ответ 1

Возможно, я опоздаю, но вот мои 10 центов (дополняющий ответ ashishjain):

В принципе, слой или слой изображения - это изменение на изображении или промежуточное изображение. Каждая указанная вами команда (FROM, RUN, COPY и т.д.) В вашем файле Docker приводит к изменению предыдущего изображения, создавая новый слой. Вы можете думать об этом как о перестановках, когда вы используете git: вы добавляете изменение файла, затем еще одно, а затем другое...

Рассмотрим следующий файл Docker:

FROM rails:onbuild
ENV RAILS_ENV production
ENTRYPOINT ["bundle", "exec", "puma"]

Сначала мы выбираем начальный образ: rails:onbuild, который, в свою очередь, имеет много слоев. Добавим еще один слой поверх нашего стартового изображения, установив переменную окружения RAILS_ENV командой ENV. Затем мы скажем, что docker запускает bundle exec puma (который загружает сервер rails). Этот другой слой.

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

Вы можете прочитать об этом здесь.

Ответ 2

Изображение контейнера-докера создается с помощью dockerfile. Каждая строка в файле dockerfile создаст слой. Рассмотрим следующий фиктивный пример:

FROM ubuntu             #This has its own number of layers say "X"
MAINTAINER FOO          #This is one layer 
RUN mkdir /tmp/foo      #This is one layer 
RUN apt-get install vim #This is one layer 

Это создаст окончательное изображение, в котором общее количество слоев будет X + 3

Ответ 3

Они имеют смысл для меня на примере...

Изучение слоев вашей сборки с помощью докера diff

Давайте возьмем надуманный пример Dockerfile:

FROM busybox

RUN mkdir /data
# imagine this is downloading source code
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one 
RUN chmod -R 0777 /data
# imagine this is compiling the app
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two 
RUN chmod -R 0777 /data
# and now this cleans up that downloaded source code
RUN rm /data/one 

CMD ls -alh /data

Каждая из этих команд dd выводит файл 1M на диск. Давайте создадим изображение с дополнительным флагом для сохранения временных контейнеров:

docker image build --rm=false .

В выводе вы увидите, что каждая из запущенных команд происходит во временном контейнере, который мы теперь храним вместо автоматического удаления:

...
Step 2/7 : RUN mkdir /data
 ---> Running in 04c5fa1360b0
 ---> 9b4368667b8c
Step 3/7 : RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
 ---> Running in f1b72db3bfaa
1024+0 records in
1024+0 records out
1048576 bytes (1.0MB) copied, 0.006002 seconds, 166.6MB/s
 ---> ea2506fc6e11

Если вы запустите docker diff для каждого из этих идентификаторов контейнеров, вы увидите, какие файлы были созданы в этих контейнерах:

$ docker diff 04c5fa1360b0  # mkdir /data
A /data
$ docker diff f1b72db3bfaa  # dd if=/dev/zero bs=1024 count=1024 of=/data/one
C /data
A /data/one
$ docker diff 81c607555a7d  # chmod -R 0777 /data
C /data
C /data/one
$ docker diff 1bd249e1a47b  # dd if=/dev/zero bs=1024 count=1024 of=/data/two
C /data
A /data/two
$ docker diff 038bd2bc5aea  # chmod -R 0777 /data
C /data/one
C /data/two
$ docker diff 504c6e9b6637  # rm /data/one
C /data
D /data/one

Каждая строка с префиксом A добавляет файл, C указывает на изменение существующего файла, а D указывает на удаление.

Здесь часть TL; DR

Каждая из приведенных выше версий файловой системы контейнера входит в один "слой", который собирается, когда вы запускаете образ как контейнер. При добавлении или изменении весь файл находится в каждом слое, поэтому каждая из этих команд chmod, несмотря на простое изменение бита разрешения, приводит к копированию всего файла на следующий слой. Удаленный /data/one файл все еще находится в предыдущих слоях, фактически 3 раза, и будет скопирован по сети и сохранен на диске при извлечении изображения.

Изучение существующих изображений

Вы можете увидеть команды, которые используются для создания слоев существующего изображения, с помощью команды docker history. Вы также можете запустить docker image inspect на изображении и увидеть список слоев в разделе RootFS.

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

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
a81cfb93008c        4 seconds ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "ls -…   0B
f36265598aef        5 seconds ago       /bin/sh -c rm /data/one                         0B
c79aff033b1c        7 seconds ago       /bin/sh -c chmod -R 0777 /data                  2.1MB
b821dfe9ea38        10 seconds ago      /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
a5602b8e8c69        13 seconds ago      /bin/sh -c chmod -R 0777 /data                  1.05MB
08ec3c707b11        15 seconds ago      /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
ed27832cb6c7        18 seconds ago      /bin/sh -c mkdir /data                          0B
22c2dd5ee85d        2 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B
<missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:2a4c44bdcb743a52f…   1.16MB

Самые новые слои перечислены сверху. Следует отметить, что внизу есть два довольно старых слоя. Они приходят из самого изображения busybox. Когда вы строите одно изображение, вы наследуете все слои изображения, которые вы указали в строке FROM. Существуют также слои, добавляемые для изменения метаданных изображения, например строка CMD. Они практически не занимают места и предназначены для учета того, какие настройки применяются к изображению, которое вы запускаете.

Почему слои?

Слои имеют пару преимуществ. Во-первых, они неизменны. После создания этот слой, идентифицируемый хэшем sha256, никогда не изменится. Эта неизменность позволяет изображениям безопасно создавать и отделяться друг от друга. Если два файла Docker имеют одинаковый начальный набор строк и построены на одном сервере, они будут использовать один и тот же набор начальных слоев, экономя дисковое пространство. Это также означает, что если вы перестраиваете изображение, и только в нескольких последних строках Dockerfile происходят изменения, нужно перестраивать только эти слои, а остальные можно повторно использовать из кэша слоев. Это может очень быстро перестроить образ докера.

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

Уменьшение раздувания слоя

Недостатком слоев является создание изображений, которые дублируют файлы или отправляют файлы, которые будут удалены в более позднем слое. Решение часто состоит в объединении нескольких команд в одну команду RUN. В частности, когда вы изменяете существующие файлы или удаляете файлы, вы хотите, чтобы эти шаги выполнялись в той же команде, в которой они были впервые созданы. Переписанный выше Dockerfile будет выглядеть так:

FROM busybox

RUN mkdir /data \
 && dd if=/dev/zero bs=1024 count=1024 of=/data/one \
 && chmod -R 0777 /data \
 && dd if=/dev/zero bs=1024 count=1024 of=/data/two \
 && chmod -R 0777 /data \
 && rm /data/one

CMD ls -alh /data

А если сравнить полученные изображения:

  • busybox: ~ 1 МБ
  • первое изображение: ~ 6 МБ
  • второе изображение: ~ 2 МБ

Просто соединив несколько строк в надуманном примере, мы получили то же самое результирующее содержимое в нашем изображении и сократили наше изображение с 5 МБ до только 1 МБ файла, который вы видите на конечном изображении.

Ответ 4

Начиная с Docker v1.10, с введением адресного хранилища контента, понятие "уровень" стало совершенно другим. Слои не имеют представления об изображении или принадлежности к изображению, они становятся просто коллекциями файлов и каталогов, которые могут совместно использоваться изображениями. Слои и изображения стали разделенными.

Например, на локально построенном изображении из базового изображения, скажем, ubuntu:14.04, команда docker history выдает цепочку изображений, но некоторые из идентификаторов изображений будут отображаться как "пропущенные", поскольку история сборки больше не существует. загружен. И слои, которые составляют эти изображения, можно найти через

docker inspect <image_id> | jq -r '.[].RootFS'

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

  1. Соответствующее отношение между изображением и его составным слоем (слоями)
  2. Фактическое расположение и размер слоя на диске

Этот блог дал много полезного.

Ответ 5

Per Docker описание изображения

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

Итак, по сути, уровень - это всего лишь набор изменений, внесенных в файловую систему.

Ответ 6

Я думаю, что официальный документ дает довольно подробное объяснение: https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/.


(источник: docker.com)

Изображение состоит из множества слоев, которые обычно создаются из Dockerfile, каждая строка в Dockerfile создает новый слой, и в результате получается изображение, которое обозначается формой repo:tag, например, ubuntu:15.04.

Для получения дополнительной информации, пожалуйста, прочитайте официальные документы выше.

Ответ 7

Спасибо @David Castillo за полезную информацию. Я думаю, что этот слой представляет собой двоичное изменение или инструкцию изображения, которое можно легко или легко отменить. Они выполняются поэтапно, так же, как слой на слое, поэтому мы называем "слой".

Для получения дополнительной информации вы можете увидеть "историю докеров" следующим образом:

docker images --tree
Warning: '--tree' is deprecated, it will be removed soon. See usage.
└─511136ea3c5a Virtual Size: 0 B Tags: scratch:latest
  └─59e359cb35ef Virtual Size: 85.18 MB
    └─e8d37d9e3476 Virtual Size: 85.18 MB Tags: debian:wheezy
      └─c58b36b8f285 Virtual Size: 85.18 MB
        └─90ea6e05b074 Virtual Size: 118.6 MB
          └─5dc74cffc471 Virtual Size: 118.6 MB Tags: vim:latest

Ответ 8

Мое личное понимание состоит в том, что мы можем сравнивать слой докера с коммитом github. Для вашего базового образа (вашего свежего главного репо) вы делаете несколько коммитов, каждый коммит меняет ваш главный статус, то же самое в докере, каждый слой выполняет некоторую операцию на основе предыдущего промежуточного слоя. И затем этот слой становится новым промежуточным слоем для следующего слоя.