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
フォルダーをホストと同期することは可能ですか?
私はすでにこれらの答えを読みました:
残念ながら、彼らは私をあまり助けませんでした。 最初のもの は好きではありません。クロスプラットフォームの問題が発生する可能性があるため、ホストでnpm install
を実行したくないためです(たとえば、ホストはWindowsまたはMacで、 DockerコンテナはDebian 8またはUbuntu 16.04です)。 2番目の は、Dockerコンテナの起動後に実行するのではなく、Dockerfile
でnpm install
を実行したいので、私にとっても良くありません。
また、私は このブログ投稿 を見つけました。著者は、私が直面しているのと同じ問題を解決しようとします。問題は、node_modules
はDockerコンテナからホストにコピーするだけなので、同期されないことです。
Dockerコンテナ内のnode_modules
をホストと同期したいのですが。私が望むことを考慮してください:
node_modules
を手動ではなく自動的にインストールするnode_modules
をインストールするnode_modules
をホストと同期させる(Dockerコンテナー内に新しいパッケージをインストールする場合、手動アクションなしで自動的にホストと同期する必要があります)ホストにnode_modules
が必要です。理由は次のとおりです。
devDependencies
やeslint
などのprettier
にアクセスできるように、node_modules
をローカルにインストールする必要があります。これらのdevDependencies
をグローバルにインストールしたくありません。前もって感謝します。
最初に、回答を投稿してくださった 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_modules
をDockerfile
で定義されているnode_module
のキャッシュディレクトリ(/usr/src/cache
)にインストールすることです。その後、entrypoint.sh
はnode_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
が必要です)。
ご質問がある場合は、コメントでお知らせください。
お役に立てれば。
ここでは3つのことが行われています。
docker build
またはdocker-compose build
を実行すると、Dockerfileは/usr/src/app/node_modules
ディレクトリとNodeインストールを含む新しいイメージを作成しますが、それ以外は何も作成しません。特に、アプリケーションはビルドされたイメージにはありません。docker-compose up
を指定すると、volumes: ['./app/frontend:/usr/src/app']
ディレクティブは/usr/src/app
にあるものをすべて隠し、その上にホストシステムのコンテンツをマウントします。volumes: ['frontend-node-modules:/usr/src/app/node_modules']
ディレクティブは、名前付きボリュームをnode_modules
ツリーの上にマウントし、対応するホストシステムディレクトリを非表示にします。別のコンテナを起動して名前付きボリュームをアタッチすると、そこにnode_modules
ツリーが表示されるはずです。あなたが説明しているのは、名前付きボリュームだけではないということです。volumes:
ブロックから2行目を削除し、volumes:
ファイルの最後にあるdocker-compose.yml
セクションを削除します。
私はこれが解決されたことを知っていますが、どうですか:
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はボリュームに存在しますが、そのコンテンツはコンテナ内で生成されるため、クロスプラットフォームの問題は発生しません。
ボリュームを重複させることはお勧めしませんが、公式のドキュメントでは禁止されていませんが、過去にいくつかの問題がありました。私のやり方は:
上記は、構成ファイルを少し短くすることで実現できます。
frontend:
build: ./app/frontend
volumes:
- ./app/frontend:/usr/src/app
ports:
- 3000:3000
environment:
NODE_ENV: ${ENV}
command: npm start
つまり、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で指定されたコマンドはアプリケーションを起動します。
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つのポイントをすべて達成でき、ファイルを移動する必要がなく、はるかにクリーンな方法です。
感謝します 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バージョンが含まれます。
ホストnode_modulesフォルダーをコンテナーnode_modulesにバインドすることは、おっしゃるように良い習慣ではありません。このフォルダーの内部ボリュームを作成するソリューションは、かなり頻繁に見ました。そうしないと、構築段階で問題が発生します。
angularアプリのdocker開発環境を構築しようとしたときにこの問題に遭遇しました。ホストフォルダー内のファイルを編集しているときにtslibエラーが表示され、ホストのnode_modulesフォルダーが空でした(予想どおり) )。
この場合、私に役立つ安価な解決策は、 "Remote-Containers"というVisual Studio Code Extensionを使用することでした。
この拡張により、Visual Studio Codeをコンテナに添付し、コンテナフォルダ内のファイルを透過的に編集できます。これを行うには、開発コンテナー内に内部vscodeサーバーをインストールします。詳細については、 このリンク を確認してください。
ただし、ボリュームがまだdocker-compose.ymlファイルに作成されていることを確認してください。
:D!