Главная/Storage/Урок

7.1. Файловая система container

Цели

После этого материала вы сможете:

  • сказать, что произойдёт с записанными данными при stop, start, restart и rm;
  • найти writable layer конкретного container на host;
  • объяснить, почему запись больших объёмов в container layer обходится дорого;
  • увидеть список изменений файловой системы container одной командой;
  • выбрать между volume, bind mount и tmpfs по сути задачи, а не по привычке.

Предварительные знания

Ключевые термины

ТерминОбъяснение
writable layerВерхний слой container'а, куда попадают все изменения
copy-upКопирование файла из нижнего слоя в верхний перед изменением
whiteoutЗапись в верхнем слое, скрывающая файл нижнего
volumeКаталог, которым управляет Docker; живёт вне container'а
bind mountКаталог host, подключённый в container напрямую
tmpfsФайловая система в оперативной памяти

Теория

Данные и жизненный цикл container

Слои образа доступны только для чтения. Всё, что container записывает, попадает в отдельный writable layer, созданный при docker create (урок 3.2).

Судьба этого слоя определяется командой:

КомандаWritable layerДанные
docker stopСохраняетсяНа месте
docker startТот же слойНа месте
docker restartТот же слойНа месте
docker killСохраняетсяНа месте
Перезапуск по --restartТот же слойНа месте
docker rmУдаляетсяПотеряны
docker rm -vУдаляетсяПотеряны, плюс удаляются anonymous volumes
docker run (новый container)Новый пустой слойДанные предыдущего недоступны

Распространённое заблуждение — что данные исчезают при остановке. Это не так: остановленный container сохраняет всё записанное, и docker start вернёт его в том же состоянии. Теряются данные только при удалении.

Практическое следствие: опасна не остановка, а docker rm — а он выполняется постоянно, потому что docker run --rm, docker compose down и обновление образа пересоздают container.

Почему запись в container layer обходится дорого

Три причины, по возрастанию значимости.

1. Copy-up при первом изменении. Изменение файла из нижнего слоя требует сначала скопировать его целиком в верхний. Правка одного байта в файле на 500 MB означает копирование 500 MB.

2. Дополнительный уровень косвенности. Запись идёт через OverlayFS, а не напрямую в файловую систему host. Для интенсивной нагрузки — например, файлов базы данных — накладные расходы заметны.

3. Данные привязаны к container'у. Их нельзя переиспользовать, нельзя примонтировать к другому container'у, они не переживут пересоздание. Резервное копирование требует docker cp или docker commit — оба варианта неудобны.

Отсюда правило: container layer предназначен для того, что не жалко потерять — временные файлы, кэш, логи, которые уже отправлены в stdout.

Три механизма хранения

VolumeBind mounttmpfs
Кто управляетDockerВыЯдро
Где данные/var/lib/docker/volumes/Любой путь hostОперативная память
Переживает docker rmДаДаНет
Переносимость между машинамиВысокаяНизкая (абсолютные пути)
Работает в Swarm и KubernetesДаОграниченноДа
Скрывает содержимое образаТолько если непустойВсегдаВсегда
Наполняется из образа при первом монтированииДаНетНет
Права доступаНаследуются от образаОт hostЗадаются при монтировании
Резервное копированиеdocker run со вспомогательным containerОбычными средствами hostНевозможно
Следы на дискеЕстьЕстьНет

Критерий выбора — не «что удобнее», а кто владеет данными:

ЗадачаМеханизмПочему
Данные базы, загруженные файлыVolumeВладелец — приложение; Docker отвечает за расположение
Исходный код при разработкеBind mountВладелец — вы; правки нужны мгновенно
Конфигурационный файл с hostBind mount, read-onlyВладелец — host; изменять из container не нужно
Сокет Docker для CIBind mountОбъект существует на host
Временные файлы, /tmp при read-onlytmpfsНе должны переживать перезапуск
Секреты в процессе работыtmpfsНе должны попадать на диск
Кэш, восстановимый при потереVolume или tmpfsПо объёму и цене прогрева

