Тариф успешно добавлен в корзину
В корзину
url image

Тома (Volumes) в Docker: хранение и управление данными

Использовать Docker-контейнеры удобно — это изолированная среда, не зависящая от программного обеспечения на сервере, которую можно быстро создавать, пересоздавать и масштабировать. Но эта среда временная, поэтому хранить в контейнере базу данных, загрузки пользователей, кэш, логи или другую важную информацию, не стоит. При пересоздании контейнера все файлы исчезнут вместе с ним. 

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

Хранение данных в Docker: что происходит внутри контейнера

Начнём с теории: почему бы не записывать данные сразу в контейнер? Дело в его устройстве. Docker запускает контейнер из образа, который состоит из слоёв (layers), доступных только для чтения. Когда стартует контейнер, поверх слоёв образа создаётся верхний writable-слой. Любая запись приложения — создание файла, изменение конфигурации, обновление базы в каталоге — попадает именно туда.

Ключевая проблема: writable-слой существует в рамках жизненного цикла конкретного контейнера. Если контейнер удалить (или пересоздать при деплое), слой исчезает вместе со всеми изменениями. Именно поэтому хранить важные данные внутри контейнера не стоит. Это допустимо только для временных файлов или в случаях, если вы используете stateless-сервисы.

Отсюда базовое правило: если данные должны пережить перезапуск или замену контейнера — их лучше вынести из слоя контейнера во внешнее хранилище. Для этой задачи зачастую используют тома (Volumes).

Что такое тома (Volumes)

Тома — это механизм постоянного хранения данных, управляемый самим Docker Engine. Технически, Docker Volume — это объект в Docker, который монтируется в контейнер как каталог, но физически хранится вне writable-слоя контейнера и управляется через Docker CLI/API. Для контейнера он выглядит как обычная директория, а для хоста — как отдельная единица хранения с собственным жизненным циклом.

В отличие от записи в слой контейнера том независим: если удалить контейнер, данные, записанные в том, останутся. Поэтому тома подходят для хранения долговечных данных, которые должны переживать любые изменения контейнера: БД, загрузки пользователей, состояние очереди. Volume можно подключить к одному или нескольким контейнерам (в зависимости от сценария) для совместного использования данных или миграции состояния между версиями контейнеров.

Тома можно использовать, когда нужны переносимость, предсказуемость и минимум ручных настроек путей для файлов. Docker сам размещает данные (обычно в служебной директории Docker), предоставляет команды управления, позволяет использовать драйверы (например, удалённое хранилище). 

Плюсы:

  • отделены от файловой структуры проекта на хосте;
  • проще бэкапить и переносить в рамках Docker-подхода;
  • меньше риска случайно сломать права и структуру каталогов на хосте.

Минусы:

  • сложнее напрямую смотреть данные, как в обычной папке (хотя технически можно);
  • нужно понимать команды управления томами.

Типовые сценарии применения Docker Volumes (томов)

  1. База данных в контейнере. 

Самый очевидный кейс — PostgreSQL/MySQL/Redis (если Redis используется с persistence). Контейнер можно обновлять сколько угодно, но каталог данных должен быть вынесен в Docker Volume, иначе любой деплой пересоздаст контейнер, и данные будут потеряны, приложение стартует «с пустой базой».

  1. Загрузки пользователей и медиа.

Если контейнер принимает файлы (аватары, документы, изображения), хранить их в слое контейнера нельзя. Том позволяет сохранять файлы между перезапусками и переносить контейнер между версиями приложения. В высоконагруженных системах такой подход часто эволюционирует в объектное хранилище, но на старте Docker Volume закрывает задачу быстро и надёжно.

  1. Shared cache, или артефакты сборки.

CI-сценарии часто используют общий том, чтобы шарить кэш зависимостей (например, npm/pip/maven) между контейнерами сборки. Это ускоряет pipeline, но требует контроля: кэш может разрастаться, и его нужно чистить по политике.

  1. Логи и диагностика.

Если логи пишутся в файл, их можно выводить в Docker Volume и затем читать отдельным контейнером-агрегатором или уносить агентом в систему логирования. При этом часто лучше использовать стандартный stdout/stderr драйвер логов Docker, но файловые логи всё ещё встречаются.

  1. Миграции и обслуживание данных.

Отдельный «utility» контейнер (например, busybox/alpine) можно запускать с подключенным томом. Это позволит:

  • сделать архив;
  • проверить структуру файлов;
  • выполнить миграцию формата данных;
  • восстановить данные из резервной копии.

Какие ещё типы хранения существуют в Docker

Кроме Volumes, в Docker существует ещё два типа работы с данными, которые подходят для разных задач.

Bind mount — это прямое подключение конкретной папки/файла хоста в контейнер. Для этого нужно явно указать путь на хостовой ОС, и контейнер начнёт работать с файлами, которые физически лежат в файловой системе хоста. Подходит, если нужно хранить данные дольше, чем работает контейнер, а также иметь возможность работать с ними, не запуская Docker. Например, чтобы смотреть кэш или логи. 

Плюсы:

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

