Docker Volumes против Bind Mounts: правильное сохранение данных контейнера

  1. Главная
  2. Блог
  3. DevOps

DevOps

Docker Volumes против Bind Mounts: Правильное сохранение данных контейнера

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

9 мин чтения
Тома Docker против монтирования привязки: правильное сохранение данных контейнера

Главное

  • Доступный для записи слой контейнера удаляется вместе с контейнером, поэтому важные данные необходимо смонтировать.
  • Именованные тома управляются Docker и являются обычным выбором для баз данных и производственных данных.
  • Привязка сопоставляет папку хоста, что делает их идеальными для живого кода во время разработки.
  • docker compose down -v удаляет тома, поэтому используйте его осторожно и сохраняйте проверенные резервные копии.

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

В этом руководстве объясняется, как каждый из них работает и как выбрать. Команды и файлы здесь представляют собой стандартные примеры, основанные на задокументированном поведении Docker, и мы не запускали их для этой статьи, поэтому сначала попробуйте их на одноразовых данных. Подробности могут различаться в разных версиях Docker и в Docker Desktop. Если вы новичок в контейнерах, начните с нашего учебника по Docker для начинающих.

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

Образ Docker состоит из слоев, доступных только для чтения. Когда контейнер запускается, Docker добавляет сверху тонкий записываемый слой, и все изменения передаются туда. Этот слой выдерживает остановку и перезапуск, но удаляется при удалении контейнера.

docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# ... create tables and add data ...
docker rm -f db
docker run -d --name db -e POSTGRES_PASSWORD=devonly postgres:17
# The data you added is not there

Это сделано специально, поскольку позволяет свободно заменять контейнеры. Это означает, что все, что вам нужно сохранить, должно находиться вне контейнера. Есть три способа сделать это:

Тип Хранится в Выдерживает удаление контейнера?
Именованный том Область, управляемая Docker Да
Привязать крепление Путь хоста, который вы выбираете Да
монтирование tmpfs Память хоста Нет

Тома Docker и привязка монтируются рядом

Аспект Именованный том Привязать крепление
Управляется Докер ты
Расположение Место хранения Docker Любой путь на хосте
Зависит от папок хоста? Нет Да
Редактирование с хостера Неудобный дизайн Легко, изменения появляются мгновенно
Пустая цель, предварительно заполненная из изображения? Да Нет, путь к хосту скрывает это.
Команды Docker CLI Да, docker volume Нет
Драйвера для удаленного хранилища Да Нет
Лучшее для Базы данных, производственные данные Исходный код в разработке

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

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

docker volume create pgdata

docker run -d --name db \
  -e POSTGRES_PASSWORD=devonly \
  -v pgdata:/var/lib/postgresql/data \
  postgres:17

Теперь файлы базы данных находятся в pgdata. Удалите контейнер и запустите новый с тем же томом, и ваши данные все равно останутся там. В Linux тома обычно находятся в папке /var/lib/docker/volumes/, но вам не следует редактировать эти файлы напрямую. В Docker Desktop они живут внутри виртуальной машины, а не в обычной папке.

Путь внутри контейнера зависит от изображения, поэтому проверьте документацию изображения. Монтирование по неправильному пути — классическая ошибка: кажется, что все работает, но данные по-прежнему записываются на уровень контейнера. Более новые основные версии образа также могут изменить этот путь, поэтому перед обновлением прочтите примечания к выпуску.

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

Привязать ездовых животных

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

docker run -d --name web \
  -p 8080:80 \
  -v "$(pwd)/site:/usr/share/nginx/html:ro" \
  nginx:1.27

Отредактируйте файл в site/, обновите браузер, и вы увидите изменения. :ro делает монтирование доступным только для чтения внутри контейнера, что является хорошей привычкой, когда контейнеру нет необходимости писать туда.

