Docker-compose: npm kurulumu başarılı olduktan sonra bir birimde düğüm_modülleri mevcut değil


184

Aşağıdaki hizmetleri içeren bir uygulamam var:

  • web/ - 5000 numaralı bağlantı noktasında bir python 3 şişesi web sunucusu tutar ve çalıştırır. sqlite3 kullanır.
  • worker/- index.jskuyruk için çalışan bir dosyaya sahip. web sunucusu bu kuyrukla bağlantı noktası üzerinden bir json API kullanarak etkileşime girer 9730. Çalışan depolama için redis kullanır. Çalışan verileri yerel olarak klasörde depolarworker/images/

Şimdi bu soru sadece 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

Çalıştığımda docker-compose build, her şey beklediğim gibi çalışıyor ve tüm npm modülleri /worker/node_modulesbeklediğim gibi kuruldu .

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>

Ama bunu docker-compose upyaptığımda şu hatayı görüyorum:

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)

Modüllerin hiçbirinin içinde /worker/node_modules(ana bilgisayarda veya kapta) olmadığı ortaya çıkıyor.

Eğer ana bilgisayar, ben npm install, o zaman her şey gayet iyi çalışıyor. Ama bunu yapmak istemiyorum. Konteynerin bağımlılıkları ele almasını istiyorum.

Burada sorun ne?

(Söylemeye gerek yok, tüm paketler var package.json.)


Bir çözüm buldun mu?
Justin Stayton

Bence ONBUILD talimatını kullanmalısın ... Şunun gibi: github.com/nodejs/docker-node/blob/master/0.12/onbuild/…
Lucas Pottersky

1
IDE node_module bağımlılıklarını bilmiyorsa ana bilgisayarda nasıl geliştirme yaparsınız?
André

2
volumes: - worker/:/worker/Bloğu docker-compose.ymldosyadan kaldırmayı deneyin . Bu satır, COPY komutuyla yaptığınız klasörün üzerine yazar.
Stepan

When I run docker-compose build, everything works as expected and all npm modules are installed in /worker/node_modules as I'd expect.- Bunu nasıl kontrol ettin?
Vallie

Yanıtlar:


272

Bunun nedeni , derleme sırasında birim bağlanmadığı için workerdizininizi bir birim olarak eklemiş olmanızdır docker-compose.yml.

Docker görüntüyü node_modulesoluşturduğunda, workerdizin dizinde oluşturulur ve tüm bağımlılıklar orada yüklenir. Daha sonra çalışma zamanında workerdış docker dizini docker örneğine (yüklü olmayan node_modules) monte edilir ve node_modulesyeni yüklediğiniz gizlenir . Takılı birimi bilgisayarınızdan çıkararak bunu doğrulayabilirsiniz docker-compose.yml.

Geçici bir çözüm, node_modulesveri birimleri, workerdizin takılmadan önce yerleşik docker görüntüsündeki verilere kopyalandığından, bunları depolamak için bir veri birimi kullanmaktır . Bu şu şekilde yapılabilir docker-compose.yml:

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - ./worker/:/worker/
        - /worker/node_modules
    links:
        - redis

Bunun görüntünün taşınabilirliği için herhangi bir sorun oluşturup oluşturmadığını tam olarak bilmiyorum, ancak öncelikle bir çalışma zamanı ortamı sağlamak için öncelikle docker'ı kullandığınız gibi, bu bir sorun olmamalı.

Birimler hakkında daha fazla bilgi edinmek isterseniz, burada güzel bir kullanım kılavuzu bulunmaktadır: https://docs.docker.com/userguide/dockervolumes/

EDIT: Docker o zamandan beri ./docker-compose.yml dosyasına göre dosyalarda montaj için bir lider gerektirecek sözdizimini değiştirdi .


7
büyük cevap, en az müdahaleci ve büyük açıklama!
kkemple

