Як змонтувати один файл в томі


259

Я намагаюся докерізувати додаток php. У dockerfile я завантажую архів, витягую його тощо.

Все працює добре, проте якщо виходить нова версія, і я оновлюю dockerfile, мені доведеться перевстановити додаток, оскільки config.php перезаписується.

Тому я подумав, що зможу змонтувати файл як об'єм, як це робиться з базою даних.

Я спробував це двома способами, з обсягом і прямим шляхом.

докер-композиція:

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

Відповіді:


314

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

Якщо ви запустили докер-композицію з /src/docker/myappпапки


81
Як я вже сказав, якщо я спробую /src/docker/myapp/upload/config.php:/var/www/html/config.php Докер створить папку для завантаження, а потім папку config.php. Не файл.
Якуб Ющак

9
У своєму дописі ви писали інакше. Якщо файл є, його слід встановити як файл.
BlackStork

16
Для того, щоб це працювало, мені довелося поставити абсолютний шлях. Порада з використанням PWD тут дуже допомогла, дякую!
Стів Сміт

4
Для мене це створення папки, а не файлів, але я думаю, тому що цей файл скопіюється пізніше на цьому шляху, чи все-таки можна відкласти прив’язку?
eKelvin

18
якщо /src/docker/myapp/upload/config.php не існує в докер-хості, створить папку ... Що я роблю, це створити сценарій, який створює порожній файл перед запуском докерного запуску - було б ідеально якщо я можу доручити докер зробити це для мене через аргументи cmd line.
онкоберез

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 для прив’язки-монтажу файлу або каталогу, які ще не існують на хості Докер, -v створить для вас кінцеву точку. Він завжди створюється як каталог .

Тому він завжди створюється як каталог, оскільки мій хокер докера не має $(pwd)/config.py.

Навіть якщо я створюю config.py в хості докера. $(pwd)/config.pyпросто перезавантажте /root/app/config.pyне експортуючи /root/app/config.py.


16
Я просто додав touch path/to/fileв Dockerfileтак що , коли я встановлюю він все одно буде файл (не створений реж)
Шаді

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

Дякую, Subbu, @Jakub Juszczak, це має бути прийнятою відповіддю, це єдина відповідь, яка взагалі відповідає на питання, і це спрацювало на мене
neokyle

2
Це насправді не відповідає на питання. томи також працюватимуть (тому що питання йде в абсолютному напрямку). Єдина відмінність між --mountі -vполягає у поведінці, коли хост-частина обсягу ще не існує. За вашим посиланням:> Якщо ви використовуєте -v або --volume для прив'язки-монтування файлу або каталогу, які ще не існують на хості Докер, -v створює для вас кінцеву точку. Він завжди створюється як каталог.
Хрещений батько

2
Я не знаю, як перекласти це на докер-композицію. «Маленька допомога?
мсанфорд

@msanford Я відповів прикладом докер-композиції до відповіді.
sebisnow

10

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

Наступні приклади не вдасться при використанні контейнерів на базі Windows, оскільки призначення об'єму або прив'язки всередині контейнера має бути одним із: неіснуючого або порожнього каталогу; або привід, відмінний від C :. Крім того, джерелом монтажу прив'язки повинен бути локальний каталог, а не файл .

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 ви можете вказати кріплення гучності типу "bind" (замість типового типу "volume"), що дозволяє монтувати один файл у контейнер. Шукати "прив’язати кріплення" в документах тома докер-композиту: https://docs.docker.com/compose/compose-file/#volumes

У моєму випадку я намагався вмонтувати єдиний файл ".secrets" у свою програму, який містив секрети лише для локальної розробки та тестування. У виробництві моє додаток отримує ці секрети замість AWS.

Якщо я змонтував цей файл у якості тома, використовуючи скорочений синтаксис:

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

Docker створить каталог ".secrets" всередині контейнера замість того, щоб відображати файл поза контейнером. Мій код тоді призведе до помилки типу "IsADirectoryError: [Errno 21] - це каталог:" .secrets "".

Я виправив це, використовуючи довгий синтаксис, вказавши мій секретний файл, використовуючи кріплення гучності "лише для читання":

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файлі версією 1.24.1 докер-композиту, збіркою 4667896b і він працював.
Acumenus

6
Я все-таки отримую каталог замість файлу.
chovy

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

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

Коли ви хочете поділитися файлом у Windows, він повинен існувати, перш ніж поділитися ним з контейнером.


Ви не можете використовувати PowerShell з docker, це створює фіксацію постачальника і шкодить спільноті ...
Matej 'Yin' Gagyi

0

Можливо, це комусь допомагає.

У мене була ця проблема і все спробувала. Встановлення томів виглядало добре, і навіть якщо я монтував каталог (а не файли), я мав імена файлів у змонтованому каталозі правильно, але монтувався як dirs.

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

Після відключення брандмауера все працювало нормально.


Дякую тобі за це! Ваш пост дав мені зрозуміти, що мій selinux налаштований на виконання, і це спричиняє всі мої неприємності. Не знаю, чому ви були зняті з голосу ¯_ (ツ) _ / ¯
Октавіан

0

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

У цьому прикладі я монтую файл env-command, який вже існує в моєму робочому каталозі

$ 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.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.