Jak zamontować pojedynczy plik w woluminie

255

Usiłuję dokować aplikację PHP. W pliku dokera pobieram archiwum, rozpakowuję go itp.

Wszystko działa dobrze, jednak jeśli zostanie wydana nowa wersja i zaktualizuję plik docker, muszę ponownie zainstalować aplikację, ponieważ plik config.php zostanie nadpisany.

Pomyślałem więc, że mogę zamontować plik jako wolumin, tak jak w przypadku bazy danych.

Próbowałem na dwa sposoby, z woluminem i bezpośrednią ścieżką.

dokowanie-komponowanie:

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:

Co powoduje błąd:

I próbowałem z podaną ścieżką, jako zamontowany wolumin.

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

Jednak oba sposoby nie działają. Po zamontowaniu woluminu widzę, że przesyłanie jest tworzone.

Ale potem się nie udaje

/var/www/html/config.php \\ „spowodował \\” nie katalog \\ "\"

Jeśli spróbuję

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

Docker tworzy folder przesyłania, a następnie folder config.php. Nie plik.

Czy istnieje inny sposób na utrwalenie konfiguracji?

Jakub Juszczak
źródło
W moim przypadku po prostu „dotykam” pustego pliku przed utworzeniem kontenera / woluminu. Jeśli plik nie istniał, utworzył katalog.
FreeSoftwareServers

Odpowiedzi:

310

TL; DR / Uwaga:

Jeśli zamiast pliku, który próbujesz zamontować, tworzony jest katalog, prawdopodobnie nie podałeś prawidłowej i bezwzględnej ścieżki. Jest to powszechny błąd w cichym i mylącym trybie awarii.

Woluminy plików są wykonywane w ten sposób w oknie dokowanym (przykład ścieżki bezwzględnej (można użyć zmiennych env) i należy podać nazwę pliku):

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

Możesz także:

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

Jeśli uruchomisz okno dokowane-komponuj z /src/docker/myappfolderu

BlackStork
źródło
81
Tak jak powiedziałem, jeśli spróbuję /src/docker/myapp/upload/config.php:/var/www/html/config.php Docker utworzy folder przesyłania, a następnie folder config.php. Nie plik.
Jakub Juszczak
9
W swoim poście napisałeś inaczej. Jeśli plik istnieje, powinien zostać zamontowany jako plik.
BlackStork
16
Aby to zadziałało, musiałem podać absolutną ścieżkę. Wskazówka dotycząca PWD bardzo mi pomogła, dziękuję!
Steve Smith
4
Dla mnie to tworzenie folderu zamiast plików, ale myślę, że ponieważ ten plik jest kopiowany później w tej ścieżce, czy w ogóle można opóźnić wiązanie?
eKelvin,
18
jeśli /src/docker/myapp/upload/config.php nie istnieje w oknie dokowanym hosta utworzy folder ... To, co robię, to utworzenie skryptu, który tworzy pusty plik przed uruchomieniem okna dokowanego - byłoby idealnie czy mogę poinstruować dokera, aby zrobił to dla mnie za pomocą argumentów linii cmd.
cancerbero,
78

Cierpiałem na podobny problem. Próbowałem zaimportować mój plik konfiguracyjny do mojego kontenera, aby móc go naprawić za każdym razem, gdy potrzebuję, bez ponownego budowania obrazu.

Mam na myśli, że myślałem, że poniższe polecenie $(pwd)/config.pyzamapuje z hosta Dockera /root/app/config.pyna kontener jako plik.

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

Jednak zawsze tworzył katalog o nazwie config.py, a nie plik.

szukając wskazówek, znalazłem przyczynę ( stąd )

Jeśli użyjesz opcji -v lub --volume, aby podłączyć plik lub katalog, który jeszcze nie istnieje na hoście Docker, opcja -v utworzy punkt końcowy. Zawsze jest tworzony jako katalog .

Dlatego zawsze jest tworzony jako katalog, ponieważ mój host dokera nie ma go $(pwd)/config.py.

