Использование драйвера хранилища OverlayFS

OverlayFS - это современная объединённая файловая система, которая похожа на AUFS, но быстрее и с более простой реализацией. Docker предоставляет два драйвера хранения для OverlayFS: оригинальный overlay и более новый и стабильный overlay2.

В этой теме драйвер ядра Linux обозначается как OverlayFS, а драйвер хранилища Docker - как overlay или overlay2.

Примечание

Если вы используете OverlayFS, используйте драйвер overlay2, а не драйвер overlay, поскольку он более эффективен с точки зрения использования инодов. Для использования нового драйвера необходима версия ядра Linux 4.0 или выше, либо RHEL или CentOS версии 3.10.0-514 и выше.

Более подробную информацию о различиях между overlay и overlay2 можно найти на сайте Драйверы хранения данных Docker.

Для драйвера fuse-overlayfs проверьте Документация по бескорневому режиму.

Пререквизиты

OverlayFS является рекомендуемым драйвером хранилища и поддерживается, если вы выполняете следующие предварительные условия:

  • Версия ядра Linux 4.0 или выше, или RHEL или CentOS, использующие версию ядра 3.10.0-514 или выше. Если вы используете более старое ядро, вам придется использовать драйвер overlay, что не рекомендуется.

  • Драйверы overlay и overlay2 поддерживаются на резервных файловых системах xfs, но только при включенном d_type=true.

    Используйте флаг xfs_info, чтобы проверить, что параметр ftype установлен в значение 1. Чтобы правильно отформатировать файловую систему xfs, используйте флаг -n ftype=1.

    Предупреждение

    Запуск на XFS без поддержки d_type теперь заставляет Docker пропустить попытку использования драйвера overlay или overlay2. Существующие установки будут продолжать работать, но выдавать ошибку. Это сделано для того, чтобы пользователи могли перенести свои данные. В будущей версии это будет фатальная ошибка, которая не позволит запустить Docker.

  • Изменение драйвера хранилища делает существующие контейнеры и образы недоступными в локальной системе. Используйте docker save, чтобы сохранить все созданные образы или отправить их в Docker Hub или частный реестр до изменения драйвера хранения, чтобы впоследствии не пришлось создавать их заново.

Настройка Docker с драйвером хранилища overlay или overlay2

Настоятельно рекомендуется использовать драйвер overlay2, если это возможно, а не драйвер overlay. Драйвер overlay не поддерживается для Docker EE.

Чтобы настроить Docker на использование драйвера хранения overlay, ваш хост Docker должен работать под управлением версии 3.18 ядра Linux (желательно более новой) с загруженным модулем ядра Overlay. Для драйвера overlay2 версия вашего ядра должна быть 4.0 или новее.

Перед выполнением этой процедуры вы должны сначала выполнить все требования предварительные условия.

Ниже описаны шаги по настройке драйвера хранилища overlay2. Если вам необходимо использовать устаревший драйвер overlay, укажите его вместо этого.

  1. Останов Docker.

    $ sudo systemctl stop docker
    
  2. Скопируйте содержимое папки /var/lib/docker во временное место.

    $ cp -au /var/lib/docker /var/lib/docker.bk
    
  3. Если вы хотите использовать отдельную резервную файловую систему, отличную от той, что используется в /var/lib/, отформатируйте файловую систему и смонтируйте ее в /var/lib/docker. Обязательно добавьте это монтирование в /etc/fstab, чтобы сделать его постоянным.

  4. Отредактируйте /etc/docker/daemon.json. Если он ещё не существует, создайте его. Предполагая, что файл был пустым, добавьте следующее содержимое.

    {
      "storage-driver": "overlay2"
    }
    

    Docker не запускается, если файл daemon.json содержит плохо сформированный JSON.

  5. Запуск Docker.

    $ sudo systemctl start docker
    
  6. Убедитесь, что демон использует драйвер хранилища overlay2. Используйте команду docker info и найдите Storage Driver и Backing filesystem.

    $ docker info
    
    Containers: 0
    Images: 0
    Storage Driver: overlay2
     Backing Filesystem: xfs
     Supports d_type: true
     Native Overlay Diff: true
    <...>
    

