DevOps в серии буткемпов K8s

Примечание: полная ментальная карта DevOps в K8s доступна по адресу: «DevOps в ментальной карте K8s».

В своих предыдущих статьях — DevOps в K8s — эффективно записывайте Dockerfile — я упоминал, что по умолчанию все файлы, созданные внутри контейнера, хранятся на доступном для записи уровне контейнера. Это означает следующие три вещи:

  • Непостоянное хранилище. Данные, которые вы храните в контейнере, не сохраняются.
  • Тесно связанные отношения: поскольку доступный для записи уровень тесно связан с хостом, перемещать данные непросто.
  • Сниженная производительность записи: драйвер хранилища (объединенная файловая система) требуется для записи в доступный для записи слой контейнера, эта дополнительная абстракция снижает производительность по сравнению с использованием томов данных.

Однако Docker предоставляет следующие два варианта контейнеров для постоянного хранения файлов на хосте: Volume и Bind mount. Если контейнер вашего приложения должен хранить файлы в памяти на хосте, вы можете использовать другой вариант, который называется tmpfs mount (в Linux). Разницу можно представить на следующей диаграмме:

Из приведенной выше диаграммы мы видим, что:

  • Том: часть файловой системы хоста (/var/lib/docker/volumes/), которой управляет Docker. Обычно это лучший способ сохранить данные в Docker.
  • Привязать монтирование: просто каталог в файловой системе хоста, который монтируется в контейнер. Данные могут храниться в любом месте хост-системы.
  • tmpfs: хранятся только в памяти хост-системы и никогда не записываются в файловую систему хост-системы.

Объемы контейнеров

Если вы хотите хранить постоянные данные, Volumes предпочтительнее. Он имеет следующие преимущества:

  • Легче выполнить резервное копирование или миграцию
  • Можно управлять с помощью Docker CLI/API
  • Может быть более безопасно разделен между несколькими контейнерами
  • Может храниться на удаленных хостах с шифрованием

Общие операции с томами

Создать том

$ docker volume create test-vpl
test-vpl

$ docker volume ls
DRIVER    VOLUME NAME
local     test-vpl

Проверить том

$ docker volume inspect test-vol
[
    {
        "CreatedAt": "2023-02-09T09:50:13-05:00",
        "Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/test-vol/_data",
        "Name": "test-vol",
        "Options": {},
        "Scope": "local"
    }
]

Удалить том

$ docker volume rm test-vol

Смонтировать том в контейнер

$ docker run -d   --name devtest --mount source=test-vol,target=/app   nginx:latest
d5e994f2c1c6ba3af5c013a4bc290bac8dabb0e583d6392cc1a3b0192760b936
$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
d5e994f2c1c6   nginx:latest   "/docker-entrypoint.…"   9 seconds ago   Up 4 seconds   80/tcp    devtest
$ docker exec -it d5e994f2c1c6 ls /app
$ docker inspect devtest | jq .[0]."Mounts"
[
  {
    "Type": "volume",
    "Name": "test-vol",
    "Source": "/var/lib/docker/volumes/test-vol/_data",
    "Destination": "/app",
    "Driver": "local",
    "Mode": "z",
    "RW": true,
    "Propagation": ""
  }
]

Примеры использования томов

Вот несколько распространенных вариантов использования Volume:

  • Совместное использование данных между несколькими запущенными контейнерами
  • Храните данные вашего контейнера на удаленном хосте или у облачного провайдера.
  • Резервное копирование, восстановление или перенос данных с одного хоста Docker на другой.
  • hHgh-производительный ввод-вывод, поскольку тома хранятся на виртуальной машине Linux, а не на хосте, а это означает, что операции чтения и записи имеют гораздо меньшую задержку и более высокую пропускную способность.

Крепления для контейнеров

С помощью Bind mounts файл или каталог на хосте монтируется (с указанием абсолютного пути) в контейнер. Bind mounts очень производительны, но они полагаются на файловую систему хост-компьютера, имеющую определенную доступную структуру каталогов.

Чтобы использовать Bind mounts, вам просто нужно ввести следующую команду:

$ docker run -d -it --name devtest --mount type=bind,source=/tmp/target,target=/app nginx:latest
64fd8bbb4aa805a9c7bd01a1d4f75167d745be57f1875aa5764947b204de3749

$ docker inspect devtest | jq .[0]."Mounts"
[
  {
    "Type": "bind",
    "Source": "/tmp/target",
    "Destination": "/app",
    "Mode": "",
    "RW": true,
    "Propagation": "rprivate"
  }
]

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

Сценарии использования Bind Mount

Ниже приведены некоторые распространенные варианты использования Bind Mounts:

  • Совместное использование файлов конфигурации между контейнерами на одном хосте (как Docker по умолчанию обеспечивает разрешение DNS для контейнеров)
  • Совместное использование исходного кода или артефактов сборки между средой разработки на хосте и контейнером.
  • Когда структура файлов или каталогов хоста Docker гарантированно соответствует монтированию привязки, которое требуется контейнерам.

tmpfs контейнера

Крепление tmpfs является временным и сохраняется только в памяти хоста. Когда контейнер останавливается, монтирование tmpfs удаляется, и файлы, записанные там, не сохраняются.

Чтобы использовать tmpfs в вашем контейнере:

$ docker run -d -it --name tmptest --mount type=tmpfs,destination=/app  nginx:latest
9ad60f229f31d24e495da60288035f72a7bad2d17b636bb464456cfa20023a45

$ docker inspect tmptest | jq .[0]."Mounts"
[
  {
    "Type": "tmpfs",
    "Source": "",
    "Destination": "/app",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]

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

Заключение