Nawet jeśli utworzę config.py na hoście dokera. $(pwd)/config.pypo prostu overwirte /root/app/config.pynie eksportuje /root/app/config.py.

SangminKim
źródło
16
Ja po prostu dodaje się touch path/to/filew Dockerfiletak że kiedy zamontować to i tak będzie to plik (a nie stworzony dir)
Shadi
8
lewa strona :musi być pełną ścieżką. Działa w ten sposób
sdkks
touchByła odpowiedź, to zrobić w Dockerfile wówczas objętość doker-komponować zamontować będzie działać poprawnie bez tworzenia katalogów
ctrlbrk
27

Użyj mount ( --mount) zamiast volume (-v )

Więcej informacji: https://docs.docker.com/storage/bind-mounts/

Przykład:

Upewnij się, że na hoście dokera istnieje plik /tmp/a.txt

docker run -it --mount type=bind,source=/tmp/a.txt,target=/root/a.txt alpine sh
Subbu M
źródło
Dziękuję Subbu, @Jakub Juszczak to powinna być zaakceptowana odpowiedź, to jedyna odpowiedź, która w ogóle odpowiada na pytanie, i zadziałało dla mnie
neokyle
2
To tak naprawdę nie odpowiada na pytanie. woluminy również będą działać (ponieważ problem znajduje się na ścieżce bezwzględnej). Jedyną różnicą między --mounti -vjest zachowanie, gdy część hosta woluminu jeszcze nie istnieje. Zgodnie z linkiem:> Jeśli użyjesz opcji -v lub --volume, aby podłączyć-mount plik lub katalog, który jeszcze nie istnieje na hoście Docker, opcja -v utworzy punkt końcowy. Zawsze jest tworzony jako katalog.
The Godfather
2
Nie wiem, jak to przełożyć na kompozycję dokera. 'Drobna pomoc?
msanford,
@msanford Do odpowiedzi dodałem przykład skomponowania dokera.
sebisnow
10

Dla każdego, kto używa kontenera Windows takiego jak ja, wiedz, że NIE MOŻESZ powiązać ani zamontować pojedynczych plików za pomocą kontenera Windows.

Poniższe przykłady zakończą się niepowodzeniem podczas korzystania z kontenerów opartych na systemie Windows, ponieważ miejscem docelowym woluminu lub podłączenia montowania wewnątrz kontenera musi być jeden z: nieistniejącego lub pustego katalogu; lub dysk inny niż C :. Ponadto źródłem montowania powiązań musi być katalog lokalny, a nie plik .

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

Trudno to dostrzec, ale tam jest

Link do problemu Github dotyczącego mapowania plików do kontenera Windows

Justin Lessard
źródło
6

Możesz również użyć ścieżki względnej do swojego docker-compose.ymlpliku w ten sposób (testowany na hoście Windows, kontener Linux):

 volumes:
      - ./test.conf:/fluentd/etc/test.conf
Daniel
źródło
1
Przetestowałem to na komputerze Mac z version: '3.7'określonym w docker-compose.ymlpliku z wersją dokującą-kompozycję w wersji 1.24.1, kompilacją 4667896b i działało.
Acumenus
6
Nadal dostaję katalog zamiast pliku.
chovy
6

Począwszy od wersji skomponowanej przez dokera w wersji 3.2 można określić podłączenie woluminu typu „bind” (zamiast domyślnego typu „wolumin”), które pozwala zamontować pojedynczy plik w kontenerze. Wyszukaj „bind mount” w dokumenatowych dokumentach woluminów: https://docs.docker.com/compose/compose-file/#volumes

W moim przypadku próbowałem zamontować pojedynczy plik „.secrets” w mojej aplikacji, który zawierał sekrety tylko dla lokalnego programowania i testowania. Podczas produkcji moja aplikacja pobiera te sekrety z AWS.

Jeśli podłączyłem ten plik jako wolumin przy użyciu skróconej składni:

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

Docker utworzyłby katalog „.secrets” w kontenerze zamiast do pliku poza kontenerem. Mój kod wygenerowałby wówczas błąd taki jak „IsADirectoryError: [Errno 21] To katalog:„ .secrets ””.

