Ответ
Docker использует механизм пространств имен Linux (namespaces), в частности пространство имен монтирования (mount namespace или CLONE_NEWNS), для изоляции файловой системы контейнера.
Механизм наследования:
- При запуске нового контейнера Docker (через
runc) вызывает системный вызовclone()илиunshare()с флагомCLONE_NEWNS. - Это создает новое, изолированное пространство имен монтирования для процесса контейнера.
- Изначально это новое пространство наследует копию таблицы монтирований (
mount tree) от родительского процесса (обычноdockerdилиcontainerd). - После создания пространства имен, Docker внутри него монтирует корневую файловую систему контейнера (образ) и другие необходимые файловые системы (
/proc,/sys,/dev).
Ключевое следствие: Изменения в дереве монтирований внутри контейнера (например, mount /dev/sdb1 /mnt) остаются видимыми только в его собственном пространстве имен и не влияют на хост или другие контейнеры.
Практический пример с bind mount:
Когда вы используете -v /host/data:/container/data, Docker создает bind mount, который отображает каталог хоста в пространство имен контейнера.
# На хосте
$ ls /host/data
file.txt
# Запуск контейнера с пробросом директории
$ docker run -it -v /host/data:/data alpine sh
# Внутри контейнера мы видим файл из хоста
/ # ls /data
file.txt
# Монтирование внутри контейнера НЕ видно на хосте
/ # mount -t tmpfs tmpfs /data
Проверка изоляции:
На хосте можно увидеть, что у каждого контейнера свой mount namespace:
# Находим PID основного процесса контейнера
$ docker inspect --format '{{.State.Pid}}' <container_id>
12345
# Смотрим его пространство имен монтирования
$ ls -la /proc/12345/ns/mnt
lrwxrwxrwx 1 root root 0 Apr 10 12:00 /proc/12345/ns/mnt -> 'mnt:[4026531841]'
# У каждого контейнера будет уникальный идентификатор в квадратных скобках.
Таким образом, наследование — это начальная копия, а последующая изоляция обеспечивает безопасность и предсказуемость работы контейнеров.