-v против --mount

Два синтаксиса делают почти одно и то же:

bash
docker run -v mydata:/data ...
docker run --mount type=volume,source=mydata,target=/data ...

Различия, которые имеют значение:

Свойство-v--mount
МногословностьКорочеДлиннее
ЧитаемостьПозиционная, легко ошибитьсяИменованные поля
Несуществующий путь hostСоздаёт каталогОшибка
Опции драйверов, tmpfs-параметрыОграниченноПолностью
Поведение в SwarmНе всё поддерживаетсяПоддерживается

Третья строка — главная. Опечатка в пути при -v создаёт пустой каталог и запускает container, который выглядит рабочим, но не видит данных. При --mount та же опечатка даёт ошибку сразу.

Курс использует --mount в примерах, где важна ясность, и -v там, где краткость важнее.


Внутренний механизм

Где физически лежит writable layer

Расположение зависит от хранилища образов (урок 3.1):

ХранилищеStorage Driver в docker infoГде искать
Классическоеoverlay2.GraphDriver.Data.UpperDir в docker inspect
containerd (по умолчанию с Engine 29 для новых установок)overlayfsСнапшоты containerd; GraphDriver может быть пустым

Поэтому путь не заучивают, а спрашивают у Docker:

bash
docker inspect <container> --format '{{.GraphDriver.Data.UpperDir}}'

Пустой результат означает containerd image store — тогда добраться до слоя напрямую сложнее, и это ещё один довод в пользу volumes: их расположение стабильно и не зависит от хранилища образов.

docker diff

Docker умеет показать, чем файловая система container'а отличается от образа:

text
A /data/report.txt      # добавлен (Added)
C /etc/hosts            # изменён (Changed)
D /usr/share/doc/README # удалён (Deleted)

Это прямое отражение содержимого writable layer: A — новый файл в верхнем слое, C — результат copy-up, D — whiteout.

Команда не показывает содержимое volumes и bind mounts: они не входят в слой. Это удобное свойство — docker diff отвечает ровно на вопрос «что будет потеряно при docker rm».


Команды и примеры

Что переживает остановку, а что — удаление

bash
docker run -d --name lifecycle alpine:3.21 sh -c 'sleep 3600'
docker exec lifecycle sh -c 'echo "записано до остановки" > /root/data.txt'

echo "═══ после записи ═══"
docker exec lifecycle cat /root/data.txt

echo "═══ после stop и start ═══"
docker stop lifecycle > /dev/null
docker start lifecycle > /dev/null
sleep 1
docker exec lifecycle cat /root/data.txt

echo "═══ после restart ═══"
docker restart lifecycle > /dev/null
sleep 1
docker exec lifecycle cat /root/data.txt

echo "═══ после rm и нового run из того же образа ═══"
docker rm -f lifecycle > /dev/null
docker run --rm alpine:3.21 sh -c 'cat /root/data.txt 2>&1 || echo "файла нет — данные потеряны"'

Ожидаемый вывод:

text
═══ после записи ═══
записано до остановки
═══ после stop и start ═══
записано до остановки
═══ после restart ═══
записано до остановки
═══ после rm и нового run из того же образа ═══
cat: can't open '/root/data.txt': No such file or directory
файла нет — данные потеряны

Три первых блока опровергают распространённое заблуждение: остановка данные не трогает. Четвёртый показывает настоящую границу — удаление container'а.

То же самое с volume

bash
docker volume create demo-data > /dev/null
docker run --rm --mount type=volume,source=demo-data,target=/data \
    alpine:3.21 sh -c 'echo "данные в volume" > /data/file.txt'

echo "═══ container удалён (--rm), читаем другим container'ом ═══"
docker run --rm --mount type=volume,source=demo-data,target=/data \
    alpine:3.21 cat /data/file.txt