41
Bu yöntemi denedim ve bağımlılıklar değiştiğinde duvara çarptım. Görüntüyü yeniden kurdum, yeni kapsayıcı başlattım ve hacim /worker/node_moduleseskisi gibi kaldı (eski bağımlılıklarla). Görüntüyü yeniden oluşturduktan sonra yeni birimin nasıl kullanılacağına dair bir hile var mı?
Ondrej Slinták

11
Docker compose, diğer kaplar bunları kullanıyorsa (ölü olsalar bile) birimleri kaldırmaz gibi görünüyor. Dolayısıyla, aynı türde bazı ölü kaplar varsa (hangi nedenle olursa olsun), önceki yorumda tarif ettiğim senaryo aşağıdaki gibidir. Denediğim kadarıyla, docker-compose rmbu sorunu çözmek gibi görünüyor, ancak daha iyi ve daha kolay bir çözüm olması gerektiğine inanıyorum.
Ondrej Slinták

15
2018'de rebuild --no-cacheher defasında değişiklik yapmak zorunda kalmadan bir çözüm var mı ?
Eelke

7
artık önceki kapsayıcılardan gelen veriler yerine anonim hacimleri yeniden oluşturacak olan "--renew-anon-volumes" ı kullanabilirsiniz .
Muhammed Essehemy

37

node_modulesKlasör hacmi ve konteynerde artık erişilebilir tarafından yazılır. Birimi klasörü çıkarmak için yerel modül yükleme stratejisini kullanıyorum :

/data/node_modules/ # dependencies installed here
/data/app/ # code base

Dockerfile:

COPY package.json /data/
WORKDIR /data/
RUN npm install
ENV PATH /data/node_modules/.bin:$PATH

COPY . /data/app/
WORKDIR /data/app/

node_modulesO görüntüde dahil olduğu için dizin konteyner dışından erişilemez.


1
bu yaklaşımın bir dezavantajı var mı? Benim için iyi çalışıyor gibi görünüyor.
Bret Fisher

1
node_moduleskonteynerin dışından erişilemez, ancak gerçekten dezavantajlı değildir;)
jsan

ve package.json'u her değiştirdiğinizde, tüm kapsayıcıyı --no-cache ile yeniden oluşturmanız gerekir değil mi?
Luke

Package.json öğesini değiştirdiğinizde görüntüyü yeniden oluşturmanız gerekir, evet, ancak --no-cache gerekli değildir. Çalıştırırsanız docker-compose run app npm install, geçerli dizinde bir node_modules oluşturacaksınız ve artık görüntüyü yeniden oluşturmanıza gerek yok.
jsan

9
Dezavantajı: IDE otomatik tamamlama, yardım yok, iyi bir dev deneyimi yok. Her şeyin şimdi ana bilgisayara yüklenmesi gerekiyor, ancak geliştiricinin bir projeyle çalışabilmesi için hiçbir şeye ihtiyaç duymaması için burada docker kullanmanın nedeni değil mi?
Michael

31

@FrederikNS tarafından sağlanan çözüm çalışıyor, ancak açıkça node_modules birimimi adlandırmayı tercih ediyorum.

Benim project/docker-compose.ymldosyası (liman işçisi-oluşturma sürüm 1.6+):

version: '2'
services:
  frontend:
    ....
    build: ./worker
    volumes:
      - ./worker:/worker
      - node_modules:/worker/node_modules
    ....
volumes:
  node_modules:

benim dosya yapısı:

project/
   │── worker/
        └─ Dockerfile
   └── docker-compose.yml

Uygulamamı project_node_modulesher açtığımda adlı bir birim oluşturur ve yeniden kullanır.

Benim docker volume lsşöyle görünüyor:

DRIVER              VOLUME NAME
local               project1_mysql
local               project1_node_modules
local               project2_postgresql
local               project2_node_modules

3
bu "işe yarar" iken, liman işçisinde gerçek bir konsepti atlatıyorsunuz: tüm bağımlılıklar maksimum taşınabilirlik için pişirilmelidir. bu darbeyi başka komutlar çalıştırmadan hareket ettiremezsiniz
Javier Buzzi

