0

Volumes в Docker

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

  1. Мы не копируем данные, они хранятся в одно месте для всех контейнеров
  2. Раньше копирование отнимало время, а сейчас это делать не нужно, контейнеры запускаются быстрее
  3. У нас появляется больше возможностей для управления данными

Типы томов Docker

Есть два основных способа обмена данными с контейнером, которые часто называют томами:

  • Перенаправление папки или файла с хоста в контейнер, называется bind mount
  • Создание специального объекта, который имеет больше возможностей управления данными volume

Основное различие этих двух типов в том, что для volume есть отдельные команды по его созданию, просмотру и удалению в самом Docker. Он так же представляет собой папку в файловой системе хоста, которая по умолчанию определена настройками Docker. Еще одно отличие, это поведение по умолчанию bind mount и volume. Для примера, внутри контейнера, по пути /usr/share/nginx/html/ лежит файл index.html. В случае проброса томов в эту папку поведение будет разным:

  • В случае bind mount файл index.html, внутри контейнера, будет удален. Это произойдет даже если папка хоста пустая
  • В случае volume при первом использовании файл index.html будет скопирован. При последующих удален

Создание Volumes через docker run

Для монтирования данных используются следующие параметры:

  • -v или --volume
  • --mount

Их различие в том, что bind mount более явно заставляет указывать источник и цель монтирования папки. Вы можете использовать эти параметры совместно, отдельно, повторяя несколько раз, ограничений нет.

Папки и файлы

Для примера, у меня есть следующая папка на хосте:

/home/alex/docker_data

В случае параметра -v указывается два пути откуда:куда. В случае --mount это именованные параметры разделенные запятыми, пример работы обоих:

-v /home/alex/docker_data:/usr/share/nginx/html

--mount type=bind,source=/home/alex/docker_data,destination=/usr/share/nginx/html

В mount мы используем следующие параметры:

  • type со значением bind говорит, что мы монтируем папку или файл
  • source источник, папка или файл, который мы хотим подключить к контейнеру
  • destination папка или файл внутри контейнера

В обоих случаях мы можем монтировать данный доступные только для чтения read-only добавив ro в конце:

-v /home/alex/docker_data:/usr/share/nginx/html:ro

--mount type=bind,source=/home/alex/docker_data,destination=/usr/share/nginx/html,ro

Так выглядит запуск контейнера с проброшенной папкой:

docker run -d --name nginx_vol1 -v /home/alex/docker_data:/usr/share/nginx/html:ro nginx

docker run -d --name nginx_vol2 --mount type=bind,source=/home/alex/docker_data,destination=/usr/share/nginx/html,ro nginx

Можно задать следующие опции:

  1. rprivate
  2. private
  3. rshared
  4. shared
  5. rslave
  6. slave
  7. ro режим только для чтения
  8. z папка на хосте может быть использована несколькими контейнерами
  9. Z папка используется только одним контейнером

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

Подключение volume

При монтировании тома нужно учитывать следующие моменты:

  • Название тома указывается без слешей
  • Если тома с этим названием нет, он будет создан
  • В случае с mount, в параметре type, указывается volume

При использовании docker run использование томов будет выглядеть так:

docker run -d --name nginx_vol1 -v docker_volume:/usr/share/nginx/html nginx

docker run -d --name nginx_vol2 --mount type=volume,source=docker_volume,destination=/usr/share/nginx/html nginx

Так же как и с папками мы можем добавить :ro или ,ro в конец значения, что бы дать права только на чтение директорий.

В предыдущем примере один том был подключен к двум контейнерам. Их совместную работу можно проверить создав файл в одном контейнере, а вывести через другой:

# создаем файл в одном контейнере
docker exec nginx_vol1 touch /usr/share/nginx/html/file1
# проверяем файл через другой контейнер
docker exec nginx_vol2 ls /usr/share/nginx/html

Создание Volumes через Dockerfile

При создании образа через Dockerfile у вас есть возможность создать том, но не использовать существующий. Смонтировать папку, через Dockerfile, нельзя.

Создание тома будет иметь ряд ограничений:

  1. Вы не сможете указать имя тома или выбрать существующий. Имя будет сгенерировано автоматически
  2. В любом случае том будет создан во время запуска контейнера т.е. так же как и в случае использования -v
  3. Каждое создание контейнера будет создавать новый том

Для создания тома есть инструкция VOLUME, пример синтаксиса:

FROM nginx
# указываем точку монтирования внутри контейнера
VOLUME /somedata1

Примерный результат где запускаются 2 контейнера с одного образа:

Volumes в Docker 1

Аналогичный результат можно получить используя одну из следующих команд:

docker run -v /somedata1 nginx

docker run -v  $(docker volume create):/somedata1 nginx
Volumes в Docker 2

Если вы используете инструкцию VOLUME и параметр -v указывающий на одну и ту же директорию, то -v возьмет верх.

Создание Volumes через docker-compose

Docker-compose позволяет запускать несколько контейнеров используя один файл инструкций. Синтаксис монтирования томов может быть ограниченным и расширенным так же как -v и --mount.

Для монтирования тома, кроме инструкции в самом контейнере, нужно указать дополнительную инструкцию volumes в верхнем уровне. Для папки этого делать не нужно:

version: "3.8"
services:
  web:
    image: nginx:alpine
    volumes:
      # том
      - somevol:/app
      # папка
      - /home/alex:/app2
# для тома
volumes:
  somevol:

Том somevol может использоваться совместно в нескольких контейнерах.