echo "═══ третий container видит те же данные ═══"
docker run --rm -v demo-data:/mnt alpine:3.21 sh -c 'cat /mnt/file.txt'

Ожидаемый вывод:

text
═══ container удалён (--rm), читаем другим container'ом ═══
данные в volume
═══ третий container видит те же данные ═══
данные в volume

Данные пережили удаление обоих container'ов и доступны третьему — по другому пути монтирования. Это и есть смысл volume: данные не принадлежат container'у.

Где находится writable layer

bash
docker run -d --name layerdemo alpine:3.21 sh -c 'sleep 300'
docker exec layerdemo sh -c 'echo "содержимое" > /root/probe.txt'

upper="$(docker inspect layerdemo --format '{{.GraphDriver.Data.UpperDir}}')"
if [ -n "$upper" ]; then
    echo "UpperDir: $upper"
    sudo ls -la "$upper/root/" 2>/dev/null || echo "  (нужен sudo для чтения)"
else
    echo "GraphDriver пуст — используется containerd image store"
    docker info --format 'Storage Driver: {{.Driver}}'
fi
docker rm -f layerdemo > /dev/null

Ожидаемый вывод при классическом хранилище:

text
UpperDir: /var/lib/docker/overlay2/8f3c.../diff
total 12
drwx------ 2 root root 4096 Jul 30 12:10 .
drwxr-xr-x 5 root root 4096 Jul 30 12:10 ..
-rw-r--r-- 1 root root   11 Jul 30 12:10 probe.txt

Ожидаемый вывод при containerd image store:

text
GraphDriver пуст — используется containerd image store
Storage Driver: overlayfs

Оба варианта нормальны. Второй — ещё один довод за volumes: docker volume inspect даёт стабильный путь независимо от хранилища образов.

docker diff: что будет потеряно

bash
docker run -d --name diffdemo python:3.13-slim sh -c 'sleep 300'
docker exec diffdemo sh -c '
    mkdir -p /app/output
    echo "результат" > /app/output/result.txt
    echo "127.0.0.1 myhost" >> /etc/hosts
    rm -f /usr/local/lib/python3.13/this.py
    python -c "print(1)" > /dev/null     # создаст __pycache__
'
docker diff diffdemo | sort | head -20

Ожидаемый вывод:

text
A /app
A /app/output
A /app/output/result.txt
C /etc
C /etc/hosts
D /usr/local/lib/python3.13/this.py

Три типа изменений видны сразу:

СтрокаЧто произошло
A /app/output/result.txtНовый файл — существует только в writable layer
C /etc/hostsCopy-up: файл скопирован из слоя образа и изменён
D .../this.pyWhiteout: файл образа скрыт, но в слое образа остался

Каталог /etc помечен C, потому что изменилось его содержимое — это ожидаемо и не означает, что изменён сам каталог.

Теперь то же самое с volume:

bash
docker rm -f diffdemo > /dev/null
docker volume create diff-vol > /dev/null
docker run -d --name diffdemo2 --mount type=volume,source=diff-vol,target=/app/output \
    python:3.13-slim sh -c 'sleep 300'
docker exec diffdemo2 sh -c 'echo "результат" > /app/output/result.txt'

echo "═══ docker diff ═══"
docker diff diffdemo2

echo "═══ файл при этом на месте ═══"
docker exec diffdemo2 cat /app/output/result.txt
docker rm -f diffdemo2 > /dev/null

Ожидаемый вывод:

text
═══ docker diff ═══
C /app
═══ файл при этом на месте ═══
результат

Файл записан и читается, но docker diff его не показывает: он не в слое, а в volume. Отсюда практическое применение команды — проверить, что состояние не оседает в container layer перед пересозданием.

Строка C /app появляется потому, что точка монтирования создаётся в слое.

Цена copy-up