4
saatlerce aynı sorunu çözmeye çalıştım ve aynı çözümü kendim buldum. Cevabınız en yüksek puan almalıdır, ama sanırım, ppl cevabınızı alamıyorsunuz çünkü cildinize "node_modules" adını verdiniz ve tüm okuyucular bunun yeni bir hacim yarattığı gerçeğini kaçırıyor. Kodunuzu okurken ben sadece yerel "node_modules" klasörü yeniden monte ve bu fikri attı düşündüm. Belki bunu netleştirmek için birim adını "container_node_modules" gibi bir şeyle düzenlemeniz gerekir. :)
Fabian

1
Ben de bu kolayca çeşitli yap aşamadan harika makale genelinde düğüm modülleri için aynı birime atıfta sağlar en zarif çözüm, olduğu tespit Docker içinde Bina Düğüm Apps'ten Dersler da aynı yaklaşımı kullanır.
kf06925

1
@ kf06925 adam beni gerçekten kurtardın, bunu çözmeye çalışırken saatler geçirdim ve yapabileceğim yazı sayesinde !! Çok teşekkür
etsem

21

Son zamanlarda benzer bir sorun yaşadım. node_modulesBaşka bir yere kurabilir ve NODE_PATHortam değişkenini ayarlayabilirsiniz .

Örnekte ben yüklü aşağıda node_modulesiçine/install

işçi / Dockerfile

FROM node:0.12

RUN ["mkdir", "/install"]

ADD ["./package.json", "/install"]
WORKDIR /install
RUN npm install --verbose
ENV NODE_PATH=/install/node_modules

WORKDIR /worker

COPY . /worker/

liman işçisi-compose.yml

redis:
    image: redis
worker:
    build: ./worker
    command: npm start
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis

6
@FrederikNS tarafından en çok oylanan çözüm faydalıdır, bu makaleyenode_modules dayanarak kabın üzerine yazarak yerel birimin farklı bir sorununu nasıl çözdüm . Ama bu sorunu yaşamaya yönlendirdi . Bu çözüm burada kopyalamak için ayrı bir dizin oluşturma , orada çalıştırın , sonra ortam değişkenini belirtmek için o dizinin klasörüne işaret eder ve doğru hissediyor. package.jsonnpm installNODE_PATHdocker-compose.ymlnode_modules
cwnewhouse

ENV NODE_PATH = / install / node_modules'i Dockerfile'a dahil etmek, saatlerce farklı yaklaşımları denedikten sonra benim için çözüm oldu. Teşekkürler bayım.
Benny Meade

npm installAna bilgisayarda çalışırsanız ne olur ? node_modulesAna bilgisayarda görünecek ve önceliğe sahip olarak kaba yansıtılacak gibi görünüyor NODE_PATH. Böylece konteyner ana bilgisayardan node_modules kullanacaktır.
vitalets

19

Zarif bir çözüm var:

Sadece tüm dizini değil, sadece uygulama dizinini bağlayın. Bu şekilde sıkıntı yaşamayacaksınız npm_modules.

Misal:

  frontend:
    build:
      context: ./ui_frontend
      dockerfile: Dockerfile.dev
    ports:
    - 3000:3000
    volumes:
    - ./ui_frontend/src:/frontend/src

Dockerfile.dev:

FROM node:7.2.0

#Show colors in docker terminal
ENV COMPOSE_HTTP_TIMEOUT=50000
ENV TERM="xterm-256color"

COPY . /frontend
WORKDIR /frontend
RUN npm install update
RUN npm install --global typescript
RUN npm install --global webpack
RUN npm install --global webpack-dev-server
RUN npm install --global karma protractor
RUN npm install
CMD npm run server:dev

Parlak. Neden kabul edilen cevap olmadığını anlayamıyorum.
Jivan

2
Bu iyi ve hızlı bir çözümdür, ancak yeni bağımlılık kurulumundan sonra yeniden oluşturma ve kuru erik gerektirir.
Kunok

