Как смонтировать один файл в томе


259

Я пытаюсь докеризировать приложение php. В докерфайле скачиваю архив, распаковываю его и т. Д.

Все работает нормально, однако, если выходит новая версия, и я обновляю dockerfile, мне нужно переустановить приложение, потому что config.php перезаписывается.

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

Я попробовал это двумя способами, с объемом и прямым путем.

докер-Compose:

version: '2'
services:
  app:
    build: src
    ports:
      - "8080:80"
    depends_on:
      - mysql
    volumes:
      -  app-conf:/var/www/html/upload
      -  app-conf:/var/www/html/config.php
    environment:
      DB_TYPE: mysql
      DB_MANAGER: MysqlManager

  mysql:
    image: mysql:5.6
    container_name: mysql
    volumes:
      - mysqldata:/var/lib/mysql
    ports:
      - 3306:3306
    environment:
      MYSQL_ROOT_PASSWORD:
      MYSQL_DATABASE:
      MYSQL_USER:
      MYSQL_PASSWORD:

volumes:
  mysqldata:
  app-conf:

Что приводит к ошибке:

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

/src/docker/myapp/upload:/var/www/html/upload
/src/docker/myapp/upload:/var/www/html/config.php

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

Но тогда терпит неудачу с

/var/www/html/config.php \\ "вызвал \\" не каталог \\ "\" "

Если я попробую это с

/src/docker/myapp/upload/config.php:/var/www/html/config.php

Docker создает папку загрузки, а затем папку config.php. Не файл

Или есть другой способ сохранить конфиг?


В моем случае я просто «прикоснулся» к пустому файлу перед созданием контейнера / тома. Если файл не существует, он создает каталог.
FreeSoftwareServers

Ответы:


313

TL; DR / Примечание:

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

Тома файлов создаются таким образом в Docker (пример абсолютного пути (можно использовать переменные env), и вам необходимо указать имя файла):

    volumes:
      - /src/docker/myapp/upload:/var/www/html/upload
      - /src/docker/myapp/upload/config.php:/var/www/html/config.php

Вы также можете сделать:

    volumes:
      - ${PWD}/upload:/var/www/html/upload
      - ${PWD}/upload/config.php:/var/www/html/config.php

Если вы запускаете docker-compose из /src/docker/myappпапки


81
Как я уже сказал, если я попробую /src/docker/myapp/upload/config.php:/var/www/html/config.php, Docker создаст папку загрузки, а затем папку config.php. Не файл
Якуб

9
В своем посте вы написали иначе. Если файл есть, он должен быть подключен как файл.
BlackStork

16
Чтобы это работало, мне нужно было указать абсолютный путь. Советы по использованию PWD здесь очень помогли, спасибо!
Стив Смит

4
Для меня это создание папки, а не файлов, но я думаю, потому что этот файл копируется позже по этому пути, есть ли способ отложить привязку?
eKelvin

18
если /src/docker/myapp/upload/config.php не существует в хосте, docker создаст папку ... То, что я делаю, - это создание сценария, который создает пустой файл перед запуском docker - было бы идеально если я могу поручить Docker сделать это для меня через строковые аргументы cmd.
Cancebero

78

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

Я имею в виду, что я думал, что приведенная ниже команда отобразит $(pwd)/config.pyхост Docker /root/app/config.pyв контейнер в виде файла.

docker run -v $(pwd)/config.py:/root/app/config.py my_docker_image

Тем не менее, он всегда создавал каталог с именем config.py, а не файл.

в поисках подсказки я нашел причину ( отсюда )

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

Поэтому он всегда создается как каталог, потому что мой докер хост не имеет $(pwd)/config.py.

Даже если я создаю config.py в хосте Docker. $(pwd)/config.pyпросто перезапись /root/app/config.pyне экспортируется /root/app/config.py.


16
Я просто добавил touch path/to/fileв Dockerfileтак, чтобы, когда я монтировал, это все еще был файл (не созданный dir)
shadi

8
Левая сторона :должна быть на полном пути. Это работает таким образом
SDKKS

touchБыл ответ, сделать это в Dockerfile тогда ваш докер-Compose монтирования тома будет корректно работать без создания каталога
ctrlbrk

27

Используйте mount ( --mount) вместо тома ( -v)

Дополнительная информация: https://docs.docker.com/storage/bind-mounts/

Пример:

Убедитесь, что /tmp/a.txt существует на хосте докера

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh

Спасибо Суббу, @Jakub Juszczak, это должен быть принятый ответ, это единственный ответ, который вообще отвечает на вопрос, и это сработало для меня
neokyle

2
Это на самом деле не отвечает на вопрос. также будут работать тома (потому что проблема в абсолютном пути). Единственная разница между --mountи -vзаключается в поведении, когда основная часть тома еще не существует. По вашей ссылке:> Если вы используете -v или --volume для привязки-монтирования файла или каталога, которого еще нет на хосте Docker, -v создаст для вас конечную точку. Он всегда создается как каталог.
Крестный отец

2
Я не знаю, как перевести это в docker-compose. 'Маленькая помощь?
MSanford

@msanford Я добавил пример docker-compose в ответ.
sebisnow

10

Для любого, кто использует контейнер Windows, такой как я, знайте, что вы НЕ МОЖЕТЕ связывать или монтировать отдельные файлы, используя контейнер Windows.