Теперь Docker использует драйвер хранения overlay2 и автоматически создал оверлейное монтирование с необходимыми конструкциями lowerdir, upperdir, merged и workdir.

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

Как работает драйвер overlay2?

If you are still using the overlay driver rather than overlay2, see How the overlay driver works instead.

OverlayFS объединяет два каталога на одном хосте Linux и представляет их как один каталог. Эти каталоги называются слоями, а процесс объединения называется объединённым монтированием. OverlayFS обозначает нижний каталог как lowerdir, а верхний - как upperdir. Унифицированное представление открывается через собственный каталог под названием merged.

Драйвер overlay2 изначально поддерживает до 128 нижних слоёв OverlayFS. Эта возможность обеспечивает более высокую производительность для связанных со слоями команд Docker, таких как docker build и docker commit, и потребляет меньше inodes в резервной файловой системе.

Слои образа и контейнера на диске

После загрузки пятислойного образа с помощью docker pull ubuntu вы можете увидеть шесть каталогов под /var/lib/docker/overlay2.

Предупреждение

Не работайте напрямую с файлами или каталогами внутри /var/lib/docker/. Этими файлами и каталогами управляет Docker.

$ ls -l /var/lib/docker/overlay2

total 24
drwx------ 5 root root 4096 Jun 20 07:36 223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7
drwx------ 3 root root 4096 Jun 20 07:36 3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b
drwx------ 5 root root 4096 Jun 20 07:36 4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1
drwx------ 5 root root 4096 Jun 20 07:36 e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5
drwx------ 5 root root 4096 Jun 20 07:36 eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed
drwx------ 2 root root 4096 Jun 20 07:36 l

Новый каталог l (строчная L) содержит сокращенные идентификаторы слоёв в виде символических ссылок. Эти идентификаторы используются для того, чтобы избежать ограничения размера страницы для аргументов команды mount.

$ ls -l /var/lib/docker/overlay2/l

total 20
lrwxrwxrwx 1 root root 72 Jun 20 07:36 6Y5IM2XC7TSNIJZZFLJCS6I4I4 -> ../3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 B3WWEFKBG3PLLV737KZFIASSW7 -> ../4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 JEYMODZYFCZFYSDABYXD5MF6YO -> ../eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 NFYKDW6APBCCUCTOUSYDH4DXAT -> ../223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 UL2MW33MSE3Q5VYIKBRN4ZAGQP -> ../e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5/diff

Самый нижний слой содержит файл под названием link, который содержит имя сокращенного идентификатора, и каталог под названием diff, который содержит содержимое слоя.

$ ls /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/

diff  link

$ cat /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/link

6Y5IM2XC7TSNIJZZFLJCS6I4I4

$ ls  /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff

bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Второй по уровню слой и каждый более высокий слой содержат файл lower, обозначающий его родителя, и каталог diff, содержащий его содержимое. Он также содержит каталог merged, который содержит объединенное содержимое его родительского слоя и его самого, и каталог work, который используется внутри OverlayFS.

$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7

diff  link  lower  merged  work

$ cat /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/lower

l/6Y5IM2XC7TSNIJZZFLJCS6I4I4

$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff/

etc  sbin  usr  var

Чтобы просмотреть монтирования, которые существуют при использовании драйвера хранения overlay с Docker, используйте команду mount. Приведенный ниже вывод усечён для удобства чтения.

$ mount | grep overlay

overlay on /var/lib/docker/overlay2/9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/merged
type overlay (rw,relatime,
lowerdir=l/DJA75GUWHWG7EWICFYX54FIOVT:l/B3WWEFKBG3PLLV737KZFIASSW7:l/JEYMODZYFCZFYSDABYXD5MF6YO:l/UL2MW33MSE3Q5VYIKBRN4ZAGQP:l/NFYKDW6APBCCUCTOUSYDH4DXAT:l/6Y5IM2XC7TSNIJZZFLJCS6I4I4,
upperdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/diff,
workdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/work)

rw во второй строке показывает, что монтирование overlay - это чтение-запись.

Как работает overlay-драйвер?