Минусы:

  • сильная зависимость от структуры каталогов на хосте;
  • больше рисков по правам доступа и безопасности: контейнер получает доступ к части ФС хоста;
  • переносимость хуже (на другом сервере путь может не существовать).

tmpfs — временное файловое хранилище в RAM: данные в нём исчезают уже при остановке контейнера, поскольку очищается оперативная память. При рестарте контейнера tmpfs монтируется заново, но пустое. 

Этот механизм идеально подходит для работы с временными данными (например, tmp-файлами или сессиями), которые не требуют длительного хранения. Кроме того, tmpfs обеспечивает максимальную скорость доступа и повышенную безопасность, так как информация не записывается на диск.

Плюсы:

  • максимальная скорость I/O;
  • подходит для чувствительных данных, которые не должны оставаться на диске (токены, временные файлы).

Минусы:

  • данные не сохраняются;
  • есть ограничение памяти.

Как работать с Docker Volumes

Создание тома

docker volume create mydata  # создаём том с именем mydata

Алгоритм дальнейших действий:

  • создаём том;
  • запускаем контейнер, монтируя том в нужный путь;
  • удаляем контейнер — том остаётся;
  • запускаем новый контейнер;
  • монтируем тот же том — данные на месте.

Подключение тома при запуске контейнера

Чаще всего том подключают через -v или --mount. Схема выглядит так: контейнер получает каталог (например, /var/lib/postgresql/data), а Docker подставляет туда том.

Пример с -v:

docker run -d --name db -v mydata:/var/lib/postgresql/data postgres  
  • docker run -d — запускает новый контейнер из указанного образа в Detached-режиме, не блокируя терминал.
  • --name db — присваивает контейнеру имя «db» для удобного обращения (например, в командах stop или logs).
  • -v mydata:/var/lib/postgresql/data — монтирует том с именем «mydata»  (источник) в путь «/var/lib/postgresql/data» внутри контейнера (цель). Если том не существует, Docker создаст его автоматически.
  • postgres — имя Docker-образа (в данном случае — официальный образ PostgreSQL).

Пример с --mount (более гибкий синтаксис, рекомендуется для сложных случаев):

docker run -d --name db --mount source=mydata,target=/var/lib/postgresql/data,type=volume postgres

Важно: параметры разделяются запятыми без пробелов (иначе команда не сработает)

  • docker run -d — запускает новый контейнер из указанного образа в Detached-режиме, не блокируя терминал.
  • --name db — присваивает контейнеру имя «db».
  • --mount source=mydata,target=/var/lib/postgresql/data,type=volume— монтирует том. Здесь:
    • source=mydata — имя тома (источник);
    • target=/var/lib/postgresql/data — путь внутри контейнера (цель);
    • type=volume — указывает тип монтирования (том, а не bind или tmpfs).
  • postgres — имя Docker-образа (PostgreSQL).

По сравнению с -v, этот синтаксис даёт больше опций — например, можно добавить readonly=true для монтирования в режиме только чтения или другие параметры (например,volume-opt для специфических настроек).

Просмотр списка томов и инспекция

docker volume ls  # — выведет список всех томов на хосте.

docker volume inspect mydata  # — покажет детали тома (путь, драйвер, метки).

В реальной эксплуатации эти команды помогают понять, какие тома существуют и где они расположены на хосте. Для оценки занимаемого места используйте docker system df -v или инструменты ОС (например, du -sh по пути из docker volume inspect).

Удаление тома

docker volume rm mydata # — удаляет том (только если он не используется контейнером).

Для массовой очистки:

docker volume prune # — удаляет все неиспользуемые тома (с подтверждением).

Обратите внимание. Тома, которые не монтированы ни в одном контейнере, даже остановленном, в терминологии Docker называются висячими). Docker не добавляет к ним специальную визуальную метку в списке (как в docker volume ls), но их можно выявить и пометить с помощью фильтров. Например:

docker volume ls -f dangling=true

Совместное использование тома несколькими контейнерами

Docker Volume удобен, когда один контейнер записывает данные, а другой читает. Но важно помнить про конкурентный доступ: если два контейнера одновременно записывают данные в одни и те же файлы без координации, можно получить гонку данных (race condition) или их повреждение. Для таких сценариев лучше проектировать разделение по каталогам, режимы read-only, либо использовать специализированное сетевое хранилище/БД.

Пример:

docker run -d --name writer -v mydata:/data ubuntu bash -c "echo 'Data' > /data/file.txt"

docker run -d --name reader -v mydata:/data:ro ubuntu cat /data/file.txt # — монтирует в read-only режиме.

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

Управление томами включает не только их создание и подключение, но и дисциплину обслуживания.

Что важно делать:

  • документировать, какие тома относятся к каким сервисам;
  • удалять тома только после понимания последствий;
  • очищать неиспользуемые тома, чтобы не забивать диск;
  • при необходимости — мигрировать данные на другой хост.

Хорошая практика — давать томам осмысленные имена (например, <имя проекта>_<имя сервиса>_<окружение(dev, prod,stage)> — bestproject_pgdata_prod, и др.), а не полагаться на случайные идентификаторы. Так администратору проще сопоставить том и контейнер даже спустя месяцы.

