web-dev-qa-db-ja.com

Dockerコンテナー内にnode_modulesをインストールし、それらをホストと同期します

node_modulesをDockerコンテナー内にインストールし、それらをホストと同期することに問題があります。私のDockerのバージョンは18.03.1-ce, build 9ee9f40であり、Docker Composeのバージョンは1.21.2, build a133471です。

私のdocker-compose.ymlは次のようになります。

# Frontend Container.
frontend:
  build: ./app/frontend
  volumes:
    - ./app/frontend:/usr/src/app
    - frontend-node-modules:/usr/src/app/node_modules
  ports:
    - 3000:3000
  environment:
    NODE_ENV: ${ENV}
  command: npm start

# Define all the external volumes.
volumes:
  frontend-node-modules: ~

私のDockerfile

# Set the base image.
FROM node:10

# Create and define the working directory.
RUN mkdir /usr/src/app
WORKDIR /usr/src/app

# Install the application's dependencies.
COPY package.json ./
COPY package-lock.json ./
RUN npm install

外部ボリュームを使用したトリックは、多くのブログ投稿とStack Overflowの回答で説明されています。たとえば、 this one

アプリケーションは素晴らしい作品です。ソースコードが同期されます。ホットリロードも素晴らしいです。

私が抱えている唯一の問題は、ホストのnode_modulesフォルダーが空であることです。 Dockerコンテナー内にあるnode_modulesフォルダーをホストと同期することは可能ですか?

私はすでにこれらの答えを読みました:

  1. node_modules上のdocker-composeボリュームですが、空です
  2. Docker内のnpmインストール後のnode_modulesへのアクセス

残念ながら、彼らは私をあまり助けませんでした。 最初のもの は好きではありません。クロスプラットフォームの問題が発生する可能性があるため、ホストでnpm installを実行したくないためです(たとえば、ホストはWindowsまたはMacで、 DockerコンテナはDebian 8またはUbuntu 16.04です)。 2番目の は、Dockerコンテナの起動後に実行するのではなく、Dockerfilenpm installを実行したいので、私にとっても良くありません。

また、私は このブログ投稿 を見つけました。著者は、私が直面しているのと同じ問題を解決しようとします。問題は、node_modulesはDockerコンテナからホストにコピーするだけなので、同期されないことです。

Dockerコンテナ内のnode_modulesをホストと同期したいのですが。私が望むことを考慮してください:

  • node_modulesを手動ではなく自動的にインストールする
  • ホストではなくDockerコンテナ内にnode_modulesをインストールする
  • node_modulesをホストと同期させる(Dockerコンテナー内に新しいパッケージをインストールする場合、手動アクションなしで自動的にホストと同期する必要があります)

ホストにnode_modulesが必要です。理由は次のとおりです。

  • 必要なときにソースコードを読む可能性
  • IDEは、devDependencieseslintなどのprettierにアクセスできるように、node_modulesをローカルにインストールする必要があります。これらのdevDependenciesをグローバルにインストールしたくありません。

前もって感謝します。

27
Vladyslav Turak

最初に、回答を投稿してくださった David Maze および trust512 に感謝します。残念ながら、彼らは私の問題を解決する助けにはなりませんでした。

この質問に対する回答を投稿したいと思います。

私のdocker-compose.yml

---
# Define Docker Compose version.
version: "3"

# Define all the containers.
services:
  # Frontend Container.
  frontend:
    build: ./app/frontend
    volumes:
      - ./app/frontend:/usr/src/app
    ports:
     - 3000:3000
    environment:
      NODE_ENV: development
    command: /usr/src/app/entrypoint.sh

私のDockerfile

# Set the base image.
FROM node:10

# Create and define the node_modules's cache directory.
RUN mkdir /usr/src/cache
WORKDIR /usr/src/cache

# Install the application's dependencies into the node_modules's cache directory.
COPY package.json ./
COPY package-lock.json ./
RUN npm install

# Create and define the application's working directory.
RUN mkdir /usr/src/app
WORKDIR /usr/src/app

最後になりましたが、entrypoint.sh

#!/bin/bash

cp -r /usr/src/cache/node_modules/. /usr/src/app/node_modules/
exec npm start