Это содержание относится только к драйверу overlay. Docker рекомендует использовать драйвер overlay2, который работает по-другому. Смотрите как работает драйвер overlay2 для overlay2.

OverlayFS объединяет два каталога на одном хосте Linux и представляет их как один каталог. Эти каталоги называются слоями, а процесс объединения называется объединённым монтированием. OverlayFS обозначает нижний каталог как lowerdir, а верхний - как upperdir. Унифицированное представление открывается через собственный каталог под названием merged.

На приведенной ниже диаграмме показано, как слоится образ Docker и контейнер Docker. Уровень образа - это lowerdir, а уровень контейнера - upperdir. Единый вид отображается через каталог под названием merged, который фактически является точкой монтирования контейнера. На диаграмме показано, как конструкции Docker сопоставляются с конструкциями OverlayFS.

overlayfs lowerdir, upperdir, merged

Если слой образа и слой контейнера содержат одинаковые файлы, слой контейнера «побеждает» и скрывает существование тех же файлов в слое образа.

Драйвер overlay работает только с двумя слоями. Это означает, что многослойные образа не могут быть реализованы как несколько слоёв OverlayFS. Вместо этого каждый слой образа реализуется как собственный каталог под /var/lib/docker/overlay. Жёсткие ссылки затем используются как экономичный способ обращения к данным, разделяемым с нижними слоями. Использование жестких ссылок приводит к чрезмерному использованию inodes, что является известным ограничением устаревшего драйвера хранения overlay, и может потребовать дополнительной настройки резервной файловой системы. Подробности см. в статье overlay FS и производительность Docker.

Чтобы создать контейнер, драйвер overlay объединяет каталог, представляющий верхний слой образа, и новый каталог для контейнера. Верхний слой образа находится под номером lowerdir в оверлее и доступен только для чтения. Новый каталог для контейнера - upperdir и доступен для записи.

Слои образа и контейнера на диске

Следующая команда docker pull показывает, как хост Docker загружает образ Docker, состоящий из пяти слоев.

$ docker pull ubuntu

Using default tag: latest
latest: Pulling from library/ubuntu

5ba4f30e5bea: Pull complete
9d7d19c9dc56: Pull complete
ac6ad7efd0f9: Pull complete
e7491a747824: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:46fb5d001b88ad904c5c732b086b596b92cfb4a4840a3abd0e35dbb6870585e4
Status: Downloaded newer image for ubuntu:latest

Слои образа

Каждый слой образа имеет свой собственный каталог в пределах /var/lib/docker/overlay/, который содержит его содержимое, как показано ниже. Идентификаторы слоев образа не соответствуют идентификаторам каталогов.

Предупреждение

Не работайте напрямую с файлами или каталогами внутри /var/lib/docker/. Этими файлами и каталогами управляет Docker.

$ ls -l /var/lib/docker/overlay/

total 20
drwx------ 3 root root 4096 Jun 20 16:11 38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8
drwx------ 3 root root 4096 Jun 20 16:11 55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
drwx------ 3 root root 4096 Jun 20 16:11 824c8a961a4f5e8fe4f4243dab57c5be798e7fd195f6d88ab06aea92ba931654
drwx------ 3 root root 4096 Jun 20 16:11 ad0fe55125ebf599da124da175174a4b8c1878afe6907bf7c78570341f308461
drwx------ 3 root root 4096 Jun 20 16:11 edab9b5e5bf73f2997524eebeac1de4cf9c8b904fa8ad3ec43b3504196aa3801

Каталоги слоев образа содержат файлы, уникальные для данного слоя, а также жесткие ссылки на данные, общие для нижележащих слоев. Это позволяет эффективно использовать дисковое пространство.

$ ls -i /var/lib/docker/overlay/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls

19793696 /var/lib/docker/overlay/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls

$ ls -i /var/lib/docker/overlay/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls

19793696 /var/lib/docker/overlay/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls

Контейнерный слой

Контейнеры также существуют на диске в файловой системе хоста Docker под номером /var/lib/docker/overlay/. Если вы перечислите подкаталоги запущенного контейнера с помощью команды ls -l, то обнаружите три каталога и один файл:

