Mam aplikację z następującymi usługami:
web/
- przechowuje i uruchamia serwer WWW z kolbą Pythona 3 na porcie 5000. Używa sqlite3.worker/
- maindex.js
plik, który jest robotem dla kolejki. serwer WWW wchodzi w interakcję z tą kolejką za pomocą interfejsu API json przez port9730
. Pracownik używa Redis do przechowywania. Pracownik przechowuje również dane lokalnie w folderzeworker/images/
Teraz to pytanie dotyczy tylko worker
.
worker/Dockerfile
FROM node:0.12
WORKDIR /worker
COPY package.json /worker/
RUN npm install
COPY . /worker/
docker-compose.yml
redis:
image: redis
worker:
build: ./worker
command: npm start
ports:
- "9730:9730"
volumes:
- worker/:/worker/
links:
- redis
Po uruchomieniu docker-compose build
wszystko działa zgodnie z oczekiwaniami, a wszystkie moduły npm są instalowane /worker/node_modules
zgodnie z oczekiwaniami.
npm WARN package.json unfold@1.0.0 No README data
> phantomjs@1.9.2-6 install /worker/node_modules/pageres/node_modules/screenshot-stream/node_modules/phantom-bridge/node_modules/phantomjs
> node install.js
<snip>
Ale kiedy to robię docker-compose up
, widzę ten błąd:
worker_1 | Error: Cannot find module 'async'
worker_1 | at Function.Module._resolveFilename (module.js:336:15)
worker_1 | at Function.Module._load (module.js:278:25)
worker_1 | at Module.require (module.js:365:17)
worker_1 | at require (module.js:384:17)
worker_1 | at Object.<anonymous> (/worker/index.js:1:75)
worker_1 | at Module._compile (module.js:460:26)
worker_1 | at Object.Module._extensions..js (module.js:478:10)
worker_1 | at Module.load (module.js:355:32)
worker_1 | at Function.Module._load (module.js:310:12)
worker_1 | at Function.Module.runMain (module.js:501:10)
Okazuje się, że żaden z modułów nie jest obecny /worker/node_modules
(na hoście lub w kontenerze).
Jeśli na hoście, ja npm install
, wtedy wszystko działa dobrze. Ale nie chcę tego robić. Chcę, aby kontener obsługiwał zależności.
Co tu idzie nie tak?
(Nie trzeba dodawać, że wszystkie paczki są w package.json
środku).
volumes: - worker/:/worker/
blok zdocker-compose.yml
pliku. Ten wiersz nadpisuje folder utworzony za pomocą polecenia KOPIUJ.When I run docker-compose build, everything works as expected and all npm modules are installed in /worker/node_modules as I'd expect.
- Jak to sprawdziłeś?Odpowiedzi:
Dzieje się tak, ponieważ
worker
katalog został dodany do woluminudocker-compose.yml
, ponieważ wolumin nie jest montowany podczas kompilacji.Podczas dokowania kompiluje obraz,
node_modules
katalog jest tworzony w tymworker
katalogu i wszystkie zależności są tam instalowane. Następnie w czasie wykonywaniaworker
katalog z zewnętrznego okna dokowanego jest montowany w instancji dokera (która nie ma zainstalowanejnode_modules
), ukrywającnode_modules
właśnie zainstalowaną. Możesz to sprawdzić, usuwając zamontowany wolumin z twojegodocker-compose.yml
.Obejściem tego problemu jest użycie woluminu danych do przechowywania wszystkich
node_modules
, ponieważ woluminy danych kopiują dane z wbudowanego obrazu dokera przedworker
zamontowaniem katalogu. Można to zrobić wdocker-compose.yml
następujący sposób:Nie jestem do końca pewien, czy powoduje to jakiekolwiek problemy z przenośnością obrazu, ale ponieważ wydaje się, że przede wszystkim używasz dockera do zapewnienia środowiska wykonawczego, nie powinno to stanowić problemu.
Jeśli chcesz dowiedzieć się więcej o woluminach, tutaj znajduje się miły przewodnik użytkownika: https://docs.docker.com/userguide/dockervolumes/
EDYCJA: Od tego czasu Docker zmienił swoją składnię, aby wymagać wiodącego sposobu
./
montowania w plikach względem pliku docker-compose.yml.źródło
/worker/node_modules
pozostał taki sam jak poprzednio (ze starymi zależnościami). Czy jest jakiś sposób na użycie nowego woluminu po odbudowaniu obrazu?docker-compose rm
wydaje się naprawiać ten problem, ale uważam, że musi być lepsze i łatwiejsze rozwiązanie.rebuild --no-cache
każdorazowej zmiany deps?node_modules
Folder jest zastępowane przez objętość i nie bardziej dostępnym w pojemniku. Używam natywnej strategii ładowania modułu, aby wyjąć folder z woluminu:Plik Docker:
node_modules
Katalog nie jest dostępny z zewnątrz zbiornika, ponieważ znajduje się w obrazie.źródło
node_modules
nie jest dostępny z zewnątrz kontenera, ale tak naprawdę nie jest wadą;)docker-compose run app npm install
utworzysz moduły_węzła w bieżącym katalogu i nie musisz już odbudowywać obrazu.Rozwiązanie dostarczone przez @FrederikNS działa, ale wolę jawnie nazwać wolumin mój moduł_węzła.
Mój
project/docker-compose.yml
plik (wersja dokowana-wersja 1.6+):moja struktura plików to:
Tworzy wolumin o nazwie
project_node_modules
i używa go ponownie przy każdym uruchomieniu aplikacji.Mój
docker volume ls
wygląda tak:źródło
Ostatnio miałem podobny problem. Możesz zainstalować
node_modules
gdzie indziej i ustawićNODE_PATH
zmienną środowiskową.W poniższym przykładzie zainstalowałem
node_modules
w/install
pracownik / plik Docker
docker-compose.yml
źródło
node_modules
podstawie tego artykułu . Ale doprowadziło mnie to do tego problemu . To rozwiązanie polegające na utworzeniu osobnego katalogu do skopiowaniapackage.json
, uruchomienianpm install
tam, a następnie określeniuNODE_PATH
zmiennej środowiskowej wdocker-compose.yml
celu wskazanianode_modules
folderu tego katalogu działa i wydaje się właściwe.npm install
na hoście? Wygląda nanode_modules
to, że pojawi się na hoście i zostanie odzwierciedlony w kontenerze, przejmując pierwszeństwoNODE_PATH
. Tak więc kontener użyje modułów node_modules z hosta.Istnieje eleganckie rozwiązanie:
Po prostu zamontuj nie cały katalog, ale tylko katalog aplikacji. W ten sposób nie będziesz mieć problemów
npm_modules
.Przykład:
Dockerfile.dev:
źródło
AKTUALIZACJA: Skorzystaj z rozwiązania dostarczonego przez @FrederikNS.
Napotkałem ten sam problem. Kiedy folder
/worker
zostanie zamontowany w kontenerze - cała jego zawartość zostanie zsynchronizowana (więc folder node_modules zniknie, jeśli nie masz go lokalnie).Z powodu niekompatybilnych pakietów npm opartych na systemie operacyjnym nie mogłem po prostu zainstalować modułów lokalnie - a następnie uruchomić kontener, więc ..
Moim rozwiązaniem tego było owinięcie źródła w
src
folderze, a następnie połączenienode_modules
z tym folderem przy użyciu tego pliku index.js . Tak,index.js
plik jest teraz punktem wyjścia mojej aplikacji.Po uruchomieniu kontenera podłączyłem
/app/src
folder do mojego lokalnegosrc
.Tak więc folder kontenera wygląda mniej więcej tak:
Jest brzydka , ale działa ..
źródło
Ze względu na sposób, w jaki Node.js ładuje moduły ,
node_modules
może znajdować się w dowolnym miejscu ścieżki do kodu źródłowego. Na przykład umieść swoje źródło w/worker/src
swoim , a więcpackage.json
w/worker
,/worker/node_modules
gdzie są zainstalowane.źródło
Instalowanie node_modules w kontenerze innym niż folder projektu i ustawienie NODE_PATH na folder node_modules pomaga mi (musisz odbudować kontener).
Używam komponowania dokera. Struktura mojego projektu:
docker-compose.yml:
Plik Docker w folderze nodejs:
źródło
NODE_PATH
był dla mnie kluczem.CMD npm start
nie używa podanej NODE_PATH.Istnieje również proste rozwiązanie bez mapowania
node_module
katalogu na inny wolumin. Ma zamiar przenieść instalowanie pakietów npm do ostatecznego polecenia CMD.pracownik / plik Docker
docker-compose.yml
źródło
Są dwa oddzielne wymagania, które widzę dla środowisk deweloperskich węzłów ... podłącz kod źródłowy do kontenera i podłącz moduły node_z kontenera (dla twojego IDE). Aby wykonać pierwszy, wykonujesz zwykły montaż, ale nie wszystko ... tylko to, czego potrzebujesz
(powód, aby tego nie robić
- /worker/node_modules
jest to, że docker-compose zachowa ten wolumin między uruchomieniami, co oznacza, że możesz odbiegać od tego, co jest faktycznie na obrazie (pokonując cel nie tylko wiązania montażu z hosta)).Drugi jest w rzeczywistości trudniejszy. Moje rozwiązanie jest trochę hackerskie, ale działa. Mam skrypt do zainstalowania folderu node_modules na moim komputerze-hoście i muszę tylko pamiętać, aby wywoływać go za każdym razem, gdy aktualizuję pakiet.json (lub dodaj go do make make, który uruchamia kompilację dokerów lokalnie).
źródło
Moim zdaniem nie powinniśmy
RUN npm install
znajdować się w Dockerfile. Zamiast tego możemy uruchomić kontener za pomocą bash, aby zainstalować zależności przed uruchomieniem formalnej usługi węzłaźródło
node_modules
być wytrwały nawet po wyjęciu pojemnika, powinieneś również wiedzieć, kiedy lub kiedy nie robić tegonpm install
ręcznie. OP sugeruje zrobienie tego na każdej kompilacji obrazu . Możesz to zrobić, ale nie musisz do tego używać woluminu. W każdej wersji moduły będą zawsze aktualne.Możesz spróbować czegoś takiego w swoim pliku Docker:
Następnie powinieneś użyć woluminu w następujący sposób:
Skrypt startowy powinien być częścią repozytorium pracownika i wygląda następująco:
Moduły node_modu są częścią woluminu roboczego i są synchronizowane, a skrypty npm są wykonywane, gdy wszystko działa.
źródło
Możesz również porzucić swój plik Docker, ze względu na jego prostotę, wystarczy użyć podstawowego obrazu i podać polecenie w pliku tworzenia:
Jest to szczególnie przydatne dla mnie, ponieważ potrzebuję tylko środowiska obrazu, ale działam na moich plikach poza kontenerem i myślę, że to też chcesz zrobić.
źródło