ここで最も難しいのは、node_modulesDockerfileで定義されているnode_moduleのキャッシュディレクトリ(/usr/src/cache)にインストールすることです。その後、entrypoint.shnode_modulesをキャッシュディレクトリ(/usr/src/cache)からアプリケーションディレクトリ(/usr/src/app)に移動します。これにより、ホストマシンにnode_modulesディレクトリ全体が表示されます。

上記の私の質問を見て、私は欲しかった:

  • node_modulesを手動ではなく自動的にインストールする
  • ホストではなくDockerコンテナ内にnode_modulesをインストールする
  • node_modulesをホストと同期させる(Dockerコンテナー内に新しいパッケージをインストールする場合、手動アクションなしでホストと自動的に同期する必要があります)

最初に、node_modulesが自動的にインストールされます。 2番目のことも行われます:node_modulesはDockerコンテナー内にインストールされます(したがって、クロスプラットフォームの問題はありません)。そして、3番目のことも行われます:Dockerコンテナー内にインストールされたnode_modulesは、ホストマシン上でvisibleになり、synchronized! Dockerコンテナ内に新しいパッケージをインストールすると、すぐにホストマシンと同期されます。

重要なことに注意してください。本当に言えば、Dockerコンテナ内にインストールされた新しいパッケージは/usr/src/app/node_modulesに表示されます。このディレクトリはホストマシンと同期されるため、この新しいパッケージはホストマシンのnode_modulesディレクトリにも表示されます。ただし、/usr/src/cache/node_modulesには、この時点で古いビルドがあります(この新しいパッケージはありません)。とにかく、それは私たちにとって問題ではありません。次のdocker-compose up --build--buildが必要)の間、Dockerはnode_modulesを再インストールし(package.jsonが変更されたため)、entrypoint.shファイルがそれらを移動します/usr/src/app/node_modules

もう1つ重要なことを考慮する必要があります。リモートリポジトリのコードをgit pullまたはDockerの実行中にgit checkout your-teammate-branchする場合、package.jsonファイルにいくつかの新しいパッケージが追加される場合があります。この場合、CTRL + CでDockerを停止し、docker-compose up --buildで再度Dockerを起動する必要があります(--buildが必要です)。コンテナがデーモンとして実行されている場合は、docker-compose stopを実行してコンテナを停止し、docker-compose up --buildで再度起動する必要があります(--buildが必要です)。

ご質問がある場合は、コメントでお知らせください。

お役に立てれば。

24
Vladyslav Turak

ここでは3つのことが行われています。

  1. docker buildまたはdocker-compose buildを実行すると、Dockerfileは/usr/src/app/node_modulesディレクトリとNodeインストールを含む新しいイメージを作成しますが、それ以外は何も作成しません。特に、アプリケーションはビルドされたイメージにはありません。
  2. docker-compose upを指定すると、volumes: ['./app/frontend:/usr/src/app']ディレクティブは/usr/src/appにあるものをすべて隠し、その上にホストシステムのコンテンツをマウントします。
  3. 次に、volumes: ['frontend-node-modules:/usr/src/app/node_modules']ディレクティブは、名前付きボリュームをnode_modulesツリーの上にマウントし、対応するホストシステムディレクトリを非表示にします。

別のコンテナを起動して名前付きボリュームをアタッチすると、そこにnode_modulesツリーが表示されるはずです。あなたが説明しているのは、名前付きボリュームだけではないということです。volumes:ブロックから2行目を削除し、volumes:ファイルの最後にあるdocker-compose.ymlセクションを削除します。

5
David Maze

私はこれが解決されたことを知っていますが、どうですか:

Dockerfile:

FROM node

# Create app directory
WORKDIR /usr/src/app

# Your other staffs

EXPOSE 3000

docker-composer.yml:

version: '3.2'
services:
    api:
        build: ./path/to/folder/with/a/dockerfile
        volumes:
            - "./volumes/app:/usr/src/app"
        command: "npm start"

volume/app/package.json

{
    ... ,
    "scripts": {
        "start": "npm install && node server.js"
    },
    "dependencies": {
        ....
    }
 }

実行後、node_modulesはボリュームに存在しますが、そのコンテンツはコンテナ内で生成されるため、クロスプラットフォームの問題は発生しません。