$ ls -l /var/lib/docker/overlay/<directory-of-running-container>

total 16
-rw-r--r-- 1 root root   64 Jun 20 16:39 lower-id
drwxr-xr-x 1 root root 4096 Jun 20 16:39 merged
drwxr-xr-x 4 root root 4096 Jun 20 16:39 upper
drwx------ 3 root root 4096 Jun 20 16:39 work

Файл lower-id содержит идентификатор верхнего слоя образа, на котором основан контейнер, - OverlayFS lowerdir.

$ cat /var/lib/docker/overlay/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id

55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358

Каталог upper содержит содержимое слоя чтения-записи контейнера, который соответствует OverlayFS upperdir.

Каталог merged - это объединённое монтирование lowerdir и upperdir, которое представляет собой вид файловой системы изнутри запущенного контейнера.

Каталог work является внутренним для OverlayFS.

Чтобы просмотреть монтирования, которые существуют при использовании драйвера хранения overlay с Docker, используйте команду mount. Приведенный ниже вывод усечён для удобства чтения.

$ mount | grep overlay

overlay on /var/lib/docker/overlay/ec444863a55a.../merged
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay/55f1e14c361b.../root,
upperdir=/var/lib/docker/overlay/ec444863a55a.../upper,
workdir=/var/lib/docker/overlay/ec444863a55a.../work)

rw во второй строке показывает, что монтирование overlay - это чтение-запись.

Как чтение и запись контейнеров работает с overlay или overlay2

Чтение файлов

Рассмотрим три сценария, в которых контейнер открывает файл для доступа на чтение с оверлеем.

  • Файл не существует в слое контейнера: Если контейнер открывает файл для доступа на чтение, а файл еще не существует в контейнере (upperdir), он считывается из образа (lowerdir). Это приводит к очень незначительным накладным расходам производительности.

  • Файл существует только в слое контейнера: Если контейнер открывает файл для доступа на чтение и файл существует в контейнере (upperdir), а не в образе (lowerdir), он считывается непосредственно из контейнера.

  • Файл существует как в слое контейнера, так и в слое образа: Если контейнер открывает файл для доступа на чтение и файл существует в слое образа и в слое контейнера, считывается версия файла в слое контейнера. Файлы в слое контейнера (upperdir) заслоняют файлы с тем же именем в слое образа (lowerdir).

Изменение файлов или каталогов

Рассмотрим некоторые сценарии, в которых файлы в контейнере изменяются.

  • Запись в файл в первый раз: При первой записи контейнера в существующий файл этот файл не существует в контейнере (upperdir). Драйвер overlay/overlay2 выполняет операцию copy_up для копирования файла из образа (lowerdir) в контейнер (upperdir). Затем контейнер записывает изменения в новую копию файла в слое контейнера.

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

  • Операция copy_up происходит только при первой записи в данный файл. Последующие записи в тот же файл выполняются над копией файла, уже скопированной в контейнер.

  • OverlayFS работает только с двумя слоями. Это означает, что производительность должна быть выше, чем у AUFS, которая может испытывать заметные задержки при поиске файлов в образах с большим количеством слоев. Это преимущество относится к драйверам overlay и overlay2. overlayfs2 немного менее производителен, чем overlayfs при первичном чтении, поскольку ему приходится просматривать больше слоев, но он кэширует результаты, так что это лишь небольшое наказание.

  • Удаление файлов и каталогов:

  • Когда файл удаляется в контейнере, в нём создается белый файл (upperdir). Версия файла в слое образа (lowerdir) не удаляется (поскольку lowerdir доступен только для чтения). Однако файл с белым пятном не позволяет ему быть доступным для контейнера.

  • Когда каталог удаляется в контейнере, в нем создается прозрачный каталог (upperdir). Он работает так же, как и файл с белым цветом, и эффективно предотвращает доступ к каталогу, хотя он все еще существует в образе (lowerdir).

  • Переименование каталогов: Вызов rename(2) для каталога разрешен только тогда, когда и исходный и конечный путь находятся на верхнем уровне. В противном случае возвращается ошибка EXDEV («cross-device link not permitted»). Ваше приложение должно быть спроектировано так, чтобы обрабатывать EXDEV и возвращаться к стратегии «копирование и отсоединение».

