Как напрямую монтировать общий объем/объем NFS в контейнере с помощью docker compose v3

У меня есть файл для компоновки с v3, где есть 3 службы, разделяющие/использующие один том. При использовании режима роя нам необходимо создать дополнительные контейнеры и тома для управления нашими службами по всему кластеру.

Я планирую использовать NFS-сервер, так что один общий ресурс NFS будет установлен непосредственно на всех узлах кластера.

Я нашел ниже два способа сделать это, но для этого требуются дополнительные шаги для хоста докера -

  • Подключите общий ресурс NFS с помощью команды "fstab" или "mount" на хосте, а затем используйте его в качестве хоста для докеров.

  • Используйте плагин Netshare - https://github.com/ContainX/docker-volume-netshare

Есть ли стандартный способ, с помощью которого я могу напрямую использовать/монтировать общий ресурс NFS с помощью docker compose v3, выполнив только несколько/без шагов (я понимаю, что пакет nfs-common требуется в любом случае) на хосте docker?

Ответ 1

Узнав, что это массово недокументировано, здесь правильный способ монтирования тома NFS с использованием стека и докера.

Самое главное, что вам нужно использовать version: "3.2" или выше. У вас будут странные и неочевидные ошибки, если вы этого не сделаете.

Вторая проблема заключается в том, что тома не обновляются автоматически при изменении их определения. Это может привести вас к кроличьей дыре, думая, что ваши изменения неверны, когда они просто не применялись. Убедитесь, что вы используете docker rm VOLUMENAME везде, где это возможно, как если бы этот том существовал, он не будет проверен.

Третья проблема связана с проблемой NFS. Папка NFS не будет создана на сервере, если она не существует. Это как раз то, как работает NFS. Вы должны убедиться, что он существует, прежде чем что-либо сделать.

(Не удаляйте "soft" и "nolock", если вы не уверены, что знаете, что делаете - это останавливает докер от зависания, если ваш сервер NFS уходит)

Вот полный пример:

[[email protected] docker-mirror]# cat nfs-compose.yml
version: "3.2"

services:
  rsyslog:
    image: jumanjiman/rsyslog
    ports:
      - "514:514"
      - "514:514/udp"
    volumes:
      - type: volume
        source: example
        target: /nfs
        volume:
          nocopy: true
volumes:
  example:
    driver_opts:
      type: "nfs"
      o: "addr=10.40.0.199,nolock,soft,rw"
      device: ":/docker/example"



[[email protected] docker-mirror]# docker stack deploy --with-registry-auth -c nfs-compose.yml rsyslog
Creating network rsyslog_default
Creating service rsyslog_rsyslog
[[email protected] docker-mirror]# docker stack ps rsyslog
ID                  NAME                IMAGE                       NODE                DESIRED STATE       CURRENT STATE                     ERROR               PORTS
tb1dod43fe4c        rsyslog_rsyslog.1   jumanjiman/rsyslog:latest   swarm-4             Running             Starting less than a second ago
[[email protected] docker-mirror]#

Теперь, на рое-4:

[email protected]:~# docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS               NAMES
d883e0f14d3f        jumanjiman/rsyslog:latest   "rsyslogd -n -f /e..."   6 seconds ago       Up 5 seconds        514/tcp, 514/udp    rsyslog_rsyslog.1.tb1dod43fe4cy3j5vzsy7pgv5
[email protected]:~# docker exec -it d883e0f14d3f df -h /nfs
Filesystem                Size      Used Available Use% Mounted on
:/docker/example          7.2T      5.5T      1.7T  77% /nfs
[email protected]:~#

Этот том будет создан (но не разрушен) на любом узле рой, в котором работает стек.

[email protected]:~# docker volume inspect rsyslog_example
[
    {
        "CreatedAt": "2017-09-29T13:53:59+10:00",
        "Driver": "local",
        "Labels": {
            "com.docker.stack.namespace": "rsyslog"
        },
        "Mountpoint": "/var/lib/docker/volumes/rsyslog_example/_data",
        "Name": "rsyslog_example",
        "Options": {
            "device": ":/docker/example",
            "o": "addr=10.40.0.199,nolock,soft,rw",
            "type": "nfs"
        },
        "Scope": "local"
    }
]
[email protected]:~#

Ответ 2

Да, вы можете напрямую ссылаться на NFS из файла компоновки:

volumes:
   db-data:
      driver: local
      driver_opts:
        type: nfs
        o: addr=$SOMEIP,rw
        device: ":$PathOnServer"

И аналогичным образом вы можете создать том nfs на каждом хосте.

docker volume create --driver local --opt type=nfs --opt o=addr=$SomeIP,rw --opt device=:$DevicePath --name nfs-docker