2
Ignacio

ボリュームを重複させることはお勧めしませんが、公式のドキュメントでは禁止されていませんが、過去にいくつかの問題がありました。私のやり方は:

  1. 実際に使用することを意図していないので、外部ボリュームを取り除きます-停止してから削除した後、コンテナで具体的に作成されたデータでコンテナを再スポーンします。

上記は、構成ファイルを少し短くすることで実現できます。

frontend:
  build: ./app/frontend
  volumes:
    - ./app/frontend:/usr/src/app
  ports:
    - 3000:3000
  environment:
    NODE_ENV: ${ENV}
  command: npm start
  1. 不要な場合は、Dockerfile命令でボリュームデータを重複させないでください。

つまり、2つのDockerfileが必要になる可能性があります。1つはローカル開発用、もう1つはすべてのアプリケーションdistファイルが内部に階層化されたファットイメージをデプロイするためです。

とはいえ、開発用のDockerfileを検討してください。

FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN npm install

上記により、アプリケーションは完全なnode_modulesインストールを作成し、ホストの場所にマッピングしますが、docker-composeで指定されたコマンドはアプリケーションを起動します。

2
trust512

Dockerのentrypoint機能を実際に使用したソリューションについては、誰も言及していません。

私の作業ソリューションは次のとおりです。

Dockerfile(マルチステージビルドなので、本番環境とローカル開発環境の両方に対応しています):

FROM node:10.15.3 as production
WORKDIR /app

COPY package*.json ./
RUN npm install && npm install --only=dev

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]


FROM production as dev

COPY docker/dev-entrypoint.sh /usr/local/bin/

ENTRYPOINT ["dev-entrypoint.sh"]
CMD ["npm", "run", "watch"]

docker/dev-entrypoint.sh:

#!/bin/sh
set -e

npm install && npm install --only=dev ## Note this line, rest is copy+paste from original entrypoint

if [ "${1#-}" != "${1}" ] || [ -z "$(command -v "${1}")" ]; then
  set -- node "$@"
fi

exec "$@"

docker-compose.yml:

version: "3.7"

services:
    web:
        build:
            target: dev
            context: .
        volumes:
            - .:/app:delegated
        ports:
            - "3000:3000"
        restart: always
        environment:
            NODE_ENV: dev

このアプローチを使用すると、必要な3つのポイントをすべて達成でき、ファイルを移動する必要がなく、はるかにクリーンな方法です。

2
Jan Mikeš

感謝します Vladyslav Turakentrypoint.shでの回答に対して、コンテナからホストにnode_modulesをコピーします。

同様のことを実装しましたが、ハスキー、@ commitlint、tslint npmパッケージの問題に遭遇しました。
リポジトリに何もプッシュできません。
理由:LinuxからWindowsにnode_modulesをコピーしました。私の場合、ファイルの5%未満が異なり(.binとpackage.jsonのほとんど)、95%は同じです。 例:差分のある画像

そこで、最初にnpm install of node_modules for Windowsでソリューションに戻りました(IDEおよびデバッグ用)。そして、Dockerイメージにはnode_modulesのLinuxバージョンが含まれます。

1
user5367575

ホストnode_modulesフォルダーをコンテナーnode_modulesにバインドすることは、おっしゃるように良い習慣ではありません。このフォルダーの内部ボリュームを作成するソリューションは、かなり頻繁に見ました。そうしないと、構築段階で問題が発生します。

angularアプリのdocker開発環境を構築しようとしたときにこの問題に遭遇しました。ホストフォルダー内のファイルを編集しているときにtslibエラーが表示され、ホストのnode_modulesフォルダーが空でした(予想どおり) )。

この場合、私に役立つ安価な解決策は、 "Remote-Containers"というVisual Studio Code Extensionを使用することでした。

この拡張により、Visual Studio Codeをコンテナに添付し、コンテナフォルダ内のファイルを透過的に編集できます。これを行うには、開発コンテナー内に内部vscodeサーバーをインストールします。詳細については、 このリンク を確認してください。

ただし、ボリュームがまだdocker-compose.ymlファイルに作成されていることを確認してください。

:D!

0
Chris Deligan