Наложение FS и производительность Docker

Драйверы overlay2 и overlay более производительны, чем aufs и devicemapper. При определенных обстоятельствах overlay2 может работать лучше, чем btrfs. Однако обратите внимание на следующие детали.

  • Кэширование страниц. OverlayFS поддерживает совместное использование кэша страниц. Несколько контейнеров, обращающихся к одному и тому же файлу, совместно используют одну запись кэша страниц для этого файла. Это делает драйверы overlay и overlay2 эффективными в использовании памяти и хорошим вариантом для случаев использования с высокой плотностью, таких как PaaS.

  • copy_up. Как и в AUFS, OverlayFS выполняет операции копирования всякий раз, когда контейнер записывает в файл в первый раз. Это может добавить задержку в операцию записи, особенно для больших файлов. Однако, как только файл был скопирован вверх, все последующие записи в этот файл происходят на верхнем уровне, без необходимости дальнейших операций копирования.

Операция OverlayFS copy_up быстрее, чем та же операция с AUFS, потому что AUFS поддерживает больше слоев, чем OverlayFS, и при поиске по многим слоям AUFS можно получить гораздо большие задержки. overlay2 также поддерживает несколько слоев, но снижает падение производительности за счет кэширования.

  • Ограничение количества инодов. Использование устаревшего драйвера хранения overlay может привести к чрезмерному потреблению инодов. Это особенно актуально при наличии большого количества образов и контейнеров на хосте Docker. Единственным способом увеличить количество инодов, доступных для файловой системы, является ее переформатирование. Чтобы избежать этой проблемы, настоятельно рекомендуется использовать overlay2, если это вообще возможно.

Лучшие практики в области производительности

Следующие общие рекомендации по повышению производительности также применимы к OverlayFS.

  • Используйте быстрое хранение данных: Твердотельные накопители (SSD) обеспечивают более быстрое чтение и запись, чем вращающиеся диски.

  • Используйте тома для рабочих нагрузок с высокой интенсивностью записи: Тома обеспечивают наилучшую и наиболее предсказуемую производительность при работе с большими объёмами записи. Это происходит потому, что они обходят драйвер хранилища и не несут никаких потенциальных накладных расходов, возникающих при тонком выделении ресурсов и копировании при записи. У томов есть и другие преимущества, например, возможность совместного использования данных контейнерами и сохранение данных, даже если ни один из запущенных контейнеров их не использует.

Ограничения совместимости с OverlayFS

Подведём итоги по аспекту OverlayFS, который несовместим с другими файловыми системами:

  • open(2): OverlayFS реализует только подмножество стандартов POSIX. Это может привести к тому, что некоторые операции OverlayFS нарушают стандарты POSIX. Одной из таких операций является операция copy-up. Предположим, что ваше приложение вызывает fd1=open("foo", O_RDONLY), а затем fd2=open("foo", O_RDWR). В этом случае ваше приложение ожидает, что fd1 и fd2 будут ссылаться на один и тот же файл. Однако из-за операции копирования, которая происходит после второго обращения к open(2), дескрипторы ссылаются на разные файлы. fd1 продолжает ссылаться на файл в образе (lowerdir), а fd2 ссылается на файл в контейнере (upperdir). Обходным решением в этом случае является touch файлов, что приводит к выполнению операции копирования. Все последующие операции open(2) независимо от режима доступа «только чтение» или «чтение-запись» ссылаются на файл в контейнере (upperdir).

Известно, что yum может быть затронут, если не установлен пакет yum-plugin-ovl. Если пакет yum-plugin-ovl недоступен в вашем дистрибутиве, например, RHEL/CentOS до версии 6.8 или 7.2, вам может потребоваться запустить touch /var/lib/rpm/* перед запуском yum install. Этот пакет реализует обходное решение touch, упомянутое выше для yum.

  • rename(2): OverlayFS не полностью поддерживает системный вызов rename(2). Ваше приложение должно обнаружить его отказ и вернуться к стратегии «копирование и отсоединение».