7.1. Файловая система container
Цели
После этого материала вы сможете:
- сказать, что произойдёт с записанными данными при
stop,start,restartиrm; - найти writable layer конкретного container на host;
- объяснить, почему запись больших объёмов в container layer обходится дорого;
- увидеть список изменений файловой системы container одной командой;
- выбрать между volume, bind mount и
tmpfsпо сути задачи, а не по привычке.
Предварительные знания
- 3.2. Слои и copy-on-write — механизм OverlayFS;
- 4.2. Жизненный цикл container — состояния и переходы.
Ключевые термины
| Термин | Объяснение |
|---|---|
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.
Три механизма хранения
| Volume | Bind mount | tmpfs | |
|---|---|---|---|
| Кто управляет | Docker | Вы | Ядро |
| Где данные | /var/lib/docker/volumes/ | Любой путь host | Оперативная память |
Переживает docker rm | Да | Да | Нет |
| Переносимость между машинами | Высокая | Низкая (абсолютные пути) | — |
| Работает в Swarm и Kubernetes | Да | Ограниченно | Да |
| Скрывает содержимое образа | Только если непустой | Всегда | Всегда |
| Наполняется из образа при первом монтировании | Да | Нет | Нет |
| Права доступа | Наследуются от образа | От host | Задаются при монтировании |
| Резервное копирование | docker run со вспомогательным container | Обычными средствами host | Невозможно |
| Следы на диске | Есть | Есть | Нет |
Критерий выбора — не «что удобнее», а кто владеет данными:
| Задача | Механизм | Почему |
|---|---|---|
| Данные базы, загруженные файлы | Volume | Владелец — приложение; Docker отвечает за расположение |
| Исходный код при разработке | Bind mount | Владелец — вы; правки нужны мгновенно |
| Конфигурационный файл с host | Bind mount, read-only | Владелец — host; изменять из container не нужно |
| Сокет Docker для CI | Bind mount | Объект существует на host |
Временные файлы, /tmp при read-only | tmpfs | Не должны переживать перезапуск |
| Секреты в процессе работы | tmpfs | Не должны попадать на диск |
| Кэш, восстановимый при потере | Volume или tmpfs | По объёму и цене прогрева |
-v против --mount
Два синтаксиса делают почти одно и то же:
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:
docker inspect <container> --format '{{.GraphDriver.Data.UpperDir}}'
Пустой результат означает containerd image store — тогда добраться до слоя напрямую сложнее, и это ещё один довод в пользу volumes: их расположение стабильно и не зависит от хранилища образов.
docker diff
Docker умеет показать, чем файловая система container'а отличается от образа:
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».
Команды и примеры
Что переживает остановку, а что — удаление
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 "файла нет — данные потеряны"'
Ожидаемый вывод:
═══ после записи ═══
записано до остановки
═══ после stop и start ═══
записано до остановки
═══ после restart ═══
записано до остановки
═══ после rm и нового run из того же образа ═══
cat: can't open '/root/data.txt': No such file or directory
файла нет — данные потеряны
Три первых блока опровергают распространённое заблуждение: остановка данные не трогает. Четвёртый показывает настоящую границу — удаление container'а.
То же самое с volume
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'
Ожидаемый вывод:
═══ container удалён (--rm), читаем другим container'ом ═══
данные в volume
═══ третий container видит те же данные ═══
данные в volume
Данные пережили удаление обоих container'ов и доступны третьему — по другому пути монтирования. Это и есть смысл volume: данные не принадлежат container'у.
Где находится writable layer
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
Ожидаемый вывод при классическом хранилище:
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:
GraphDriver пуст — используется containerd image store
Storage Driver: overlayfs
Оба варианта нормальны. Второй — ещё один довод за volumes: docker volume inspect даёт стабильный путь независимо от хранилища образов.
docker diff: что будет потеряно
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
Ожидаемый вывод:
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/hosts | Copy-up: файл скопирован из слоя образа и изменён |
D .../this.py | Whiteout: файл образа скрыт, но в слое образа остался |
Каталог /etc помечен C, потому что изменилось его содержимое — это ожидаемо и не означает, что изменён сам каталог.
Теперь то же самое с volume:
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
Ожидаемый вывод:
═══ docker diff ═══
C /app
═══ файл при этом на месте ═══
результат
Файл записан и читается, но docker diff его не показывает: он не в слое, а в volume. Отсюда практическое применение команды — проверить, что состояние не оседает в container layer перед пересозданием.
Строка C /app появляется потому, что точка монтирования создаётся в слое.
Цена copy-up
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
Ожидаемый вывод:
═══ изменение 1 байта в файле из слоя образа ═══
правка 1 байта: 214 мс
═══ повторная правка того же файла ═══
правка 1 байта: 1 мс
Первая правка стоила 214 мс, вторая — 1 мс. Разница — это copy-up: файл на 200 MB был целиком скопирован в writable layer. Второй раз копировать уже нечего.
Именно поэтому файлы базы данных не держат в container layer: при интенсивной записи стоимость первого обращения платится за каждый файл.
Три механизма рядом
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 "пусто"
'
Ожидаемый вывод:
═══ типы файловых систем внутри 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.
docker volume rm three-vol demo-data diff-vol > /dev/null 2>&1
rm -rf /tmp/three-bind
Опечатка в пути: -v против --mount
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
Ожидаемый вывод:
═══ -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).
Практическое упражнение
Задание. Докажите измерением четыре утверждения.
- Данные в container layer переживают
stopиstart, но неrm. - Данные в volume переживают удаление container'а.
docker diffпоказывает содержимое container layer и не показывает содержимое volume.- Первое изменение крупного файла из слоя образа заметно дороже последующих.
Каждое утверждение подтвердите командой, вывод которой не допускает двоякого толкования.
Подсказки
Подсказка 1
Для утверждения 3 нужен container, который пишет и в слой, и в volume одновременно.
Подсказка 2
Для утверждения 4 файл должен быть создан в образе (инструкцией RUN), а не в работающем container'е — иначе copy-up не потребуется.
Решение
Показать решение
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 "КОД: $?"
Ожидаемый вывод:
═══ 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 быстрее для интенсивной записи» в курсе приводится со ссылкой на документацию, а не как результат этого замера.
cd /tmp && rm -rf /tmp/fs-proof
Проверка результата
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 для сохранения данных | Кажется простым | Данные попадают в образ; неуправляемо и неповторяемо |
Контрольные вопросы
На понимание:
- Что происходит с writable layer при
stop,start,rm? - Почему правка одного байта в большом файле может занять сотни миллисекунд?
- Почему
docker diffне показывает файлы из volume? - Чем
-vотличается от--mountпри несуществующем пути host? - Кто владеет данными в каждом из трёх механизмов хранения?
На применение:
- Как узнать, что будет потеряно при удалении конкретного container'а?
- Как выбрать между volume и bind mount для каталога с конфигурацией?
- Как найти writable layer container'а на host?
На диагностику:
- Приложение «не видит» смонтированные данные, container работает. Первая версия?
- После обновления образа пропали загруженные пользователями файлы. Что произошло?
Краткое резюме
- Writable layer создаётся при
docker createи уничтожается приdocker rm. stop,startиrestartданные не трогают — теряются они только при удалении.docker run --rm,compose downи обновление образа удаляют container, а значит и слой.- Первое изменение файла из слоя образа требует copy-up всего файла.
- Container layer подходит для того, что не жалко потерять.
- Volume — данные приложения, bind mount — данные host,
tmpfs— данные в памяти. - Критерий выбора — кто владеет данными, а не что удобнее набрать.
-vсоздаёт отсутствующий путь host,--mountсообщает об ошибке.docker diffпоказывает содержимое writable layer и игнорирует монтирования.- Расположение writable layer зависит от хранилища образов; путь узнают у Docker.
Официальные источники
| Источник | Ссылка | Что подтверждает |
|---|---|---|
| Docker: storage overview | https://docs.docker.com/engine/storage/ | Три механизма, критерии выбора |
| Docker: volumes | https://docs.docker.com/engine/storage/volumes/ | Управление, -v против --mount |
| Docker: bind mounts | https://docs.docker.com/engine/storage/bind-mounts/ | Поведение при несуществующем пути |
| Docker: storage drivers | https://docs.docker.com/engine/storage/drivers/ | Writable layer, copy-on-write, стоимость записи |
Docker: docker diff | https://docs.docker.com/reference/cli/docker/container/diff/ | A, C, D и что в них попадает |
| Docker: containerd image store | https://docs.docker.com/engine/storage/containerd/ | Отличия при снапшоттере containerd |
Навигация
← Вернуться к разделу
Следующий материал → Volumes
Главное оглавление