Привязные крепления имеют некоторые компромиссы:

  • Они привязывают вас к хосту. Путь должен существовать на каждой машине, поэтому настройки менее переносимы.
  • Они скрывают содержимое изображения. Если вы смонтируете поверх /app, все, что там было, станет невидимым. Типичным примером является пропажа node_modules.
  • Они раскрывают хост. Контейнер с доступным для записи монтированием может изменять или удалять реальные файлы хоста. Никогда не монтируйте чувствительные пути, такие как / или сокет Docker, если вы полностью не понимаете риск.
  • Производительность может варьироваться. В Docker Desktop для macOS и Windows общий доступ к файлам пересекает границы виртуализации и может быть медленнее, чем в Linux.

tmpfs монтирует

Монтирование tmpfs находится в памяти хоста и никогда не записывается на уровень контейнера. Он исчезает, когда контейнер останавливается, поэтому подходит для временных файлов, кешей и недолговечных конфиденциальных данных:

docker run -d --tmpfs /app/cache:size=64m myapp:1.0

tmpfs доступен на хостах Linux. Он также может ускорить работу баз данных в одноразовых тестовых средах, где вам не нужно заботиться о хранении данных.

-v или –mount?

Оба флага работают. --mount длиннее, но он более явный, и многие предпочитают его в скриптах:

# Short form
docker run -v pgdata:/var/lib/postgresql/data postgres:17

# Explicit form
docker run --mount type=volume,source=pgdata,target=/var/lib/postgresql/data postgres:17

# Bind mount, read-only
docker run --mount type=bind,source="$(pwd)"/site,target=/usr/share/nginx/html,readonly nginx:1.27

Есть одно существенное отличие. При выборе -v для вас создается отсутствующий путь к хосту в виде пустой папки, которая может скрыть опечатку. При использовании --mount и типа привязки Docker вместо этого сообщает об ошибке. Кроме того, в -v левая сторона определяет тип: имя означает том, а путь означает монтирование привязки. Итак, -v data:/x и -v ./data:/x делают очень разные вещи.

Тома в Docker Compose

Большинство реальных проектов объявляют хранилище в файле Compose. Здесь используются оба типа, каждый для своей задачи:

services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./src:/app/src      # bind mount: live code
    depends_on:
      - db

  db:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: devonly
    volumes:
      - pgdata:/var/lib/postgresql/data   # named volume: data

volumes:
  pgdata:

Именованные тома должны быть объявлены в разделе верхнего уровня volumes. Compose добавляет к фактическому имени префикс имени проекта. Подробное описание см. в нашем руководстве по Docker Compose.

Совет: docker compose down сохраняет именованные тома, но docker compose down -v удаляет их вместе с вашими данными. Будьте особенно осторожны со сценариями и историей оболочки, которые включают -v.

Полезные команды громкости

Команда Что он делает
том докера ls Перечисляет тома
имя создания тома Docker Создает том
имя проверки тома Docker Показывает детали, включая его местоположение.
имя тома Docker RM Удаляет том и его данные
обрезка объема Docker Удаляет неиспользуемые тома
докер-система df -v Показывает использование диска, включая тома

Прежде чем подтвердить это, проверьте, что prune будет удалено, поскольку это невозможно отменить. Тома, которые в настоящее время не используются ни одним контейнером, могут по-прежнему содержать важные данные.

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

Резервную копию тома можно создать, запустив недолговечный контейнер, который монтирует и том, и папку хоста:

# Back up
docker run --rm \
  -v pgdata:/data:ro \
  -v "$(pwd)":/backup \
  alpine tar czf /backup/pgdata.tar.gz -C /data .

# Restore into a new volume
docker volume create pgdata_restored
docker run --rm \
  -v pgdata_restored:/data \
  -v "$(pwd)":/backup \
  alpine tar xzf /backup/pgdata.tar.gz -C /data

Для работающей базы данных копирование таких файлов может привести к несогласованному состоянию. Сначала остановите контейнер или лучше воспользуйтесь собственным инструментом базы данных, например pg_dump для PostgreSQL. А резервная копия, которую вы никогда не восстанавливали, на самом деле является всего лишь надеждой, поэтому проверьте восстановление.

Права доступа к файлам

