Глиф Учебники

Урок 5. Данные: тома и папки

Курс «Docker» · урок 5 из 10 · 5 минут чтения

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

Почему данные пропадают

Вспомните устройство контейнера: образ только для чтения, а сверху — слой для записи, свой у каждого контейнера. Удалили контейнер — удалился и слой. Проверьте сами:

Терминал
$ docker run --name test ubuntu:24.04 sh -c 'echo привет > /root/file.txt'
$ docker rm test
test
$ docker run --rm ubuntu:24.04 cat /root/file.txt
cat: /root/file.txt: No such file or directory

Первый контейнер создал файл и завершился. Его удалили (docker rm в ответ печатает имя удалённого контейнера) — и новый контейнер из того же образа файла не видит: образ не изменился.

Именованный том

Том (volume) — хранилище, которым управляет Docker. Он существует отдельно от контейнеров: контейнер удаляют, том остаётся. Подключается ключом -v имя-тома:путь-в-контейнере:

Терминал
$ docker run --rm -v mydata:/data ubuntu:24.04 sh -c 'echo привет > /data/file.txt'
$ docker run --rm -v mydata:/data ubuntu:24.04 cat /data/file.txt
привет

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

Без тома /root/file.txt ubuntu:24.04 контейнер test docker rm test слой для записи удалён файла нет ubuntu:24.04 новый контейнер С томом -v mydata:/data /data ubuntu:24.04 контейнер удалён (--rm) том mydata file.txt /data/file.txt ubuntu:24.04 новый контейнер видит файл пишет читает
Без тома файл исчезает вместе со слоем для записи контейнера, а в томе mydata он остаётся и виден новому контейнеру.

Управление томами:

Bash
docker volume ls
docker volume inspect mydata
docker volume rm mydata

docker volume inspect показывает, где том лежит на диске хоста: обычно /var/lib/docker/volumes/mydata/_data. Файлы там можно читать с правами root, но менять их, пока том используется, не стоит.

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

docker volume rm удаляет том со всеми данными без вопросов и без корзины. Удалить том, который подключён к существующему контейнеру, даже остановленному, Docker не даст — но если контейнер уже удалён, ничего не остановит. Проверяйте имя тома перед удалением.

Папка хоста

Второй способ — подключить в контейнер обычную папку с хоста (bind mount). Тот же ключ -v, но слева путь, а не имя:

Bash
mkdir -p ~/site
echo '<h1>Привет из Docker</h1>' > ~/site/index.html
docker run -d --name site -p 8080:80 -v "$HOME/site":/usr/share/nginx/html:ro nginx:alpine

Nginx отдаёт страницы из /usr/share/nginx/html, а туда подключена папка ~/site. Откройте http://localhost:8080 — будет ваша страница. Поправьте файл на хосте и обновите страницу: изменения видны сразу, контейнер пересоздавать не нужно.

Правила записи:

Именованный том -v mydata:/data на хосте: том mydata /var/lib/docker/volumes/mydata/_data в контейнере /data слово без косой черты — имя тома; пустой том получает файлы образа Папка хоста -v "$HOME/site":/usr/share/nginx/html:ro на хосте: папка ~/site ваши файлы, правки видны сразу в контейнере /usr/share/nginx/html путь с / или ./ — папка хоста; она закрывает файлы образа по этому пути
Именованный том хранит Docker в /var/lib/docker/volumes, а папка хоста подключается как есть и закрывает файлы образа по своему пути.

Подключённая папка закрывает то, что было по этому пути в образе. Если подключить пустую папку в /usr/share/nginx/html, стандартная страница Nginx исчезнет, а не скопируется в папку, как у тома. Кроме того, всё, что контейнер пишет в подключённую папку, сразу меняется на хосте — подключение -v /:/host даёт контейнеру доступ ко всей системе.

Права на файлы

Программа в контейнере работает от своего пользователя — с номером (UID), который может не совпадать с вашим на хосте. Отсюда частая ошибка Permission denied при записи в подключённую папку. Решения: выдать права на папку пользователю с нужным UID (sudo chown -R 999:999 ~/data — номер смотрите в описании образа) или использовать именованный том — с ним Docker разбирается сам.

Анонимные тома

Многие образы баз данных сами объявляют том для данных (инструкция VOLUME в Dockerfile). Если не подключить туда свой, Docker создаст анонимный том со случайным именем из 64 знаков. Данные в нём не пропадут при docker rm, но новый контейнер получит новый пустой том — и база «пропадёт». Анонимные тома копятся и занимают место, их видно в docker volume ls.

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

Без своего тома контейнер db старый, удалён анонимный том данные базы пересоздали контейнер db новый анонимный том пусто новый контейнер получил новый пустой том — база «пропала» С томом -v pgdata:/var/lib/postgresql контейнер db старый, удалён pgdata данные базы контейнер db новый новый контейнер подключил тот же том — база на месте
Без своего тома новый контейнер базы получает новый пустой анонимный том, а с томом pgdata подключает тот же, и база остаётся.

Пример: PostgreSQL с томом

Удалите контейнер db из прошлого урока (docker rm -f db) и создайте его заново — теперь с томом:

Bash
docker run -d --name db \
  -e POSTGRES_PASSWORD=Smena-Parol-2026 \
  -v pgdata:/var/lib/postgresql \
  -p 127.0.0.1:5432:5432 \
  --restart unless-stopped \
  postgres:18

Обратная косая черта \ в конце строки переносит длинную команду на следующую строку. Теперь контейнер db можно удалить и создать заново с тем же томом — база останется на месте.

Путь для данных меняется между версиями образов. Для postgres:18 и новее том подключают в /var/lib/postgresql, для 17 и старше — в /var/lib/postgresql/data. Всегда сверяйтесь с описанием образа на Docker Hub: ошибка в пути — и данные окажутся в анонимном томе.

Резервная копия тома

Том — обычные файлы, их можно упаковать в архив временным контейнером:

Bash
docker run --rm -v pgdata:/from:ro -v "$PWD":/backup alpine tar czf /backup/pgdata.tar.gz -C /from .

В текущей папке появится pgdata.tar.gz. Восстановление — в новый пустой том:

Bash
docker run --rm -v pgdata2:/to -v "$PWD":/backup alpine tar xzf /backup/pgdata.tar.gz -C /to

Копировать файлы работающей базы данных опасно: копия может оказаться несогласованной. Остановите контейнер с базой перед копированием тома (docker stop db) или делайте копию средствами самой базы — для PostgreSQL это pg_dump.

Что выбрать

ЗадачаСпособ
Данные базы, загрузки пользователейименованный том
Файлы сайта, которые вы правите на хостепапка хоста, часто с :ro
Свой файл настроек для программыпапка или файл хоста с :ro
Временные файлы, которые не жалконичего — слой контейнера

Коротко

Проверьте себя

1. Как подключить в контейнер именованный том appdata в папку /data?
2. Чем -v site:/usr/share/nginx/html отличается от -v ./site:/usr/share/nginx/html?
3. Контейнер с базой удалили и создали заново без -v, и база пустая. Почему?
4. Что делает :ro в -v "$HOME/site":/usr/share/nginx/html:ro?