С чего начать Первые шаги трек · 15 ступеней
Linux Labs

Образы контейнеров — слои, теги, реестр и digest

11 мин Docker 29.1 · Ubuntu 24.04

Образ — неизменяемый набор слоёв с файлами и настройками запуска; из него Docker создаёт контейнеры.

Шпаргалка

10 команд Версия для печати
  • sudo docker load -i /opt/images/alpine.tar образ из файла
  • sudo docker images образы на машине
  • sudo docker image ls --digests с digest
  • sudo docker history nginx:alpine слои и чем созданы
  • sudo docker image inspect -f '{{.Id}}' busybox полный ID
  • sudo docker tag busybox:latest app:1.0 второе имя того же образа
  • sudo docker rmi app:1.0 снять тег или удалить образ
  • sudo docker image prune удалить образы без тега
  • sudo docker save busybox > busybox.tar образ в файл
  • sudo docker pull nginx:alpine скачать из реестра (нужна сеть)

Обзор

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

На машине тренажёра сети наружу нет. Образы лежат файлами в /opt/images, docker load загружает их в Docker. На этой машине student не входит в группу docker, поэтому все команды идут через sudo.

text
student@ubuntu:~$ sudo docker load -i /opt/images/alpine.tar
Loaded image: alpine:latest
student@ubuntu:~$ sudo docker images
IMAGE            ID             DISK USAGE   CONTENT SIZE   EXTRA
alpine:latest    d1e016453729       17.8MB         8.71MB
busybox:latest   27be924c62a0       9.26MB         4.68MB   U
nginx:alpine     1acb5b0222ee        144MB         70.4MB
Столбец Что в нём
IMAGE имя образа: репозиторий и тег
ID короткий ID — первые 12 знаков хэша
CONTENT SIZE слои в сжатом виде, как в файле или в реестре
DISK USAGE место на диске вместе с распакованными слоями
EXTRA U — образ использует хотя бы один контейнер

После таблицы docker images печатает предупреждение This output is designed for human readability: вид таблицы может поменяться с версией Docker. Скрипту нужен --format — рецепт ниже.

Имя образа и реестр

Реестр — сервер, где хранятся образы: Docker Hub, GitLab Registry, свой реестр компании. docker pull скачивает образ из реестра, docker push отправляет. Полное имя образа говорит, где он лежит:

text
registry.example.com:5000/team/app:1.4
└── реестр ─────────────┘└ путь ─┘└ тег

Без реестра в имени Docker идёт в Docker Hub, без тега берёт latest. nginx:alpine — это docker.io/library/nginx:alpine. Полное имя видно в ошибке, когда образа нет на машине: failed to resolve reference "docker.io/library/nginx:alpine".

Слои

Образ собран из слоёв. Слой — архив с изменениями файлов: что добавлено, изменено или удалено относительно слоёв под ним. Каждая инструкция dockerfile, которая меняет файлы, даёт слой. Историю слоёв показывает docker history, новые сверху:

text
student@ubuntu:~$ sudo docker history nginx:alpine
IMAGE          CREATED      CREATED BY                         SIZE
1acb5b0222ee   5 days ago   RUN /bin/sh -c set -x && apkArch…  52.4MB
<missing>      5 days ago   CMD ["nginx" "-g" "daemon off;"]   0B
<missing>      5 days ago   EXPOSE map[80/tcp:{}]              0B
<missing>      5 days ago   COPY docker-entrypoint.sh / # bu…  8.19kB
…
<missing>      4 weeks ago  ADD alpine-minirootfs-3.24.2-x86…  9.08MB

Нижняя строка — слой Alpine: nginx:alpine собран поверх образа Alpine. Строки с размером 0B (CMD, EXPOSE, ENV) файлов не меняют — они записывают настройки запуска. <missing> в столбце IMAGE значит, что у шага нет отдельного образа на этой машине: так выглядит история любого скачанного или загруженного образа.

Одинаковые слои хранятся один раз. Десять образов на основе Alpine держат на диске одну копию его слоя.

