Learning Platform
Глоссарий Troubleshooting
Урок 10.01 · 22 мин
Начальный
dockervolumesbind-mounttmpfs

Три типа mount: bind, volume, tmpfs

Контейнер по умолчанию stateless: остановил — удалил — данные пропали. Чтобы данные жили дольше контейнера, или чтобы файлы с хоста были доступны внутри контейнера, Docker даёт три механизма монтирования: bind mount, named volume и tmpfs. Все три выглядят похоже — «папка появилась внутри контейнера», — но устроены и применяются по-разному. Разница важна для DE: ты будешь монтировать DAG-файлы в Airflow (bind), хранить data directory Postgres (volume) и держать секреты в памяти (tmpfs).


Зачем вообще нужны mount’ы

У контейнера своя файловая система — overlay из слоёв образа плюс writable layer сверху. Запись в overlay медленнее, чем в обычную FS, и при удалении контейнера всё, что было в writable layer, исчезает. Если контейнер — Postgres, и его data directory лежит в writable layer, то docker rm postgres уничтожает базу. Это плохой план.

Mount’ы решают две задачи:

  1. Persistence — данные переживают рестарт и удаление контейнера.
  2. Sharing — файл с хоста (или другого контейнера) доступен внутри.
Три способа подключить хранилище к контейнеру
bind mountТочка монтирования на хосте указывается явно: /Users/me/project. Docker не управляет этим, любая программа на хосте может писать сюда
dev
DAG-код AirflowDAG-файлы редактируются на хосте в IDE, Airflow внутри контейнера их видит. Live edit без пересборки образа
named volumeУправляется Docker'ом. Живёт в /var/lib/docker/volumes/. Имя задаём мы, путь — Docker. Видим через docker volume ls
prod
Postgres dataКаталог /var/lib/postgresql/data. Volume лежит на хосте, но через abstraction Docker. Backup и restore через docker run-helper
tmpfsIn-memory filesystem. Размер ограничен RAM. На остановке контейнера данные исчезают всегда
secrets
Временные секретыToken, временный JWT, расшифрованный пароль. Не попадает на диск, не светится в docker inspect

Mount, /etc/fstab и mount namespaces

Bind mount: путь с хоста

Bind mount — самый прямолинейный механизм. Берёшь существующую папку на хосте, говоришь Docker «покажи её внутри контейнера в такой-то точке».

docker run --rm -it \
  -v /Users/me/dags:/opt/airflow/dags \
  apache/airflow:2.10.0 bash

Внутри контейнера /opt/airflow/dags — это та же самая папка, что /Users/me/dags на хосте. Изменил файл в VS Code — изменения тут же видны в контейнере. Airflow scheduler перечитает DAG, обновит расписание. Никакого rebuild.

Альтернативный синтаксис, более многословный, но явный — --mount:

docker run --rm -it \
  --mount type=bind,source=/Users/me/dags,target=/opt/airflow/dags \
  apache/airflow:2.10.0 bash

Bind mount удобен для разработки, но в production он становится проблемой: чтобы развернуть Postgres на новой машине, нужно сначала вручную создать /var/lib/postgres-data с правильными правами. Это нарушает «runs anywhere» — главное обещание контейнеров.


Named volume: Docker управляет

Named volume — это «папка», которой управляет сам Docker. Ты задаёшь только имя, путь Docker выбирает сам и прячет под капотом.

docker volume create pgdata
docker run -d --name pg \
  -v pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:17

Если volume не существовал — Docker создаст его сам при первом -v pgdata:.... Команда docker volume create нужна, только если хочется заранее задать driver или labels.

Где физически живут данные? Обычно в /var/lib/docker/volumes/<name>/_data/. На macOS внутри Docker Desktop это спрятано в VM, на OrbStack — тоже виртуализировано. Доступа «прямо в Finder» нет, и это намеренно: Docker хочет, чтобы ты ходил в volume только через контейнер.

Преимущества named volume:

  • Portable. Запустил compose-стенд на новой машине — volume создастся автоматически.
  • Backup/restore — стандартный паттерн. Через одноразовый контейнер, который монтирует volume и tar’ит содержимое.
  • Volume drivers. Local — default, но бывают NFS, GlusterFS, плагины облачных провайдеров.
  • Контейнер контролирует владельца. Postgres-образ при первом запуске сам выставит UID/GID на data directory.

Tmpfs: всё в RAM

Tmpfs — это файловая система в памяти. Linux tmpfs существует независимо от Docker, Docker просто умеет монтировать tmpfs внутрь контейнера.

docker run --rm -it \
  --tmpfs /tmp:size=64m \
  --tmpfs /run/secrets:size=8m,mode=0700 \
  alpine sh

Внутри /tmp и /run/secrets — это память, не диск. Размер ограничен флагом size=. Когда контейнер остановится, данные исчезнут — гарантированно, потому что они никогда и не были на диске.

Tmpfs полезен для:

  • Секретов. JWT-токен, расшифрованный пароль, временный API-key. Не должны попасть на диск даже на секунду.
  • Скрэтч-файлов. Промежуточные tmp-файлы pandas-pipeline, которые всё равно удалятся.
  • Защиты от перезаписи. /tmp в production-контейнерах часто делают tmpfs, чтобы атакующий не мог записать туда payload, переживший рестарт.