Şimdi farklı şekilde yapıyorum, özellikle node_modules için bir birim ve ana bilgisayardan monte ettiğiniz bir birim olmalıdır. O zaman hiç sorun yok
holms

14

GÜNCELLEME: @FrederikNS tarafından sağlanan çözümü kullanın .

Aynı sorunla karşılaştım. Klasör /workerkapsayıcıya bağlandığında - tüm içeriği senkronize edilir (bu nedenle yerel olarak sahip değilseniz node_modules klasörü kaybolur.)

İşletim sistemine dayalı uyumsuz npm paketleri nedeniyle, sadece modülleri yerel olarak yükleyemedim, ardından kapsayıcıyı başlatamadım.

Benim çözümüm, kaynağı bir srcklasöre sarmak ve sonra bu index.js dosyasınınode_modules kullanarak o klasöre bağlanmaktı . Yani, dosya şimdi benim uygulamanın başlangıç noktasıdır.index.js

Kapsayıcıyı çalıştırdığımda, /app/srcklasörü yerel srcklasöre bağladım.

Kapsayıcı klasörü şöyle görünür:

/app
  /node_modules
  /src
    /node_modules -> ../node_modules
    /app.js
  /index.js

Öyle çirkin , ama çalışıyor ..


3
Ah, sevgili lord ... buna da takılı kaldığımı düşünemiyorum!
Lucas Pottersky

10

Nedeniyle way node.js yükler modüllerin , node_moduleskaynak koduna yolunda herhangi bir yerde olabilir. Örneğin, adresinde kaynağı yerleştirin /worker/srcve package.jsonin /workeryüzden, /worker/node_modulesonlar yüklü nereye olduğunu.


7

Kapsayıcıya node_modules'ü proje klasöründen farklı olarak yüklemek ve NODE_PATH değerini node_modules klasörünüze ayarlamak bana yardımcı olur (kapsayıcıyı yeniden oluşturmanız gerekir).

Docker-compose kullanıyorum. Proje dosya yapım:

-/myproject
--docker-compose.yml
--nodejs/
----Dockerfile

liman işçisi-compose.yml:

version: '2'
services:
  nodejs:
    image: myproject/nodejs
    build: ./nodejs/.
    volumes:
      - ./nodejs:/workdir
    ports:
      - "23005:3000"
    command: npm run server

Düğümler klasöründeki Dockerfile:

FROM node:argon
RUN mkdir /workdir
COPY ./package.json /workdir/.
RUN mkdir /data
RUN ln -s /workdir/package.json /data/.
WORKDIR /data
RUN npm install
ENV NODE_PATH /data/node_modules/
WORKDIR /workdir

1
Bulduğum en iyi çözüm bu. NODE_PATHbenim için anahtardı.
cdignam

Bunun mantıklı olduğunu düşünüyorum ama NODE_PATH ayarlayarak, görüntüyü çalıştırırken CMD npm start belirtilen NODE_PATH kullanmıyor.
Acton

6

node_moduleDizini başka bir birime eşlemeden bazı basit çözümler de vardır . Npm paketlerinin kurulumunu nihai CMD komutuna taşımak üzeredir.

Bu yaklaşımın dezavantajı:

  • çalıştırmak npm install(den geçiş sen konteyner her çalıştırdığınızda npmiçin yarnde bu süreci biraz hızlandırmak kudretini).

işçi / Dockerfile

FROM node:0.12
WORKDIR /worker
COPY package.json /worker/
COPY . /worker/
CMD /bin/bash -c 'npm install; npm start'

liman işçisi-compose.yml

redis:
    image: redis
worker:
    build: ./worker
    ports:
        - "9730:9730"
    volumes:
        - worker/:/worker/
    links:
        - redis

3