Слой контейнера

Слои образа только читаются. Контейнер получает поверх них свой слой для записи — слой контейнера. Файл, изменённый внутри контейнера, копируется в этот слой (копирование при записи), а образ остаётся прежним.

Слой контейнера живёт, пока жив контейнер: docker stop и docker start его сохраняют, docker rm удаляет вместе со всеми данными. Данные, которые должны пережить пересоздание контейнера, хранят в томе — раздел «Тома» статьи о Docker.

Тег

Тег — подвижное имя образа: часть после двоеточия. docker tag даёт тому же образу второе имя, ID у имён один:

text
student@ubuntu:~$ sudo docker tag busybox:latest app:1.0
student@ubuntu:~$ sudo docker images
IMAGE            ID             DISK USAGE   CONTENT SIZE   EXTRA
app:1.0          27be924c62a0       9.26MB         4.68MB   U
busybox:latest   27be924c62a0       9.26MB         4.68MB   U

latest — просто тег по умолчанию. Он ставится, когда тег не указан, и ничего не говорит о свежести: alpine:latest на машине — тот образ, который в неё загрузили.

Тег переезжает при сборке. docker build -t app:1.1 второй раз отдаёт имя новому образу, а прежний остаётся без имени, <none>:<none> — висячий образ (dangling). Обычный docker images его не показывает, найти можно фильтром:

text
student@ubuntu:~$ sudo docker images --filter dangling=true \
    --format '{{.ID}} {{.Repository}}:{{.Tag}}'
a4eab66e5237 <none>:<none>

docker images -a показывает такие образы строкой <untagged>.

docker rmi <имя> снимает тег. Если у образа есть другие имена, образ остаётся: Untagged: busybox:latest. Последнее имя docker rmi удаляет вместе с образом — если образ не нужен ни одному контейнеру.

Digest и ID

Digest — SHA-256 от манифеста образа, описания слоёв и настроек. Поменяется хоть один байт в любом слое — поменяется и digest. Поэтому nginx@sha256:1acb… всегда означает одно и то же содержимое, а nginx:alpine завтра может указывать на другой образ.

text
student@ubuntu:~$ sudo docker image ls --digests
REPOSITORY   TAG      DIGEST            IMAGE ID       …   SIZE
nginx        alpine   sha256:1acb5b0…   1acb5b0222ee   …   144MB
busybox      latest   sha256:27be924…   27be924c62a0   …   9.26MB

В Docker 29 образы хранит containerd, и у загруженного образа ID совпадает с digest.

docker load и docker save

docker save пишет образ в tar-архив со всеми слоями, docker load загружает его обратно — на этой же или другой машине. Так образ попадает туда, где нет доступа к реестру. Внутри архива — формат OCI: index.json, manifest.json и каталог blobs/sha256, где каждый файл назван своим SHA-256.

Рецепты

5

Какой образ у контейнера

bash
sudo docker ps -a --format '{{.Names}} {{.Image}}'
sudo docker inspect -f '{{.Config.Image}} {{.Image}}' web

Первое поле inspect — имя, с которым контейнер создан, второе — ID образа. Если имя с тех пор переехало на новый образ, ID это покажет.

Сверить digest вручную

text
student@ubuntu:~$ mkdir bb && sudo docker save busybox | tar -xf - -C bb
student@ubuntu:~$ ls bb
blobs  index.json  manifest.json  oci-layout
student@ubuntu:~$ sha256sum bb/blobs/sha256/27be924c62a0…
27be924c62a0fa666ec2763cd824eb5caa9a7b324a953496909ff11498a409ea  bb/…

index.json указывает на манифест по digest, файл манифеста назван тем же digest, и sha256sum от него даёт то же число. По таким хэшам реестр и Docker проверяют, что слой дошёл целым.

Перенести образ на машину без сети

bash
sudo docker save app:1.1 > app.tar     # на машине с образом
scp app.tar admin@server:/tmp/
sudo docker load -i /tmp/app.tar       # на сервере