bash
docker build -q -t cowcost - <<'EOF' > /dev/null
FROM alpine:3.21
RUN dd if=/dev/zero of=/big.bin bs=1M count=200 2>/dev/null
EOF

docker run --rm cowcost sh -c '
    echo "═══ изменение 1 байта в файле из слоя образа ═══"
    time_start=$(date +%s%N)
    dd if=/dev/zero of=/big.bin bs=1 count=1 conv=notrunc 2>/dev/null
    time_end=$(date +%s%N)
    echo "  правка 1 байта: $(( (time_end - time_start) / 1000000 )) мс"

    echo "═══ повторная правка того же файла ═══"
    time_start=$(date +%s%N)
    dd if=/dev/zero of=/big.bin bs=1 count=1 conv=notrunc 2>/dev/null
    time_end=$(date +%s%N)
    echo "  правка 1 байта: $(( (time_end - time_start) / 1000000 )) мс"
'
docker rmi -f cowcost > /dev/null

Ожидаемый вывод:

text
═══ изменение 1 байта в файле из слоя образа ═══
  правка 1 байта: 214 мс
═══ повторная правка того же файла ═══
  правка 1 байта: 1 мс

Первая правка стоила 214 мс, вторая — 1 мс. Разница — это copy-up: файл на 200 MB был целиком скопирован в writable layer. Второй раз копировать уже нечего.

Именно поэтому файлы базы данных не держат в container layer: при интенсивной записи стоимость первого обращения платится за каждый файл.

Три механизма рядом

bash
docker volume create three-vol > /dev/null
mkdir -p /tmp/three-bind && echo "с host" > /tmp/three-bind/host.txt

docker run -d --name three \
    --mount type=volume,source=three-vol,target=/vol \
    --mount type=bind,source=/tmp/three-bind,target=/bind \
    --mount type=tmpfs,target=/mem,tmpfs-size=16m \
    alpine:3.21 sh -c 'sleep 300' > /dev/null

docker exec three sh -c '
    echo "в volume" > /vol/a.txt
    echo "в tmpfs"  > /mem/b.txt
    echo "в слое"   > /layer.txt
'

echo "═══ типы файловых систем внутри container ═══"
docker exec three df -hT /vol /bind /mem / 2>/dev/null | awk 'NR==1 || /vol|bind|mem|overlay/'

echo
echo "═══ что видит docker diff ═══"
docker diff three | grep -v '^C /$'

echo
echo "═══ пересоздаём container ═══"
docker rm -f three > /dev/null
docker run --rm \
    --mount type=volume,source=three-vol,target=/vol \
    --mount type=bind,source=/tmp/three-bind,target=/bind \
    --mount type=tmpfs,target=/mem,tmpfs-size=16m \
    alpine:3.21 sh -c '
        echo -n "  volume: "; cat /vol/a.txt 2>/dev/null || echo "пусто"
        echo -n "  bind:   "; cat /bind/host.txt 2>/dev/null || echo "пусто"
        echo -n "  tmpfs:  "; cat /mem/b.txt 2>/dev/null || echo "пусто"
        echo -n "  слой:   "; cat /layer.txt 2>/dev/null || echo "пусто"
    '

Ожидаемый вывод:

text
═══ типы файловых систем внутри container ═══
Filesystem     Type   Size  Used Avail Use% Mounted on
overlay        overlay 58G   21G   35G  38% /
/dev/sda1      ext4    58G   21G   35G  38% /bind
/dev/sda1      ext4    58G   21G   35G  38% /vol
tmpfs          tmpfs   16M     0   16M   0% /mem

═══ что видит docker diff ═══
A /layer.txt

═══ пересоздаём container ═══
  volume: в volume
  bind:   с host
  tmpfs:  пусто
  слой:   пусто

Один запуск показывает всё различие механизмов.

df -T раскрывает устройство: корень — overlay, volume и bind mount — обычная файловая система host (ext4), tmpfs — отдельная файловая система в памяти. Volume и bind mount не случайно выглядят одинаково: named volume — это тоже каталог на диске host, просто под управлением Docker.