Если нам нужно дать права на том или папку, то мы просто добавляем ro или rw в конец пути:

...
    volumes:
      # том
      - somevol:/app:ro
      # папка
      - /home/alex:/app2:rw
...

Для монтирования так же есть расширенный синтаксис, похожий на команду mount в docker. Следующий пример аналогичен предыдущем по эффекту:

version: "3.8"
services:
  web:
    image: nginx:alpine
    volumes:
      # том
      - type: volume
        source: somevol
        target: /app1
      # папка
      - type: bind
        source: /home/alex
        target: /app2
volumes:
  somevol:

Есть еще инструкции, которые вы можете использовать. Ниже только их часть, но они используются редко:

volumes:
      - type: volume
        source: somevol
        target: /app1
        # папка только для чтения
        read_only: true
        # не будет копировать файлы в том, которые уже находятся в контейнере
        volume:
           nocopy: true
      # папка
      - type: bind
        source: /home/alex
        target: /app2
        # папка только для чтения
        read_only: true
        # создаст папку на хосте если ее нет
        create_host_path: true

Мы можем использовать один и тот же том в нескольких контейнерах (сервисах). Кроме этого есть инструкция volumes_from, которая использует тома с указанного контейнера, ниже оба примера:

version: "3.8"
services:
  container1:
    image: nginx:alpine
    volumes:
      - somevol:/app1
      - /home/alex:/app2
  container2:
    image: nginx:alpine
    volumes:
      # тот же том, но в другом контейнере
      - somevol:/app2
  container3:
    image: nginx:alpine
    # берем тома из сервиса container1
    # с доступностью только на чтение
    volumes_from:
      - container1:ro
volumes:
  somevol:

Использование внешних томов

Если вам нужно использовать том, который был создан не в текущем файле docker-compose.yml, то вы можете его указать через параметр external, автоматический такой том не создается:

...
volumes:
  somevol:
    external: true

Создание тома в другой директории

Через docker-compose.yml мы можем указывать драйвера и опции. Например, создадим тома в другой директории по аналогии с тем, что делали выше:

...
volumes:
  my_test_volume:
    driver: local
    driver_opts:
       o: bind
       type: none
       device: /home/alex/compose_vol1

Монтирование через Tmpfs

Еще одним способом монтирования томов является tmpfs. Данные этого тома хранятся в оперативной памяти. При остановке контейнера, в отличие от других томов, данные будут удалены. Эти данные просто не выгружаются из оперативной памяти. Такой тип тома вы можете создать только на одном контейнере и только в Linux.

Такие типы хранилищ редко используются. Их можно использовать для хранения чувствительных данных (для безопасности) или что бы ускорить работу какого-то приложения, но оба варианта, обычно, реализовываются на стороне приложения. Есть два способа создания tmpfs.

Первый способ:

docker run \
  --tmpfs /app \
  nginx:latest
# или
docker run -d \
  --mount type=tmpfs,destination=/app,tmpfs-size=400,tmpfs-mode=1777 \
  nginx:latest

При использовании параметра --tmpfs вы можете указать только директорию, которую планируете использовать.

При использовании mount у вас появляются не обязательные параметры:

  • tmpfs-size размер в байтах, по умолчанию не ограничен
  • tmpfs-mode права на файлы, по умолчанию 1777. Можно не указывать специальные разрешения (т.е. 700, например).

Второй способ через docker-compose.yml:

volumes:
  foo:
    driver: local
    driver_opts:
      type: "tmpfs"
      o: "o=size=100m,uid=1000"
      device: "tmpfs"

Просмотр привязанных томов

Вы можете объявлять тома внутри смонтированных папок и наоборот. Это может создавать путаницу, но это требуется в определенных ситуациях. Например некоторые фреймворки используют следующую структуру хранение модулей и приложений:

docker inspect название_контейнера --format "'{{json .Mounts}}'"
sudo docker inspect название_контейнера | grep Mountpoint | awk '{ print $2 }'

Привязка томов из другого контейнера

С помощью параметра --volumes-from мы можем скопировать тома у запущенного или остановившегося тома, в значении мы указываем контейнер:

# контейнер 1
docker run -v $(pwd)/app:/usr/src/app \
           -v node_modules:/usr/src/app/node_modules \
           --name node1 \
           node
# контейнер 2
docker run --volumes-from node1 --name node2 node

Создание и удаление Volume

volume это отдельны объект у docker есть команды, с помощью которых можно им управлять:

Выведет список томов:

docker volume ls

Покажет подробную информацию о томе, даже его расположение на хосте:

docker volume inspect

Создание нового тома:

docker volume create

Удалит все тома, которые не используются контейнерами:

docker volume prune

Удалит один том:

docker volume rm
Облачная платформа

Свежие комментарии

Подписка

Лучшие статьи

Рубрики

Популярное

Previous Story

Настройка потоковой репликации PostgreSQL

Next Story

Запускаем PostgreSQL в Docker

Latest from Blog

Проброс портов в роутере MikroTik 2

Проброс портов в роутере MikroTik (port forwarding) позволяет организовать удаленный доступ из интернета к какому-нибудь устройству внутри вашей локальной сети (к IP-камере, Web, FTP или игровому серверу). В данной статье мы рассмотрим пример, как

How to set up WireGuard Client on Debian?

WireGuard is an extremely simple yet fast and modern VPN. Setting up the WireGuard VPN client on Debian is straightforward. In this tutorial, we will set up WireGuard VPN client on Debian
Go toTop