Объем одного файла, установленный как каталог в Docker

Документация докеров говорит, что можно установить один файл в контейнер Docker:

Флаг -v также может использоваться для монтирования одного файла, а не только каталогов - с главной машины.

$ docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash

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

Когда я пытаюсь, однако, файл монтируется как каталог:

[email protected] ~/project $ docker run --rm -it -v file.json:/file.json test
total 80K
drwxr-xr-x  9 root root 4.0K Dec  7 12:58 .
drwxr-xr-x 63 root root 4.0K Dec  7 12:58 ..
drwxr-xr-x  2 root root 4.0K Dec  4 16:10 file.json

Мой Dockerfile выглядит так:

FROM ubuntu:14.04
MAINTAINER Tom
CMD ["ls", "-lah", "/test"]

Версия Docker - 1.9.1, постройте a34a1d5.

Это проблема документации, непонимание на моей стороне или что-то еще происходит?

Ответы

Ответ 1

test - это имя вашего изображения, которое вы создали с помощью docker build -t test ', а не папки /test.

Попробуйте Dockerfile с помощью:

CMD ["ls", "-lah", "/"]
or
CMD ["cat", "/file.json"]

и

docker run --rm -it -v $(pwd)/file.json:/file.json test

Обратите внимание на использование $(pwd) для монтирования файла с полным полным путем (относительные пути не поддерживаются)

Ответ 2

Возможно, это ясно из ответов выше... но мне потребовалось некоторое время, чтобы понять это в моем случае.

Основная причина, по которой файл, совместно используемый с -v, отображаться как каталог, а не файл, - это то, что Docker не смог найти файл на хосте. Таким образом, Docker создает новый каталог в контейнере с именем, являющимся именем несуществующего файла на хосте, поскольку докер считает, что пользователь просто хочет обмениваться томом/каталогом, который будет создан в будущем.

Итак, в описанной выше проблеме, если вы использовали относительный каталог в команде -v, а докер не понимает относительные каталоги, это означает, что файл не найден на хосте, и поэтому docker создал каталог. И ответ выше, который предлагает использовать $(pwd), будет правильным решением, если проблема связана с относительным каталогом.

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

Это может быть просто глупая опечатка...

Возможно, вы выполняете команду "docker run" от клиента, который создает контейнер докеров на другом хосте, а общий файл не существует на этом другом хосте. Файл, совместно используемый с -v, должен существовать на хосте, где агент докеров запускает контейнер... не обязательно на клиенте, где выполняется команда "docker run -v..." (хотя они будут одинаковыми в во многих случаях).

Есть другие возможные объяснения выше для Mac и Windows... это тоже может быть.

Таким образом, файл, отсутствующий на хосте, является проблемой... устранение проблемы в вашей настройке... использование $(pwd) может быть решением, но не всегда.

Ответ 3

Я немного побеспокоился и диагностировал эту проблему с докером в Windows. Это также может повлиять на людей, работающих на Mac OSX, поэтому я добавляю ответ здесь для людей, которые могут иметь проблему в этих средах, поскольку мой поиск привел меня в это место и добавил объяснение того, что, как представляется, происходит в докере.

В Windows или Mac OSX ваш докер работает на виртуальной машине boot2docker, и по умолчанию используется только каталог пользователей. В Windows этот каталог пользователя используется как /c/Users/, однако в оболочке MinGW, поставляемой с Docker Machine, доступ к диску можно получить как /C или/c, так что это может привести вас в гайки, если вы забудете, что команды докера на самом деле работает против виртуальной машины boot2docker, и ваши пути к файлу должны существовать на виртуальной машине boot2docker и должны быть указаны таким образом, что они существуют там, потому что то, что появляется в докере, заключается в том, что вместо того, чтобы давать предупреждение или ошибку, что каталог/файл не существует, докер молча создает указанный источник как каталог в VM-загрузчике, поэтому нет готового вывода, указывающего на то, что вы делаете что-то неправильно.

Итак, как в ответе выше, если ваш файл монтируется как каталог, тогда проверьте, что вы предоставляете абсолютный путь. Для Windows и Mac OSX убедитесь, что абсолютный путь, который вы устанавливаете, существует в вашей виртуальной машине boot2docker.

Ответ 4

При запуске docker внутри docker (например, путем монтирования /var/run/docker.sock), вы должны знать, что если вы монтируете внутри docker, используемые пути к файлам всегда совпадают с вашим хостом.

Так что, если на вашем хосте вы делаете следующее монтирование:

-v /tmp/foobar.txt:/my/path/foobar.txt

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

-v /my/path/foobar.txt:/my/other/path.txt

но вместо этого используйте путь к файлу хоста, например:

-v /tmp/foobar:txt:/my/other/path.txt

Ответ 5

Существует простое решение для тех, кто использует машину VirtualBox. По умолчанию добавляется папка C:/User. Если ваш проект находится в проектах C:/, добавьте эту папку, чтобы сделать ее доступной в VB (с автомонтированием).

Ответ 6

Случай, когда Docker может не найти файл, даже если вы уверены, что он существует

Как указывало edi9999, если вы скажете демону docker монтировать файл, он не будет смотреть на вашу текущую контейнерную файловую систему, он будет смотреть на файловую систему, в которой работает демон.

Вы можете столкнуться с этой проблемой, если ваш демон Docker по какой-то причине работает в другом месте.

❯ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock docker
/ # echo "bar" > /foo
/ # docker run --rm -v /foo:/foo ubuntu bash -c 'cat foo'
cat: foo: Is a directory

Docker не может найти файл /foo на своем хосте, поэтому он (полезно?) создает там каталог, так что по крайней мере вы что-то смонтировали.

Обходной путь

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

❯ docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock -v /dev/shm:/dev/shm docker
/ # echo "bar" > /dev/shm/foo
/ # docker run --rm -v /dev/shm/foo:/dev/shm/foo ubuntu bash -c 'cat /dev/shm/foo'
bar

Это заставляет путь /dev/shm/foo ссылаться на один и тот же файл в любом контексте, поэтому вы можете ссылаться на файл из внешнего контейнера, и демон найдет его на хосте, что означает, что он будет отображаться как сам в внутренний контейнер, а не как каталог.