Урок 5 из 8 · 20 мин · обновлено

Данные: тома и монтирование папок

Почему данные внутри контейнера пропадают вместе с ним, как сохранить их в томе на примере PostgreSQL, как подключить папку с компьютера к контейнеру и как управлять томами.

Контейнер забывает

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

Проверим на PostgreSQL. Запустим базу без тома:

Терминал
docker run -d --name db -e POSTGRES_PASSWORD=secret postgres:16

-e передаёт в контейнер переменную окружения: образ postgres требует задать пароль администратора. Пароль secret годится только для учебного примера.

Создадим таблицу. Пока используем готовую команду — что она делает, разберём в уроке 8:

Терминал
docker exec -it db psql -U postgres -c "CREATE TABLE notes (text TEXT); INSERT INTO notes VALUES ('Привет');"

Удалим контейнер и запустим новый — таблицы там не будет. Данные жили внутри старого контейнера и исчезли вместе с ним.

Терминал
docker rm -f db

Флаг -f останавливает и удаляет контейнер одной командой.

Тома

Том — хранилище данных, которым управляет Docker. Он существует отдельно от контейнеров: удалили контейнер — том остался.

Запустим базу с томом:

Терминал
docker run -d --name db -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql/data postgres:16

-v pgdata:/var/lib/postgresql/data — подключить том pgdata к папке, где PostgreSQL 16 хранит данные. Если тома ещё нет, Docker создаст его сам.

Повторим эксперимент: создадим таблицу, удалим контейнер и запустим новый с тем же томом:

Терминал
docker exec -it db psql -U postgres -c "CREATE TABLE notes (text TEXT); INSERT INTO notes VALUES ('Привет');"
docker rm -f db
docker run -d --name db -e POSTGRES_PASSWORD=secret -v pgdata:/var/lib/postgresql/data postgres:16
docker exec -it db psql -U postgres -c "SELECT * FROM notes;"
Результат
  text
--------
 Привет
(1 row)

Таблица на месте: новый контейнер нашёл данные в томе.

Путь к данным зависит от программы и иногда — от версии. Его указывают в описании образа на Docker Hub. Это ещё одна причина фиксировать тег: у новых основных версий PostgreSQL путь к данным в официальном образе может отличаться.

Монтирование папки

Второй способ — подключить к контейнеру папку с вашего компьютера. Удобно, когда вы правите файлы и хотите сразу видеть результат. Вернёмся к сайту из прошлого урока: запустите nginx и подключите папку my-site туда, откуда он отдаёт страницы.

В терминале Linux, macOS или Git Bash:

Терминал
docker run -d --name live -p 8080:80 -v "$(pwd)":/usr/share/nginx/html:ro nginx:alpine

В PowerShell на Windows вместо "$(pwd)" пишут "${PWD}".

:ro в конце — только для чтения: контейнер не сможет менять ваши файлы. Измените index.html в папке, обновите страницу — изменения видны сразу, без сборки образа. Когда закончите, удалите контейнер: docker rm -f live.

Когда что использовать:

  • том — для данных программ: базы данных, загруженные файлы;
  • монтирование папки — для файлов, которые вы правите сами: код и страницы при разработке.

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

Терминал
docker volume ls             # список томов
docker volume inspect pgdata # подробности: где лежит, когда создан
docker volume rm pgdata      # удалить том

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

Попробуйте сами. Запустите PostgreSQL с томом notes-data, создайте таблицу и запись, удалите контейнер, запустите новый с тем же томом и убедитесь, что запись на месте. В конце удалите и контейнер, и том.

Решение
Терминал
docker run -d --name notes -e POSTGRES_PASSWORD=secret -v notes-data:/var/lib/postgresql/data postgres:16
docker exec -it notes psql -U postgres -c "CREATE TABLE notes (text TEXT); INSERT INTO notes VALUES ('Запись из урока 5');"
docker rm -f notes
docker run -d --name notes -e POSTGRES_PASSWORD=secret -v notes-data:/var/lib/postgresql/data postgres:16
docker exec -it notes psql -U postgres -c "SELECT * FROM notes;"

Если exec сразу после запуска ответил ошибкой подключения — подождите несколько секунд: базе нужно время, чтобы стартовать.

Уборка:

Терминал
docker rm -f notes
docker volume rm notes-data

Мини-тест: проверьте себя

Закрепите урок: несколько вопросов, разбор ответов — в конце.

  1. Вы создали таблицу в базе внутри контейнера без тома, затем удалили контейнер. Что с таблицей?

  2. Что делает часть -v pgdata:/var/lib/postgresql/data?

  3. Когда удобнее монтировать папку с компьютера, а не том?