Ответ 3

Мое решение для AWS EFS, которое работает:

  1. Создать EFS (не забудьте открыть порт NFS 2049 в группе безопасности)
  2. Установите пакет nfs-common:

    sudo apt-get install -y nfs-common

  3. Проверьте, работает ли ваш efs:

    mkdir efs-test-point
    sudo chmod go+rw efs-test-point
    sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [YOUR_EFS_DNS]:/ efs-test-point
    touch efs-test-point/1.txt
    sudo umount efs-test-point/
    ls -la efs-test-point/

    каталог должен быть пустым

    sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [YOUR_EFS_DNS]:/ efs-test-point

    ls -la efs-test-point/

    файл 1.txt должен существовать

  4. Сконфигурируйте файл docker-compose.yml:

    services:
      sidekiq:
        volumes:
          - uploads_tmp_efs:/home/application/public/uploads/tmp
      ...
    volumes:
      uploads_tmp_efs:
        driver: local
        driver_opts:
          type: nfs
          o: addr=[YOUR_EFS_DNS],nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2
          device: [YOUR_EFS_DNS]:/

Ответ 4

Моя проблема была решена с изменением типа опции драйвера на NFS4.

volumes:
  my-nfs-share:
    driver: local
    driver_opts:
      type: "nfs4"
      o: "addr=172.24.0.107,rw"
      device: ":/mnt/sharedwordpress"

Ответ 5

В зависимости от того, как мне нужно использовать громкость, у меня есть следующие 3 варианта.

Во-первых, вы можете создать именованный том напрямую и использовать его в качестве внешнего тома в compose или в качестве именованного тома в команде docker run docker service create или команды docker service create.

  # create a reusable volume
  $ docker volume create --driver local \
      --opt type=nfs \
      --opt o=nfsvers=4,addr=nfs.example.com,rw \
      --opt device=:/path/to/dir \
      foo

Далее, есть синтаксис --mount который работает из docker run --mount и docker service create --mount. Это довольно длинный параметр, и когда вы встраиваете параметр с разделителями-запятыми в другой параметр с разделителями-запятыми, вам нужно передать некоторые кавычки (экранированные, чтобы оболочка не удаляла их) в выполняемой команде. Я склонен использовать это для одноразового контейнера, которому требуется доступ к NFS (например, служебный контейнер для установки каталогов NFS):

  # or from the docker run command
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=nfs.example.com\",volume-opt=device=:/host/path \
    foo

  # or to create a service
  $ docker service create \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=nfs,\"volume-opt=o=nfsvers=4,addr=nfs.example.com\",volume-opt=device=:/host/path \
    foo

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

  # inside a docker-compose file
  ...
  services:
    example-app:
      volumes:
      - "nfs-data:/data"
  ...
  volumes:
    nfs-data:
      driver: local
      driver_opts:
        type: nfs
        o: nfsvers=4,addr=nfs.example.com,rw
        device: ":/path/to/dir"
  ...

В каждом из этих примеров:

  • Тип установлен в nfs, а не nfs4. Это связано с тем, что docker предоставляет некоторые полезные функции для поля addr, но только для типа nfs.
  • o - это параметры, которые передаются системному вызову mount. Одно из отличий между монтированием syscall и командой mount в Linux состоит в том, что у устройства есть часть перед параметром : перемещено в опцию addr.
  • nfsvers используется для установки версии NFS. Это позволяет избежать задержек, так как ОС сначала пробует другие версии NFS.
  • addr может быть DNS-именем, когда вы используете type=nfs, а не только IP-адрес. Очень полезно, если у вас есть несколько VPC с разными NFS-серверами, использующими одно и то же DNS-имя, или если вы хотите настроить NFS-сервер в будущем без обновления каждого тома монтирования.
  • Другие опции, такие как rw (чтение-запись), могут быть переданы опции o.
  • Поле device - это путь на удаленном сервере NFS. Требуется ведущий двоеточие. Это артефакт, как команда монтирования перемещает IP - адрес в addr поле для системного вызова. Этот каталог должен существовать на удаленном хосте до того, как том будет смонтирован в контейнер.
  • В синтаксисе --mount поле dst - это путь внутри контейнера. Для именованных томов вы задаете этот путь в правой части монтирования тома (в кратком синтаксисе) в docker run -v.

Если у вас возникают проблемы с правами доступа к удаленному тому NFS, я часто сталкиваюсь с контейнерами, работающими как root, с сервером NFS, установленным на root squash (изменяя все права доступа root для пользователя nobody). Вам необходимо либо настроить контейнеры для работы с хорошо известным UID без полномочий root, который имеет доступ к каталогам на NFS-сервере, либо отключить корневое сжатие на NFS-сервере.