Düğüm geliştirme ortamları için gördüğüm iki ayrı gereksinim var ... kaynak kodunuzu konteynere monte edin ve düğümü modülden kabın (IDE'niz için) monte edin. İlkini başarmak için her zamanki montajı yaparsınız, sadece ihtiyacınız olan şeyleri değil

volumes:
    - worker/src:/worker/src
    - worker/package.json:/worker/package.json
    - etc...

( - /worker/node_modulesyapmamanın nedeni, docker-compose'un çalıştırmalar arasındaki hacmi devam ettirmesi, yani görüntüde gerçekte olandan uzaklaşabilmenizdir (sadece ana makinenizden montajı bağlama amacını ortadan kaldırmaktır).

İkincisi aslında daha zor. Benim çözümüm biraz acayip, ama işe yarıyor. Ana makineme node_modules klasörünü yüklemek için bir komut dosyası var ve sadece package.json'u güncellediğimde çağırmayı hatırlamalıyım (ya da docker-compose derlemesini yerel olarak çalıştıran hedefine ekleyin).

install_node_modules:
    docker build -t building .
    docker run -v `pwd`/node_modules:/app/node_modules building npm install

2

Bence RUN npm installDockerfile'da olmamalıyız. Bunun yerine, resmi düğüm hizmetini çalıştırmadan önce bağımlılıkları yüklemek için bash kullanarak bir kap başlatabiliriz

docker run -it -v ./app:/usr/src/app  your_node_image_name  /bin/bash
root@247543a930d6:/usr/src/app# npm install

Aslında bu konuda sana katılıyorum. Birimler, verileri kapsayıcı ve ana bilgisayar arasında paylaşmak istediğinizde kullanılmalıdır. node_modulesKonteyner kaldırıldıktan sonra bile kalıcı olmaya karar verdiğinizde, npm installmanuel olarak ne zaman veya ne zaman yapılmayacağını da bilmelisiniz . OP bunu her görüntü derlemesinde yapmayı önerir . Bunu yapabilirsiniz, ancak bunun için bir birim kullanmanıza gerek yoktur. Her yapıda, modüller her zaman güncel olacaktır.
phil294

@Buuhirn örneğin gulp seyretme (veya benzer komutlar) yaparken yerel bir ana bilgisayar hacmini konteynere monte etmek yararlı olur - diğer kaynaklarda (js, css vb.) Değişikliklere izin verirken node_modules'ün devam etmesini istersiniz. npm yerel bir yudum kullanmakta ısrar ediyor, bu yüzden devam etmeli (veya başlangıçta diğer yöntemlerle kurulmalıdır)
tbm

2

Dockerfile dosyasında böyle bir şey deneyebilirsiniz:

FROM node:0.12
WORKDIR /worker
CMD bash ./start.sh

O zaman Hacmi şu şekilde kullanmalısınız:

volumes:
  - worker/:/worker:rw

Başlangıç ​​metni, çalışan deponuzun bir parçası olmalı ve şöyle görünmelidir:

#!/bin/sh
npm install
npm start

Bu nedenle node_modules, çalışan hacminizin bir parçasıdır ve senkronize edilir ve her şey bittiğinde npm komut dosyaları yürütülür.


Bu, kabın başlatılması için büyük bir ek yük sağlayacaktır.
tbm

2
Ancak sadece ilk kez, çünkü node_modules yerel makinede kalıcı olacaktır.
Parav01d

Veya görüntü yeniden oluşturuluncaya veya cilt kaldırılana kadar :). Bununla birlikte, kendim için daha iyi bir çözüm bulamadım.
tbm

0

Ayrıca, Dockerfile'ınızı basitleştirmesi nedeniyle basit bir görüntü kullanın ve oluşturma dosyanızdaki komutu belirtin:

version: '3.2'

services:
  frontend:
    image: node:12-alpine
    volumes:
      - ./frontend/:/app/
    command: sh -c "cd /app/ && yarn && yarn run start"
    expose: [8080]
    ports:
      - 8080:4200

Bu benim için özellikle yararlı, çünkü sadece görüntünün ortamına ihtiyacım var, ancak konteyner dışındaki dosyalarımda çalışıyorum ve bence bu da yapmak istediğiniz şey.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.