«Разрешение отклонено» — наиболее распространенная проблема при монтировании. В Linux файлы сохраняют свои числовые идентификаторы пользователей и групп, поэтому, если контейнер запускается от имени пользователя 1000, а папка хоста принадлежит другому пользователю, запись не удастся. Некоторые способы исправить это:

  • Запустите контейнер с соответствующим пользователем: docker run --user "$(id -u):$(id -g)" ...
  • Настройте правильное право собственности на образ, как описано в наших рекомендациях по Dockerfile.
  • Предпочитайте именованные тома для хранения данных, поскольку новый том становится владельцем папки образа при первом использовании.
  • В системах, использующих SELinux, для привязки может потребоваться метка :z или :Z.

Избегайте искушения chmod 777, как объясняется в нашем руководстве по командам Linux.

Что вам следует использовать?

Ситуация Использование
Данные базы данных Именованный том
Исходный код для живого редактирования Привязать крепление
Конфигурационный файл из вашего репозитория Привязка только для чтения
Обмен данными между контейнерами Именованный том
Временный кеш или рабочие файлы tmpfs
Одноразовая тестовая база данных tmpfs или нет монтирования
Код приложения в производстве Встройте это в изображение

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

Распространенные ошибки

  • Монтаж по неправильному пути. Данные по-прежнему находятся на уровне контейнера и впоследствии исчезают.
  • Выполняется down -v случайно. При этом именованные тома будут удалены.
  • Использование относительных путей с -v. Формы типа -v data:/x создают том, а не сопоставление папок.
  • Размещение секретов в записываемых привязках. Смонтируйте их только для чтения или используйте функцию секретов.
  • Указание двух контейнеров базы данных на один том. Это может привести к повреждению данных.
  • Без резервных копий. Том не является резервной копией. Он живет на том же диске.

Итоги

Эмпирическое правило короткое: именованные тома для данных, привязки для кода, который вы редактируете, и tmpfs для вещей, которые не должны длиться долго. Попробуйте это на одноразовой базе данных. Создайте именованный том, добавьте строку, удалите контейнер, запустите новый и убедитесь, что ваша строка сохранилась. Затем попрактикуйтесь в резервном копировании и восстановлении, прежде чем оно вам понадобится.

Часто задаваемые вопросы

В чем разница между томом Docker и привязкой?

Том управляется Docker и хранится в отдельной области. Привязка-монтирование отображает определенный путь к хосту, которым вы управляете, непосредственно в контейнер.

Остановка контейнера удаляет его данные?

Нет. Данные на записываемом слое сохраняются после остановки и перезапуска. Он теряется при удалении контейнера, если только он не сохранен в томе или привязке.

Сохраняются ли тома Docker после завершения работы Docker?

Да, именованные тома остаются после завершения компоновки Docker. Добавление флага -v удаляет их вместе со всеми данными, которые они содержат.

Где хранятся тома Docker?

В Linux обычно в /var/lib/docker/volumes. В Docker Desktop они живут внутри виртуальной машины. Используйте проверку громкости Docker, чтобы увидеть местоположение.

Могут ли несколько контейнеров использовать один том?

Да, несколько контейнеров могут монтировать один том. Приложение должно безопасно обрабатывать одновременный доступ, и базы данных обычно не должны совместно использовать файлы данных таким образом.

Продолжайте учиться

Работайте с Stack Quora

Нужна помощь с тестированием, WordPress или SEO?

Мы помогаем командам выпускать лучшее программное обеспечение и развивать свои сайты. Расскажите нам, над чем вы работаете, и мы предложим четкий следующий шаг.

Продолжайте читать

Больше руководств по тестирование, искусственный интеллект и современные разработки

Понравилась эта статья? Выберите тему и сразу приступайте к нашим новейшим руководствам.

Искусственный интеллект

Объяснение галлюцинаций искусственного интеллекта: почему языковые модели все выдумывают и как их уменьшить

Галлюцинации ИИ объяснили: что это такое, почему языковые модели их создают, распространенные типы, как уменьшить их с помощью заземления и подсказо…

Читать статью →
DevOps

Объяснение переменных среды: файлы .env, секреты и правильно выполненная конфигурация

Переменные среды объясняются на примерах Python, которые мы запускали: их чтение и установка, почему каждое значение является строкой, файлы .env, н…

Читать статью →
Разработка ПО