docker diff показал только /layer.txt — единственный файл, попавший в writable layer. Именно он и пропал после пересоздания вместе с данными tmpfs.

bash
docker volume rm three-vol demo-data diff-vol > /dev/null 2>&1
rm -rf /tmp/three-bind

Опечатка в пути: -v против --mount

bash
echo "═══ -v с опечаткой в пути host ═══"
docker run --rm -v /tmp/nesuschestvuet:/data alpine:3.21 sh -c 'ls -la /data; echo "container запустился"'
ls -ld /tmp/nesuschestvuet 2>/dev/null && echo "  ← Docker создал пустой каталог"

echo
echo "═══ --mount с той же опечаткой ═══"
docker run --rm --mount type=bind,source=/tmp/nesuschestvuet2,target=/data \
    alpine:3.21 ls /data 2>&1 | tail -2

rmdir /tmp/nesuschestvuet 2>/dev/null

Ожидаемый вывод:

text
═══ -v с опечаткой в пути host ═══
total 0
container запустился
drwxr-xr-x 2 root root 4096 Jul 30 12:15 /tmp/nesuschestvuet
  ← Docker создал пустой каталог

═══ --mount с той же опечаткой ═══
docker: Error response from daemon: invalid mount config for type "bind":
bind source path does not exist: /tmp/nesuschestvuet2

Первый случай опаснее, чем кажется: container работает, каталог пуст, приложение «не видит данных» — и причина неочевидна. Второй сообщает об ошибке сразу.

Ещё одна деталь: созданный Docker каталог принадлежит root, потому что его создал демон. Это отдельный источник проблем с правами (урок 7.5).


Практическое упражнение

Задание. Докажите измерением четыре утверждения.

  1. Данные в container layer переживают stop и start, но не rm.
  2. Данные в volume переживают удаление container'а.
  3. docker diff показывает содержимое container layer и не показывает содержимое volume.
  4. Первое изменение крупного файла из слоя образа заметно дороже последующих.

Каждое утверждение подтвердите командой, вывод которой не допускает двоякого толкования.

Подсказки

Подсказка 1

Для утверждения 3 нужен container, который пишет и в слой, и в volume одновременно.

Подсказка 2

Для утверждения 4 файл должен быть создан в образе (инструкцией RUN), а не в работающем container'е — иначе copy-up не потребуется.

Решение

Показать решение
bash
mkdir -p /tmp/fs-proof && cd /tmp/fs-proof

cat > proof.sh <<'SH'
#!/usr/bin/env bash
set -uo pipefail

VOL=proof-vol
IMG=proof-img
fail=0

ok()  { printf '  ✓ %s\n' "$1"; }
bad() { printf '  ✗ %s\n' "$1"; fail=1; }
eq()  { [ "$2" = "$3" ] && ok "$1" || bad "$1: получено '$2', ожидалось '$3'"; }

cleanup() {
    docker rm -f proof-c > /dev/null 2>&1
    docker volume rm "$VOL" > /dev/null 2>&1
    docker rmi -f "$IMG" > /dev/null 2>&1
}
trap cleanup EXIT

# Образ с крупным файлом — для утверждения 4
docker build -q -t "$IMG" - > /dev/null <<'EOF'
FROM alpine:3.21
RUN dd if=/dev/zero of=/big.bin bs=1M count=200 2>/dev/null
EOF

docker volume create "$VOL" > /dev/null

printf '\n═══ 1. Слой переживает stop/start, но не rm ═══\n'
docker run -d --name proof-c --mount type=volume,source="$VOL",target=/vol \
    "$IMG" sh -c 'sleep 300' > /dev/null
docker exec proof-c sh -c 'echo layer-data > /layer.txt; echo vol-data > /vol/v.txt'