Тома часто являются единственным хранилищем критических данных. Поэтому для продакшена стоит заранее продумать бэкапы и тест восстановления.

Бэкап тома

Чтобы сделать резервную копию, запустите utility-контейнер:

docker run --rm -v mydata:/data -v "$(pwd -P)":/backup ubuntu tar czf /backup/mydata.tar.gz -C /data .  # — архивирует данные тома в файл на хосте.

Восстановление из бэкапа

docker run --rm -v mydata:/data -v "$(pwd -P)":/backup ubuntu tar xzf /backup/mydata.tar.gz -C /data #Распаковывает архив в том.

Миграция тома на другой хост

Сначала экспортируйте:

docker run --rm -v mydata:/data -v "$(pwd -P)":/backup ubuntu cp -a /data/. /backup/

Затем на новом хосте создайте том и импортируйте:

docker volume create mydata
docker run --rm -v mydata:/data -v "$(pwd -P)":/backup ubuntu cp -a /backup/. /data/

Использование Volumes в Docker Compose

В Docker Compose тома описываются декларативно: мы фиксируем, какой сервис какой том монтирует и куда. Это делает окружение повторяемым: один и тот же compose-файл воспроизводит инфраструктуру на другом хосте (с поправкой на драйверы и политики).

Типовой шаблон: 

```yaml
services:  
  db:  
    image: postgres  
    volumes:  
      - pgdata:/var/lib/postgresql/data  
volumes:  
  pgdata:  

```
  • Раздел services монтирует том в контейнер.
  • Раздел volumes объявляет именованные тома.
  • При выполнении docker compose up том будет создан автоматически (если его нет), и контейнер будет работать с постоянным хранилищем.

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

При удалении сервисов docker compose down все Volumes, описанные в конфигурационном файле, останутся вместе с данными на месте. Для удаления томов потребуется выполнить: 

docker compose down -v # — останавливает сервисы и удаляет тома (будьте осторожны!).

Лучшие практики и частые ошибки

Best practice

  • Считайте контейнер одноразовым, а данные — отдельным объектом. Контейнер можно безопасно пересоздать в любой момент, если данные вынесены правильно.
  • Используйте Docker Volume в продакшене по умолчанию, а bind mount оставляйте для dev и точечного проброса конфигов/сертификатов.
  • Давайте томам осмысленные имена и ведите карту соответствия: сервис → том → путь монтирования → политика бэкапа. Это ускоряет поиск нужных данных и снижает риск удалить/забыть про критичный том.
  • Ограничивайте доступ: read-only там, где это возможно. Так вы защищаете данные от случайной записи/порчи и уменьшаете последствия компрометации сервиса.
  • Если контейнеру достаточно читать данные (например, отдавать статику), монтируйте том в режиме RO. Это делает поведение сервиса предсказуемее и предотвращает «тихие» изменения данных внутри тома.
  • Наличие Docker Volume само по себе не равно защите от потери данных. Нужны регулярные бэкапы и тестовое восстановление. Продумайте их. Бэкап без регулярной проверки восстановления даёт ложное чувство безопасности.
  • Следите за ростом данных и «висячими» томами. Это помогает избегать внезапного переполнения диска.
  • Периодически проводите аудит хранилища. Тома не исчезают вместе с контейнерами, и рост их количества не всегда можно заметить по размеру образов/контейнеров. В результате кэши, логи и временные файлы в Volumes могут накапливаться месяцами и в какой-то момент занять всё свободное место на диске.

Частые ошибки

  • Использовать bind mount и volumes без понимания различий. Это может приводить к конфликтам прав, появлению «скрытых» файлов и формированию разной структуры данных на разных хостах.
  • Монтировать том в непустую директорию без учёта эффектов монтирования. Если по пути монтирования в образе уже есть файлы, они могут стать недоступными (скрыться за точкой монтирования). Кроме того, при первом подключении пустого Volume Docker может скопировать в него содержимое директории из контейнера.
  • Монтировать с хоста каталог /var/lib/docker. Это внутреннее хранилище Docker Engine. Прямой доступ к нему (с хоста или из контейнера) может нарушить работу Docker и привести к повреждению данных.
  • Давать случайные имена томам —  это затрудняет понимание, какой том к какому контейнеру относится.
  • Не учитывать конкурентную запись нескольких контейнеров в один и тот же том без синхронизации, что может приводить к состояниям гонки и повреждению данных.

Заключение

Docker делает контейнер удобной единицей доставки и запуска приложения, но контейнер не должен быть хранилищем. Постоянные данные нужно отделять от жизненного цикла контейнера — и для этого тома являются базовым инструментом. 

Правильно выбранный тип монтирования, понятные правила именования и управления, а также продуманные бэкапы превращают Docker Volume в надёжный фундамент для stateful-сервисов, не ломая главный принцип Docker: контейнер можно пересоздать в любой момент.

Этот материал был полезен?

Скидка новым клиентам
Закажите сервер сегодня и получите скидку на первый месяц аренды!
Наш сайт использует cookies Вы можете отключить их в настройках браузера, но это может ограничить функционал. Оставаясь на сайте, вы соглашаетесь с использованием cookies.