Управление файловыми системами контейнеров

DockerDockerBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

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

  • Если контейнер больше не существует, данные теряются,
  • Записной слой контейнера тесно связан с хост-машиной, и
  • Чтобы управлять файловой системой, вам нужен драйвер хранилища, который обеспечивает объединенную файловую систему, используя ядро Linux. Эта дополнительная абстракция снижает производительность по сравнению с «датовыми томами», которые записываются напрямую в файловую систему.

Docker предоставляет два варианта для хранения файлов на хост-машине: «томы» (volumes) и «привязанные точки монтирования» (bind mounts). Если вы запускаете Docker на Linux, вы также можете использовать «монтирование tmpfs», а при использовании Docker на Windows вы также можете использовать «именованный канал» (named pipe).

Виды точек монтирования
  • «Томы» (Volumes) хранятся в файловой системе хоста, которая управляется Docker.
  • «Привязанные точки монтирования» (Bind mounts) хранятся в любом месте системы хоста.
  • «Монтирование tmpfs» (tmpfs mounts) хранится только в памяти хоста.

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


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/VolumeOperationsGroup(["Volume Operations"]) docker(("Docker")) -.-> docker/SystemManagementGroup(["System Management"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/stop("Stop Container") docker/ContainerOperationsGroup -.-> docker/rm("Remove Container") docker/ContainerOperationsGroup -.-> docker/exec("Execute Command in Container") docker/ContainerOperationsGroup -.-> docker/inspect("Inspect Container") docker/VolumeOperationsGroup -.-> docker/volume("Manage Volumes") docker/SystemManagementGroup -.-> docker/prune("Remove Unused Docker Objects") subgraph Lab Skills docker/run -.-> lab-148984{{"Управление файловыми системами контейнеров"}} docker/stop -.-> lab-148984{{"Управление файловыми системами контейнеров"}} docker/rm -.-> lab-148984{{"Управление файловыми системами контейнеров"}} docker/exec -.-> lab-148984{{"Управление файловыми системами контейнеров"}} docker/inspect -.-> lab-148984{{"Управление файловыми системами контейнеров"}} docker/volume -.-> lab-148984{{"Управление файловыми системами контейнеров"}} docker/prune -.-> lab-148984{{"Управление файловыми системами контейнеров"}} end

Томы

«Датовый том» (data volume) или «том» (volume) — это каталог, который обходит объединенную файловую систему Docker.

Есть три типа томов:

  • анонимный том,
  • именованный том, и
  • хостовой том.

Анонимный том

Создадим экземпляр популярной открытой исходной кодовой NoSQL-базы данных CouchDB и используем анонимный том для хранения файлов данных для базы данных.

Для запуска экземпляра CouchDB используйте образ CouchDB с Docker Hub по адресу https://hub.docker.com/_/couchdb. В документации сказано, что по умолчанию для CouchDB записываются файлы базы данных на диск в системе хоста с использованием собственного внутреннего управления томами.

Запустите следующую команду:

docker run -d -p 5984:5984 --name my-couchdb -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1

CouchDB создаст анонимный том и сгенерирует именованный хэш. Проверьте тома на вашей системе хоста:

labex:~/ $ docker volume ls
DRIVER VOLUME NAME
local 1d292aca855adb9de9be7acea88f6d3f8e6a08eef5bfd986a81f073f1906b82f

Установите переменную окружения VOLUME со значением сгенерированного имени:

export VOLUME=<VOLUME NAME>

И проверьте том, который был создан, используя хэш-имя, сгенерированное для тома:

$ docker volume inspect $VOLUME
[
{
  "CreatedAt": "2020-09-24T14:10:07Z",
  "Driver": "local",
  "Labels": null,
  "Mountpoint": "/var/lib/docker/volumes/f543c5319ebd96b7701dc1f2d915f21b095dfb35adbb8dc851630e098d526a50/_data",
  "Name": "f543c5319ebd96b7701dc1f2d915f21b095dfb35adbb8dc851630e098d526a50",
  "Options": null,
  "Scope": "local"
}
]

Вы видите, что Docker создал и управляет томом в файловой системе Docker-хоста по пути /var/lib/docker/volumes/$VOLUME_NAME/_data. Обратите внимание, что это не путь на хост-машине, а часть управляемой Docker файловой системы.

Создайте новую базу данных mydb и вставьте новый документ с сообщением hello world.

curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1 -d '{"msg": "hello world"}'

Остановите контейнер и запустите его снова:

docker stop my-couchdb
docker start my-couchdb

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

curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/_all_docs
curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1

Вывод:

## $ curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/_all_docs
{"total_rows":1,"offset":0,"rows":[
{"id":"1","key":"1","value":{"rev":"1-c09289617e06b96bc747fb1201fea7f1"}}
]}

## $ curl -X GET -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1
{"_id":"1","_rev":"1-c09289617e06b96bc747fb1201fea7f1","msg":"hello world"}

Общий доступ к томам

Вы можете поделиться анонимным томом с другим контейнером, используя параметр --volumes-from.

Создайте контейнер busybox с анонимным томом, смонтированным в каталог /data внутри контейнера, и с использованием командной строки напишите сообщение в файл журнала.

$ docker run -it --name busybox1 -v /data busybox sh
/ ## echo "hello from busybox1" > /data/hi.log
/ ## ls /data
hi.log
/ ## exit

Убедитесь, что контейнер busybox1 остановлен, но не удален.

labex:~/ $ docker ps -a | grep busybox1
f4dbf9ee7513   busybox                               "sh"                     2 minutes ago   Exited (0) About a minute ago                                                                                                                                          busybox1

Затем создайте второй контейнер busybox с именем busybox2, используя параметр --volumes-from, чтобы поделиться томом, созданным контейнером busybox1:

$ docker run --rm -it --name busybox2 --volumes-from busybox1 busybox sh
/ ## ls -al /data
total 12
drwxr-xr-x 2 root root 4096 Jan 23 07:20.
drwxr-xr-x 1 root root 4096 Jan 23 07:24..
-rw-r--r-- 1 root root 20 Jan 23 07:20 hi.log
/ ## cat /data/hi.log
hello from busybox1
/ ## exit

Docker создал анонимный том, который вы смогли поделиться с использованием параметра --volumes-from, и создал новый анонимный том.

labex:~/ $ docker volume ls
DRIVER VOLUME NAME
local 0f971b2477d5fc0d0c2b31fc908ee59d6b577b4887e381964650ce6853890dc9
local 1d292aca855adb9de9be7acea88f6d3f8e6a08eef5bfd986a81f073f1906b82f

Очистите существующие тома и контейнеры.

docker stop my-couchdb
docker rm my-couchdb
docker rm busybox1
docker volume rm $(docker volume ls -q)
docker system prune -a
clear

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

«Именованный том» (named volume) и «анонимный том» похожи тем, что Docker управляет их расположением. Однако именованный том можно ссылаться по имени при монтировании в каталог контейнера. Это полезно, если вы хотите поделиться томом между несколькими контейнерами.

Сначала создайте именованный том:

docker volume create my-couchdb-data-volume

Проверьте, был ли том создан:

$ docker volume ls
DRIVER VOLUME NAME
local my-couchdb-data-volume

Теперь создайте контейнер CouchDB с именем my-couchdb-name-vol, используя именованный том:

docker run -d -p 59840:5984 --name my-couchdb-name-vol -v my-couchdb-data-volume:/opt/couchdb/data -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1

Подождите, пока контейнер CouchDB запустится и будет доступен.

Создайте новую базу данных mydb и вставьте новый документ с сообщением hello world.

curl -X PUT -u admin:passw0rd1 http://127.0.0.1:59840/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:59840/mydb/1 -d '{"msg": "hello world"}'

Теперь легко поделиться томом с другим контейнером. Например, прочитайте содержимое тома с использованием образа busybox и поделитесь томом my-couchdb-data-volume, смонтировав том в каталог внутри контейнера busybox.

labex:~/ $ docker run --rm -it --name busybox -v my-couchdb-data-volume:/myvolume busybox sh
/ #
/ ## ls -al /myvolume
total 40
drwxr-xr-x 4 5984 5984 4096 Jan 23 07:30.
drwxr-xr-x 1 root root 4096 Jan 23 07:31..
drwxr-xr-x 2 5984 5984 4096 Jan 23 07:29.delete
-rw-r--r-- 1 5984 5984 8388 Jan 23 07:30 _dbs.couch
-rw-r--r-- 1 5984 5984 8385 Jan 23 07:29 _nodes.couch
drwxr-xr-x 4 5984 5984 4096 Jan 23 07:30 shards
/ ## exit

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

docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh
/ ## ls -l /var/lib/docker/volumes
total 28
-rw------- 1 root root 32768 Nov 10 15:54 metadata.db
drwxr-xr-x 3 root root 4096 Nov 10 15:54 my-couchdb-data-volume
/ ## exit

Очистите:

docker stop my-couchdb
docker rm my-couchdb
docker volume rm my-couchdb-data-volume
docker system prune -a
docker volume prune
clear

Хостовой том

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

Используйте каталог в текущем рабочем каталоге (указанный командой pwd), называемый data, или выберите свой собственный каталог данных на хост-машине, например, /home/couchdb/data. Мы позволим Docker создать каталог $(pwd)/data, если он еще не существует. Мы монтируем хостовой том внутри контейнера CouchDB в каталог контейнера /opt/couchdb/data, который является стандартным каталогом данных для CouchDB.

Запустите следующую команду:

cd /home/labex/project
docker run -d -p 5984:5984 --name my-couchdb -v $(pwd)/data:/opt/couchdb/data -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=passw0rd1 couchdb:3.1

Проверьте, был ли создан каталог data:

$ ls -al
total 20
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14.
drwxr-x--- 25 labex labex 4096 Aug 29 14:14..
drwxr-xr-x 3 5984 5984 4096 Aug 29 14:14 data

и что CouchDB создал здесь файлы данных:

$ ls -al data
total 32
drwxr-xr-x 3 5984 5984 4096 Aug 29 14:14.
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14..
-rw-r--r-- 1 5984 5984 4257 Aug 29 14:14 _dbs.couch
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:14.delete
-rw-r--r-- 1 5984 5984 8385 Aug 29 14:14 _nodes.couch

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

docker volume ls

и

docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh
sh-5.1## ls -l /var/lib/docker/volumes
total 28
brw------- 1 root root 252, 3 Jan 23 15:15 backingFsBlockDev
-rw------- 1 root root 32768 Jan 23 15:33 metadata.db
drwx-----x 3 root root 4096 Jan 23 15:26 my-couchdb-data-volume
sh-5.1## exit

Создайте новую базу данных mydb и вставьте новый документ с сообщением hello world.

curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb
curl -X PUT -u admin:passw0rd1 http://127.0.0.1:5984/mydb/1 -d '{"msg": "hello world"}'

Обратите внимание, что CouchDB создал папку shards:

$ ls -al data
total 40
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15.
drwxrwxr-x 3 labex labex 4096 Aug 29 14:14..
-rw-r--r-- 1 5984 5984 8388 Aug 29 14:15 _dbs.couch
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:14.delete
-rw-r--r-- 1 5984 5984 8385 Aug 29 14:14 _nodes.couch
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15 shards

Выведите содержимое каталога shards:

$ ls -al data/shards
total 16
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15.
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15..
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 00000000-7fffffff
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15 80000000-ffffffff

и первый шар:

$ ls -al data/shards/00000000-7fffffff/
total 20
drwxr-xr-x 2 5984 5984 4096 Aug 29 14:15.
drwxr-xr-x 4 5984 5984 4096 Aug 29 14:15..
-rw-r--r-- 1 5984 5984 8346 Aug 29 14:15 mydb.1693289721.couch

Шарды — это горизонтальное разделение данных в базе данных. Разделение данных на шарды и распределение копий каждого шарда по разным узлам в кластере обеспечивает большую устойчивость данных к потере узлов. CouchDB автоматически разбивает базы данных на шарды и распределяет подмножества документов между узлами.

Очистите:

docker stop my-couchdb
docker rm my-couchdb
sudo rm -rf $(pwd)/data
docker system prune -a

Привязанные точки монтирования

Синтаксис mount рекомендуется Docker вместо синтаксиса volume. Привязанные точки монтирования имеют ограниченную функциональность по сравнению с томами. Файл или каталог ссылается на его полный путь на хост-машине при монтировании в контейнер. Привязанные точки монтирования зависят от того, что на файловой системе хоста есть определенная структура каталогов, и вы не можете использовать Docker CLI для управления привязанными точками монтирования. Обратите внимание, что привязанные точки монтирования могут изменить файловую систему хоста с помощью процессов, запускающихся в контейнере.

Вместо использования синтаксиса -v с тремя полями, разделенными двоеточием (:), синтаксис mount более подробный и использует несколько пар ключ-значение:

  • type: bind, volume или tmpfs,
  • source: путь к файлу или каталогу на хост-машине,
  • destination: путь в контейнере,
  • readonly,
  • bind-propagation: rprivate, private, rshared, shared, rslave, slave,
  • consistency: consistent, delegated, cached,
  • mount.
cd /home/labex/project
mkdir data
docker run -it --name busybox --mount type=bind,source="$(pwd)"/data,target=/data busybox sh

Введите команду в контейнере:

echo "hello busybox" > /data/hi.txt
exit

Проверьте, был ли создан файл на хост-машине.

cat data/hi.txt

[Необязательно] OverlayFS

OverlayFS — это реализация объединенного файлового systému (union mount filesystem) для Linux. Чтобы понять, что такое том Docker, полезно знать, как работают слои и файловая система в Docker.

Для запуска контейнера Docker берет образ с чтением только и создает поверх него новый слой с записью. Чтобы рассматривать слои как единый целый, Docker использует объединенную файловую систему или OverlayFS (Overlay File System), конкретно драйвер хранилища overlay2.

Чтобы увидеть файлы, управляемые Docker-хостом, вам нужно иметь доступ к файловой системе процесса Docker. С использованием флагов --privileged и --pid=host вы можете получить доступ к пространству имен идентификаторов процессов хоста изнутри контейнера, такого как busybox. Затем вы можете перейти по директории /var/lib/docker/overlay2 Docker, чтобы увидеть загруженные слои, управляемые Docker.

Чтобы просмотреть текущий список слоев в Docker:

$ docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh

/ ## ls -l /var/lib/docker/overlay2
total 16
drwx------ 3 root root 4096 Sep 25 19:44 0e55ecaa4d17c353191e68022d9a17fde64fb5e9217b07b5c56eb4c74dad5b32
drwx------ 5 root root 4096 Sep 25 19:44 187854d05ccd18980642e820b0d2be6a127ba85d8ed96315bb5ae37eb1add36d
drwx------ 4 root root 4096 Sep 25 19:44 187854d05ccd18980642e820b0d2be6a127ba85d8ed96315bb5ae37eb1add36d-init
drwx------ 2 root root 4096 Sep 25 19:44 l

/ ## exit

Скачайте образ ubuntu и проверьте снова:

docker pull ubuntu
docker run -it --privileged --pid=host busybox nsenter -t 1 -m -u -n -i sh

Введите команду, чтобы снова увидеть список слоев:

ls -l /var/lib/docker/overlay2/ & exit

Вы увидите, что при скачивании образа ubuntu неявно были скачаны 4 новых слоя:

  • a611792b4cac502995fa88a888261dfba0b5d852e72f9db9e075050991423779
  • d181f1a41fc35a45c16e8bfcb8eee6f768f3b98f82210a43ea65f284a45fcd65
  • dac2f37f6280a076836d39b87b0ae5ebf5c0d386b6d8b991b103aadbcebaa7c6
  • f3e921b440c37c86d06cd9c9fb70df50edad553c36cc87f84d5eeba734aae709

Драйвер хранилища overlay2 по существу накладывает разные директории на хосте и представляет их в виде одной директории.

  • базовый слой или lowerdir,
  • слой diff или upperdir,
  • слой overlay (представление пользователя), и
  • директория work.

OverlayFS ссылается на нижние директории как lowerdir, которая содержит базовый образ и слои с чтением только (R/O), которые были загружены.

Верхняя директория называется upperdir и представляет собой слой контейнера с записью (R/W).

Объединенное представление или слой overlay называется merged.

Наконец, workdir является обязательной и представляет собой пустую директорию, используемую overlay для внутреннего использования.

Драйвер overlay2 поддерживает до 128 нижних слоев OverlayFS. Директория l содержит сокращенные идентификаторы слоев в виде символических ссылок.

Драйвер хранилища Overlay2

Очистите:

docker system prune -a
clear

Резюме

В этом практическом занятии вы узнали, как управлять данными в контейнерах с использованием томов (volumes) и привязанных точек монтирования (bind mounts). Вы также узнали о драйвере хранилища overlay2 и том, как он использует объединенную файловую систему для управления слоями.