docker stop proof-c > /dev/null && docker start proof-c > /dev/null
sleep 1
eq "после stop/start файл в слое на месте" \
   "$(docker exec proof-c cat /layer.txt)" "layer-data"

printf '\n═══ 3. docker diff видит слой, не видит volume ═══\n'
diff_out="$(docker diff proof-c)"
echo "$diff_out" | grep -q '^A /layer.txt$' \
    && ok "файл слоя в docker diff" || bad "файла слоя нет в docker diff"
echo "$diff_out" | grep -q '/vol/v.txt' \
    && bad "файл volume попал в docker diff" || ok "файла volume нет в docker diff"

printf '\n═══ 2. Volume переживает удаление container ═══\n'
docker rm -f proof-c > /dev/null
eq "данные volume после rm" \
   "$(docker run --rm --mount type=volume,source="$VOL",target=/vol "$IMG" cat /vol/v.txt)" \
   "vol-data"
layer_after="$(docker run --rm "$IMG" sh -c 'cat /layer.txt 2>/dev/null || echo ОТСУТСТВУЕТ')"
eq "данные слоя после rm" "$layer_after" "ОТСУТСТВУЕТ"

printf '\n═══ 4. Цена первого copy-up ═══\n'
docker run --rm "$IMG" sh -c '
    t() {
        s=$(date +%s%N)
        dd if=/dev/zero of=/big.bin bs=1 count=1 conv=notrunc 2>/dev/null
        e=$(date +%s%N)
        echo $(( (e - s) / 1000000 ))
    }
    first=$(t); second=$(t); third=$(t)
    echo "  первая правка:  ${first} мс"
    echo "  вторая правка:  ${second} мс"
    echo "  третья правка:  ${third} мс"
    if [ "$first" -gt "$second" ] && [ "$first" -gt 20 ]; then
        echo "  ✓ первая правка заметно дороже — copy-up подтверждён"
    else
        echo "  ✗ разницы не видно (быстрый диск? файл слишком мал?)"
        exit 1
    fi
' || fail=1

printf '\n═══ ИТОГ ═══\n'
[ "$fail" -eq 0 ] && echo "  все четыре утверждения подтверждены" || echo "  ЕСТЬ ПРОВАЛЫ"
exit "$fail"
SH
chmod +x proof.sh
./proof.sh
echo "КОД: $?"

Ожидаемый вывод:

text
═══ 1. Слой переживает stop/start, но не rm ═══
  ✓ после stop/start файл в слое на месте

═══ 3. docker diff видит слой, не видит volume ═══
  ✓ файл слоя в docker diff
  ✓ файла volume нет в docker diff

═══ 2. Volume переживает удаление container ═══
  ✓ данные volume после rm
  ✓ данные слоя после rm

═══ 4. Цена первого copy-up ═══
  первая правка:  208 мс
  вторая правка:  1 мс
  третья правка:  1 мс
  ✓ первая правка заметно дороже — copy-up подтверждён

═══ ИТОГ ═══
  все четыре утверждения подтверждены
КОД: 0

Три решения, определяющие качество.

Проверки 1 и 3 выполняются на одном container'е. Это не экономия команд: важно, что файл в слое и файл в volume созданы одним процессом, в один момент, одинаковым способом. Различие в поведении тогда объясняется только механизмом хранения, а не обстоятельствами записи.

Утверждение 4 проверяет два условия, а не одно. first > second могло бы выполниться случайно из-за разброса измерений, поэтому добавлено first > 20 мс. Без второго условия тест был бы нестабильным и «подтверждал» бы copy-up даже там, где его нет.

Крупный файл создан инструкцией RUN в образе. Файл, созданный в работающем container'е, уже находится в writable layer — copy-up для него не нужен, и измерение показало бы одинаковое время. Это ровно тот случай, когда неверно поставленный эксперимент даёт правдоподобный, но бессмысленный результат.