Список образов для скрипта

bash
sudo docker images --format '{{.Repository}}:{{.Tag}} {{.ID}}'
sudo docker image inspect -f '{{.Size}}' nginx:alpine

Освободить место

bash
sudo docker system df                  # образы, контейнеры, тома
sudo docker image prune                # только образы без тега
sudo docker images --filter dangling=true   # что удалит prune

Неполадки

5

Unable to find image … locally

text
Unable to find image 'nosuch:1' locally
docker: Error response from daemon: failed to resolve reference
"docker.io/library/nosuch:1": … server misbehaving

Образа с таким именем и тегом на машине нет, и Docker пошёл за ним в реестр. docker run, docker build с таким FROM и docker compose up так и делают. Без сети запрос падает на lookup registry-1.docker.io. Сверь имя и тег с docker images (busybox:latest и busybox:1.36 — разные образы) или загрузи образ из файла: docker load -i.

conflict: unable to delete … must be forced

text
Error response from daemon: conflict: unable to delete busybox:latest
(must be forced) - container 5401987efe76 is using its referenced
image 27be924c62a0

Образ нужен контейнеру, хотя бы остановленному. Найди его: docker ps -a --filter ancestor=busybox, удали docker rm, потом образ.

Пересобрал образ, а контейнер работает по-старому

Контейнер создан из того образа, который был под именем в момент docker run. Новая сборка с тем же тегом его не трогает. Пересоздай контейнер: docker rm -f web, затем docker run с теми же ключами. Сверить можно ID: docker inspect -f '{{.Image}}' web и docker image inspect -f '{{.Id}}' app:1.1.

<none> вместо имени

Висячие образы остаются после пересборки с тем же тегом. Они занимают место, но не мешают. Убрать — docker image prune.

Permission denied на архив из docker save

sudo docker save -o file.tar создаёт файл от root с правами 600, и student не может его прочитать. Перенаправь вывод — sudo docker save busybox > busybox.tar: файл создаёт твоя оболочка, он твой.

Опасно

2

docker image prune -a и docker rmi -f

prune -a удаляет и висячие образы, и все остальные, которые сейчас не нужны ни одному контейнеру. Без сети вернуть их нечем: файл для docker load придётся искать заново. rmi -f снимает защиту от удаления образа, нужного контейнеру.

latest в рабочих конфигах

image: app:latest в compose или скрипте запуска означает «что сейчас под этим именем». После docker pull или новой сборки сервис молча поднимется на другой версии. Пиши тег версии или digest: nginx@sha256:1acb5b02….

Термины

5
слой образа image layer
Часть образа — архив изменений файлов, который дала одна инструкция Dockerfile. Слои только читаются и общие у образов с одной основой; список — docker history. Ещё встречается в: Dockerfile
слой контейнера container layer
Слой для записи поверх слоёв образа: всё, что контейнер меняет в своих файлах, попадает сюда. Удаляется вместе с контейнером командой docker rm. Ещё встречается в: Docker
тег образа image tag
Подвижное имя образа после двоеточия: nginx:alpine, app:1.1. Без тега подставляется latest. После новой сборки тот же тег указывает на новый образ. Ещё встречается в: Dockerfile
реестр образов image registry
Сервер, где хранятся образы и откуда их скачивает docker pull: Docker Hub, GitLab Registry, свой реестр компании. Имя реестра — первая часть полного имени образа.
digest образа image digest
SHA-256 манифеста образа, sha256:… — отпечаток содержимого. nginx@sha256:… всегда означает одни и те же слои, а тег может переехать на другой образ.

См. также

  • docker — запуск контейнеров, тома, сети, inspect.
  • dockerfile — как собрать свой образ и откуда берутся слои.
  • docker-compose — несколько контейнеров из одного файла.
  • cgroups-namespaces — чем контейнер изолирован от хоста.
  • tar — формат архива docker save.
  • disk-usage — куда ушло место на диске.
Загрузка…