Следующие примеры завершатся неудачно при использовании контейнеров на основе Windows, поскольку местом назначения тома или монтирования привязки внутри контейнера должен быть один из: несуществующего или пустого каталога; или диск, отличный от C :. Кроме того, источником монтирования bind должен быть локальный каталог, а не файл .

net use z: \\remotemachine\share

docker run -v z:\foo:c:\dest ...

docker run -v \\uncpath\to\directory:c:\dest ...

docker run -v c:\foo\somefile.txt:c:\dest ...

docker run -v c:\foo:c: ...

docker run -v c:\foo:c:\existing-directory-with-contents ...

Это трудно заметить, но это там

Ссылка на проблему Github относительно отображения файлов в контейнер Windows


9

Способ, который работал для меня, это использовать bindкрепление

  version: "3.7"    
  services:
  app:
    image: app:latest
    volumes:
      - type: bind
        source: ./sourceFile.yaml
        target: /location/targetFile.yaml

Спасибо Майку Породе за ответ по адресу: Монтирование отдельного файла из тома с помощью docker-compose.

Вам нужно использовать «длинный синтаксис» для выражения bindмонтирования: https://docs.docker.com/compose/compose-file/#long-syntax


7

Начиная с версии 3.2 файла docker-compose вы можете указать монтирование тома типа «bind» (вместо типа по умолчанию «том»), которое позволяет монтировать один файл в контейнер. Ищите «bind mount» в документации тома docker-compose: https://docs.docker.com/compose/compose-file/#volumes

В моем случае я пытался подключить в приложение один файл «.secrets», который содержал секреты только для локальной разработки и тестирования. Вместо этого мое приложение извлекает эти секреты из AWS.

Если я смонтировал этот файл как том, используя сокращенный синтаксис:

volumes:
 - ./.secrets:/data/app/.secrets

Docker бы создать «.secrets» каталог внутри контейнера вместо отображения в файл снаружи контейнера. Мой код будет вызывать ошибку, такую ​​как «IsADirectoryError: [Errno 21] Является каталогом:« .secrets »».

Я исправил это, используя вместо этого длинный синтаксис, указав мой файл секретов с помощью монтируемого только для чтения тома «bind»:

volumes:
 - type: bind
   source: ./.secrets
   target: /data/app/.secrets
   read_only: true

Теперь Docker правильно монтирует мой файл .secrets в контейнер, создавая файл внутри контейнера вместо каталога. Надеюсь, что другие найдут этот пример полезным!


Спасибо, сэр! Это было решение, которое мне нужно было, чтобы иметь возможность смонтировать мой файл WordPress wp-config.php (и остановить его создание в качестве каталога)
Jono

6

Вы также можете использовать относительный путь к вашему docker-compose.ymlфайлу, как это (проверено на хосте Windows, контейнере Linux):

 volumes:
      - ./test.conf:/fluentd/etc/test.conf

1
Я протестировал это на Mac с version: '3.7'указанным в docker-compose.ymlфайле с версией docker-compose 1.24.1, сборка 4667896b, и это сработало.
Acumenus

6
Я все еще получаю каталог вместо файла.
Чови

0

Для меня проблема была в том, что у меня была битая символическая ссылка на файл, который я пытался смонтировать в контейнер


0

У меня была такая же проблема на Windows Docker 18.06.1-ce-win73 (19507).

Извлечение и повторное добавление общего диска через панель настроек Docker, и все снова заработало.


0

В Windows, если вам нужна переменная $ {PWD} env в вашем docker-compose.yml, вы можете создать файл .env в той же директории, что и ваш файл docker-compose.yml, а затем вставить вручную местоположение вашей папки.

CMD (pwd_var.bat):

echo PWD=%cd% >> .env

Powershell (pwd_var.ps1):

$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'; echo "PWD=$(get-location).path" >> .env

Есть и другие полезные функции для docker-compose переменных .env: https://docs.docker.com/compose/reference/envvars/, особенно для COMPOSE_CONVERT_WINDOWS_PATHSпеременной env, которые позволяют docker compose принимать путь к Windows с помощью baskslash"\" .

Если вы хотите поделиться файлом в Windows, файл должен существовать, прежде чем делиться им с контейнером.


Вы не можете использовать PowerShell с докером, это создает
привязку

0

Может быть, это кому-то помогает.

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

Я попытался повторно включить общие диски, и Докер пожаловался, что брандмауэр активен.

После отключения брандмауэра все работало нормально.


Спасибо вам за это! Ваш пост заставил меня понять, что мой selinux был настроен на принудительное исполнение, и это вызывало все мои проблемы. Не знаю, почему за вас проголосовали ¯_ (ツ) _ / ¯
Октавиан

0

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

В этом примере я монтирую файл команд env, который уже существует в моем рабочем каталоге

$ docker run  --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"

-1

У меня такая же проблема на моей Windows 8.1

Оказалось, что это связано с регистрозависимостью пути. Я звонил docker-compose upиз справочникаcd /c/users/alex/ и внутри контейнера файл был превращен в каталог.

Но когда я сделал cd /c/Users/alex/(не пользователи заглавными буквами) и позвонилdocker-compose up оттуда, это сработало.

В моей системе оба пользователя dir и Alex dir пишутся с большой буквы, хотя кажется, что значение имеет только Users dir.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.