Чего проверка не делает. Она не измеряет разницу в скорости записи между container layer и volume. Такое измерение требует устойчивой нагрузки и повторов: разброс на однократном тесте больше самого эффекта. Утверждение «volume быстрее для интенсивной записи» в курсе приводится со ссылкой на документацию, а не как результат этого замера.

bash
cd /tmp && rm -rf /tmp/fs-proof

Проверка результата

bash
docker run -d --name check-fs alpine:3.21 sleep 60
docker exec check-fs sh -c 'echo test > /probe.txt'
docker diff check-fs
docker stop check-fs > /dev/null && docker start check-fs > /dev/null
docker exec check-fs cat /probe.txt
docker rm -f check-fs > /dev/null

Ожидается A /probe.txt в docker diff и сохранившийся файл после перезапуска.

Типичные ошибки

ОшибкаПричинаИсправление
Считают, что данные теряются при docker stopПутают остановку с удалениемТеряются при rm; проверить docker start
Данные базы в container layerНе задумывались о храненииVolume: docker rm неизбежен
Опечатка в пути при -vПозиционный синтаксисDocker создаст пустой каталог; использовать --mount
Ищут данные volume в docker diffСчитают, что видно всёVolumes не входят в слой
Правка большого файла из образа в циклеНе знают про copy-upПервое обращение копирует файл целиком
Заучивают путь /var/lib/docker/overlay2/Он был стабилен раньшеПри containerd image store устройство другое
docker commit для сохранения данныхКажется простымДанные попадают в образ; неуправляемо и неповторяемо

Контрольные вопросы

На понимание:

  1. Что происходит с writable layer при stop, start, rm?
  2. Почему правка одного байта в большом файле может занять сотни миллисекунд?
  3. Почему docker diff не показывает файлы из volume?
  4. Чем -v отличается от --mount при несуществующем пути host?
  5. Кто владеет данными в каждом из трёх механизмов хранения?

На применение:

  1. Как узнать, что будет потеряно при удалении конкретного container'а?
  2. Как выбрать между volume и bind mount для каталога с конфигурацией?
  3. Как найти writable layer container'а на host?

На диагностику:

  1. Приложение «не видит» смонтированные данные, container работает. Первая версия?
  2. После обновления образа пропали загруженные пользователями файлы. Что произошло?

Краткое резюме

  1. Writable layer создаётся при docker create и уничтожается при docker rm.
  2. stop, start и restart данные не трогают — теряются они только при удалении.
  3. docker run --rm, compose down и обновление образа удаляют container, а значит и слой.
  4. Первое изменение файла из слоя образа требует copy-up всего файла.
  5. Container layer подходит для того, что не жалко потерять.
  6. Volume — данные приложения, bind mount — данные host, tmpfs — данные в памяти.
  7. Критерий выбора — кто владеет данными, а не что удобнее набрать.
  8. -v создаёт отсутствующий путь host, --mount сообщает об ошибке.
  9. docker diff показывает содержимое writable layer и игнорирует монтирования.
  10. Расположение writable layer зависит от хранилища образов; путь узнают у Docker.

Официальные источники

ИсточникСсылкаЧто подтверждает
Docker: storage overviewhttps://docs.docker.com/engine/storage/Три механизма, критерии выбора
Docker: volumeshttps://docs.docker.com/engine/storage/volumes/Управление, -v против --mount
Docker: bind mountshttps://docs.docker.com/engine/storage/bind-mounts/Поведение при несуществующем пути
Docker: storage drivershttps://docs.docker.com/engine/storage/drivers/Writable layer, copy-on-write, стоимость записи
Docker: docker diffhttps://docs.docker.com/reference/cli/docker/container/diff/A, C, D и что в них попадает
Docker: containerd image storehttps://docs.docker.com/engine/storage/containerd/Отличия при снапшоттере containerd

Навигация

← Вернуться к разделу
Следующий материал → Volumes
Главное оглавление

Markdown на GitHub ↗