Урок 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 создал его при первом запуске. Оба контейнера удалились, а файл в томе остался.
Управление томами:
docker volume ls
docker volume inspect mydata
docker volume rm mydatadocker volume inspect показывает, где том лежит на диске хоста: обычно /var/lib/docker/volumes/mydata/_data. Файлы там можно читать с правами root, но менять их, пока том используется, не стоит.
Удобная особенность: если том пустой, а в образе по этому пути уже есть файлы, Docker при первом подключении скопирует их в том. Так в том попадают, например, настройки по умолчанию.
docker volume rm удаляет том со всеми данными без вопросов и без корзины. Удалить том, который подключён к существующему контейнеру, даже остановленному, Docker не даст — но если контейнер уже удалён, ничего не остановит. Проверяйте имя тома перед удалением.
Папка хоста
Второй способ — подключить в контейнер обычную папку с хоста (bind mount). Тот же ключ -v, но слева путь, а не имя:
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:alpineNginx отдаёт страницы из /usr/share/nginx/html, а туда подключена папка ~/site. Откройте http://localhost:8080 — будет ваша страница. Поправьте файл на хосте и обновите страницу: изменения видны сразу, контейнер пересоздавать не нужно.
Правила записи:
- путь слева должен быть абсолютным (
/home/ivan/site,"$HOME/site","$PWD/site") или начинаться с./(относительные пути понимает Docker Engine 23 и новее). Слово без косой черты, напримерsite, Docker сочтёт именем тома; :roв конце (read-only) — контейнер может только читать. Ставьте, если программе не нужно писать;- если папки на хосте нет,
-vсоздаст её — пустую и от root. Опечатка в пути даёт пустую папку вместо данных.
Подключённая папка закрывает то, что было по этому пути в образе. Если подключить пустую папку в /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.
Вывод: для базы всегда подключайте именованный том в тот путь, который указан в описании образа.
Пример: PostgreSQL с томом
Удалите контейнер db из прошлого урока (docker rm -f db) и создайте его заново — теперь с томом:
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: ошибка в пути — и данные окажутся в анонимном томе.
Резервная копия тома
Том — обычные файлы, их можно упаковать в архив временным контейнером:
docker run --rm -v pgdata:/from:ro -v "$PWD":/backup alpine tar czf /backup/pgdata.tar.gz -C /from .В текущей папке появится pgdata.tar.gz. Восстановление — в новый пустой том:
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 |
| Временные файлы, которые не жалко | ничего — слой контейнера |
Коротко
- Слой для записи удаляется вместе с контейнером; нужное держат в томах или папках хоста.
-v имя:/путь— именованный том, Docker хранит его в/var/lib/docker/volumes.-v /абсолютный/путь:/путь— папка хоста;:ro— только чтение.- Подключённая папка закрывает содержимое образа по этому пути; пустой том, наоборот, заполняется из образа.
- Без своего тома база попадает в анонимный том, и новый контейнер её не увидит.
docker volume rmудаляет данные навсегда; перед копированием базы остановите контейнер.