Naprawiłem to, używając zamiast tego składni długiej ręki, określając mój plik sekretów za pomocą montowania woluminu „bind” tylko do odczytu:

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

Teraz Docker poprawnie montuje mój plik .secrets w kontenerze, tworząc plik w kontenerze zamiast katalogu. Mam nadzieję, że inni uznają ten przykład za pomocny!

Carlton Duffett
źródło
Dziękuję Panu! To było rozwiązanie muszę być w stanie zamontować mój WordPress pliku wp-config.php (i zatrzymać tworzone jako katalog)
Jono
0

Dla mnie problemem było to, że miałem uszkodzony symboliczny link w pliku, który próbowałem zamontować w kontenerze

jla
źródło
0

Miałem ten sam problem w systemie Windows Docker 18.06.1-ce-win73 (19507).

Usunięcie i ponowne dodanie udostępnionego dysku za pomocą panelu ustawień Dockera i wszystko działało ponownie.

Basen
źródło
0

W systemie Windows, jeśli potrzebujesz zmiennej env $ {PWD} w pliku docker-compose.yml, możesz utworzyć plik .env w tym samym katalogu, co plik docker-compose.yml, a następnie ręcznie wstaw lokalizację folderu.

CMD (pwd_var.bat):

echo PWD=%cd% >> .env

PowerShell (pwd_var.ps1):

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

Jest więcej dobrych funkcji, które można usłyszeć w przypadku zmiennych .env w oknie dokowanym: https://docs.docker.com/compose/reference/envvars/, szczególnie w przypadku COMPOSE_CONVERT_WINDOWS_PATHSzmiennej env, która pozwala komponentowi docker zaakceptować ścieżkę systemu Windows za pomocą baskslash "\".

Jeśli chcesz udostępnić plik w systemie Windows, plik musi istnieć przed udostępnieniem go kontenerowi.

CallMarl
źródło
Nie można używać programu PowerShell z dokerem, tworzy on blokadę dostawcy i szkodzi społeczności ...
Matej 'Yin' Gagyi
0

Może to komuś pomaga.

Miałem ten problem i próbowałem wszystkiego. Powiązania woluminów wyglądały dobrze i nawet jeśli podłączyłem katalog (nie pliki), miałem nazwy plików w katalogu zamontowanym poprawnie, ale zamontowane jako katalogi.

Próbowałem ponownie włączyć dyski współdzielone i Docker narzekał, że zapora jest aktywna.

Po wyłączeniu zapory wszystko działało dobrze.

Josef Sábl
źródło
Dziękuję za to! Twój post uświadomił mi, że mój selinux został ustawiony na egzekwowanie i to spowodowało wszystkie moje problemy. Nie wiem, dlaczego zostałeś odrzucony ¯_ (ツ) _ / ¯
Octavian
0

Możesz montować pliki lub katalogi / foldery, wszystko zależy od pliku źródłowego lub katalogu. Musisz także podać pełną ścieżkę lub jeśli nie masz pewności, czy możesz użyć PWD. Oto prosty działający przykład.

W tym przykładzie instaluję plik poleceń env, który już istnieje w moim katalogu roboczym

$ docker run  --rm -it -v ${PWD}/env-commands:/env-commands aravindgv/eosdt:1.0.5 /bin/bash -c "cat /env-commands"
Aravind GV
źródło
-1

Mam ten sam problem w moim systemie Windows 8.1

Okazało się, że było to spowodowane rozróżnianiem wielkości liter w ścieżce. Zadzwoniłem docker-compose upz katalogu cd /c/users/alex/i wewnątrz kontenera plik został zamieniony w katalog.

Ale kiedy to zrobiłem cd /c/Users/alex/(nie użytkownicy pisali wielkie litery) i zadzwoniłem docker-compose upstamtąd, zadziałało.

W moim systemie zarówno katalog użytkowników, jak i katalog Alexa są pisane dużymi literami, choć wydaje się, że tylko katalog użytkowników ma znaczenie.

Alex Velickiy
źródło