Объяснение ограничения скорости API: алгоритмы, заголовки и обработка ошибок 429

Ограничение скорости API объясняется с помощью проведенного нами моделирования: сегмент токенов, фиксированное окно, скользящее окно, 429 ответов, з…

Читать статью →
Автоматизация тестирования

Издевательство в Python: unittest.mock, патч и ошибки, из-за которых тесты лгут

Издевательство на Python с помощью unittest.mock, протестировано: Mock и return_value, Side_effect, исправление использования имени, спецификация и …

Читать статью →
Тестирование ПО

Объяснение покрытия кода: покрытие линий или ветвей и что на самом деле означает 100%

Покрытие кода объяснено с помощью реального запуска покрытия.py: покрытие строк, ветвей и условий, чтение отчета, почему 100%-ное покрытие все еще м…

Читать статью →
Базы данных и SQL

DELETE, TRUNCATE и DROP в SQL: различия, откат и когда использовать каждый из них

Объяснение DELETE, TRUNCATE и DROP на примере протестированного SQL: что каждый из них удаляет, откат, триггеры, сброс идентификаторов, скорость и ч…

Читать статью →
Базы данных и SQL

Объяснение представлений SQL: создавайте, используйте и избегайте ловушек, с примерами

Представления SQL, объясненные с помощью запросов, которые мы выполняли: создание представления, результаты в реальном времени, скрытие столбцов, пр…

Читать статью →
Разработка ПО

Интерфейс TypeScript и тип: реальные различия, протестированные с помощью компилятора

Интерфейс TypeScript против типа, проверенный реальным компилятором: что могут делать оба, что может делать только один, слияние объявлений, расшире…

Читать статью →
Разработка ПО

Объяснение Python *args и **kwargs: гибкие функции с понятными примерами

Python *args и **kwargs, объясненные с помощью кода, который мы запускали: упаковка и распаковка, порядок параметров, аргументы только по ключевым с…

Читать статью →
Разработка ПО

Лямбда-функции Python: синтаксис, реальное использование и когда их не следует использовать

Лямбда-функции Python, объясненные с помощью кода, который мы запускали: синтаксис, сортировка с помощью ключа, карты и фильтра, замыкания, ловушка …

Читать статью →
Искусственный интеллект

Что такое ИИ-агенты? Как они работают: можно запустить простой цикл агента

Что такое агенты ИИ? Простое руководство по циклу агента, инструментам, памяти и ограничениям, с небольшим циклом Python, который мы запустили, реал…

Читать статью →
DevOps

Мониторинг и наблюдаемость: реальная разница с журналами, метриками и трассировками

Объяснение мониторинга и наблюдаемости: известные и неизвестные сбои, журналы, метрики и трассировки, пошаговое руководство по инцидентам при оформл…

Читать статью →
DevOps

Docker Volumes против Bind Mounts: правильное сохранение данных контейнера

Объяснение томов Docker и монтирования привязки: почему исчезают данные контейнера, именованные тома, монтирование привязки, tmpfs, примеры создания…

Читать статью →
Автоматизация тестирования

TDD против BDD: ключевые различия, одна функция, созданная для обоих способов, и когда использовать каждый

TDD и BDD объясняются с помощью одной функции скидки, созданной в обоих направлениях: красно-зеленый рефакторинг с кодом, который мы запускали, сцен…

Читать статью →
Разработка ПО

Git merge vs rebase: отличия, примеры и когда что использовать

Git merge vs rebase с реальным выводом log, сравнительной таблицей, золотым правилом rebase и безопасным рабочим процессом для команды.

Читать статью →
Разработка ПО

Генераторы списков в Python: синтаксис, примеры и когда их избегать

Генераторы списков в Python: синтаксис, фильтры, if-else, вложенные циклы, измеренное время и случаи, когда обычный цикл for лучше.

Читать статью →
Базы данных и SQL

SQL JOIN: объяснение с примерами (Inner, Left, Right, Full)

Разберите SQL JOIN шаг за шагом на примерах таблиц и запросов: INNER, LEFT, RIGHT, FULL, CROSS и SELF, а также частые ошибки и советы по производите…

Читать статью →