WARNING

Tmpfs ест RAM. Если задал size=2g и забил его реальными данными — у хоста стало на 2 ГБ меньше памяти для других процессов. Это легко устроить OOM на дев-машине.


Таблица «когда что»

Mount type vs use case
Bind mountПрямая ссылка на host path. Изменения мгновенные. Идеально для разработки
Dev: код, DAG, конфигЛюбые файлы, которые ты редактируешь на хосте и хочешь сразу видеть в контейнере без rebuild
Named volumeУправляется Docker. Контейнер пишет туда, как в обычную папку. Между запусками не пропадает
Prod: data dir БДPostgres data, Redis snapshots, MinIO bucket storage, Airflow logs/dags-bundle. Всё, что должно пережить рестарт контейнера
tmpfsIn-memory, никогда не попадёт на диск. Очищается на остановке. Не подходит для persistence
Секреты, scratchTokens, decrypted passwords, временные файлы pipeline. Всё, что не должно остаться на диске
Свойствоbind mountnamed volumetmpfs
Где живётhost pathDocker-managedRAM
Persistenceдаданет
Backup стандартныйrsync hostdocker run+tarбессмысленен
Portable между PCнетдада
Скорость на macOSмедленныйбыстрыйочень быстрый
Видит host-программадатеоретически данет
Типичный DE useDAG live editPostgres datascratch /tmp

Реальный пример: Airflow-стенд

В compose-стенде Airflow для DE-разработки одновременно используются все три типа:

services:
  postgres:
    image: postgres:17
    volumes:
      - pgdata:/var/lib/postgresql/data
  airflow-scheduler:
    image: apache/airflow:2.10.0
    volumes:
      - ./dags:/opt/airflow/dags
      - airflow-logs:/opt/airflow/logs
    tmpfs:
      - /tmp:size=128m
volumes:
  pgdata:
  airflow-logs:
  • pgdata — named volume для Postgres, чтобы метаданные Airflow (DagRun, TaskInstance) пережили рестарт.
  • ./dags — bind mount: DAG-файлы я редактирую в IDE, Airflow scheduler их подхватывает.
  • airflow-logs — named volume для логов Airflow, чтобы они не теряли историю.
  • /tmp — tmpfs, чтобы временные файлы task-runner не засоряли overlay.

Каждый mount — на своём месте. Если бы я положил Postgres data в ./pgdata (bind mount), на проде это превратилось бы в кошмар с правами доступа и переносом между машинами. Если бы положил DAG-файлы в named volume — пришлось бы каждый раз заходить в контейнер и редактировать там через vi.


Попробуй сам

# 1. Bind mount: проверь, что изменение на хосте видно в контейнере.
mkdir -p /tmp/bind-demo
echo "hello from host" > /tmp/bind-demo/note.txt

docker run --rm -it \
  -v /tmp/bind-demo:/data \
  alpine cat /data/note.txt

# Из второго терминала отредактируй файл, не выходя из контейнера:
echo "edited on host" >> /tmp/bind-demo/note.txt
# В контейнере: cat /data/note.txt — увидишь обновление.

# 2. Named volume: данные переживут удаление контейнера.
docker volume create demo-vol
docker run --rm -v demo-vol:/data alpine sh -c 'echo "persistent" > /data/file.txt'

# Контейнер вышел и удалился. Создадим новый и прочитаем:
docker run --rm -v demo-vol:/data alpine cat /data/file.txt
# -> persistent

# 3. tmpfs: после рестарта пусто.
docker run --rm -it --tmpfs /scratch:size=16m alpine sh
# В контейнере:
#   echo "in-memory" > /scratch/x
#   ls /scratch  -> x
#   exit
# Новый запуск:
docker run --rm -it --tmpfs /scratch:size=16m alpine ls /scratch
# -> пусто
TIP

На macOS bind mount работает через виртуализацию: Docker Desktop использует VirtioFS/gRPC FUSE, OrbStack — VirtFS поверх Linux VM. Поэтому bind mount на маке заметно медленнее, чем на Linux. Если pipeline жалуется на медленный I/O в bind-папке, это не баг — это архитектура.

В следующем уроке погружаемся в bind mount: синтаксис, права, macOS-specific нюансы.


Проверка знанийKnowledge check
Postgres-контейнер монтирует данные через -v pgdata:/var/lib/postgresql/data . После docker rm Postgres-контейнера и нового docker run с тем же volume — данные должны остаться. Какой тип mount здесь используется и почему именно он подходит?
ОтветAnswer
Используется named volume. Подходит он, потому что: (1) персистентность — данные живут в /var/lib/docker/volumes/pgdata/_data/ и не зависят от lifecycle контейнера; (2) Docker-managed: Postgres-образ при первом запуске может выставить нужные UID/GID на data directory без ручного chown на хосте; (3) portable — на новой машине Docker создаст volume автоматически при первом запуске compose; (4) backup через стандартный паттерн "одноразовый контейнер с двумя volume mount + tar". Bind mount тут хуже потому, что host path придётся вручную готовить на каждой машине и следить за правами. Tmpfs не подходит вообще: данные пропадут на рестарте.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Какой тип mount правильный для production Postgres data directory и почему?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5