在 Docker 容器中安装 node_modules 并将它们与主机同步
Install node_modules inside Docker container and synchronize them with host
我在 Docker 容器中安装 node_modules
并将它们与主机同步时遇到问题。我的 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
文件夹与主机同步?
我已经阅读了这些答案:
不幸的是,他们对我帮助不大。我不喜欢 , because I don't want to run npm install
on my host because of the possible cross-platform issues (e.g. the host is Windows or Mac and the Docker container is Debian 8 or Ubuntu 16.04). 对我也不好,因为我想 运行 npm install
在我的 Dockerfile
而不是 运行 之后Docker 容器已启动。
另外,我发现了 this blog post。作者试图解决我面临的同样问题。问题是 node_modules
不会同步,因为我们只是将它们从 Docker 容器复制到主机。
我希望 Docker 容器内的 node_modules
与主机同步。请考虑我想要的:
- 自动安装
node_modules
而不是手动安装
- 在 Docker 容器而不是主机中安装
node_modules
- 让
node_modules
与主机同步(如果我在Docker容器中安装一些新包,它应该自动与主机同步,无需任何手动操作)
我需要在主机上安装 node_modules
,因为:
- 可以在需要时阅读源代码
- IDE 需要在本地安装
node_modules
以便它可以访问 devDependencies
,例如 eslint
或 prettier
。我不想全局安装这些 devDependencies
。
提前致谢。
这里发生了三件事:
- 当您 运行
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:
块中的第二行和 docker-compose.yml
文件末尾的 volumes:
部分。
我不建议重叠卷,虽然我没有看到任何官方文档禁止它,但我过去遇到过一些问题。我是怎么做的:
- 摆脱外部卷,因为您不打算实际使用它,它应该如何使用 - 在停止+删除它后,使用专门在容器中创建的数据重新生成容器。
以上内容可以通过稍微缩短您的撰写文件来实现:
frontend:
build: ./app/frontend
volumes:
- ./app/frontend:/usr/src/app
ports:
- 3000:3000
environment:
NODE_ENV: ${ENV}
command: npm start
- 避免在不必要时将卷数据与 Dockerfile 指令重叠。
这意味着您可能需要两个 Dockerfiles - 一个用于本地开发,一个用于部署包含所有应用程序 dist 文件的胖映像。
也就是说,考虑开发 Dockerfile:
FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN npm install
以上内容使应用程序创建一个完整的 node_modules 安装并将其映射到您的主机位置,而 docker-compose 指定的命令将启动您的应用程序。
首先,我要感谢David Maze and trust512 post他们的回答。不幸的是,他们没有帮助我解决我的问题。
我想post回答这个问题。
我的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
目录将出现在我们的主机上。
看我上面的问题我想:
- to install
node_modules
automatically instead of manually
- to install
node_modules
inside the Docker container instead of the host
- to have
node_modules
synchronized with the host (if I install some new package inside the Docker container, it should be
synchronized with the host automatically without any manual actions
第一件事是:node_modules
是自动安装的。第二件事也完成了:node_modules
安装在 Docker 容器内(因此,不会有跨平台问题)。第三件事也完成了:安装在 Docker 容器内的 node_modules
将在我们的主机上 visible 并且它们将是 同步!如果我们在 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
.
你应该考虑一件更重要的事情。如果您 git pull
来自远程存储库的代码或 git checkout your-teammate-branch
当 Docker 为 运行 时,可能会有一些新包添加到 package.json
文件中。在这种情况下,您应该使用 CTRL + C
停止 Docker 并使用 docker-compose up --build
再次启动它(需要 --build
)。如果您的容器是 运行 作为守护进程,您应该只执行 docker-compose stop
来停止容器并使用 docker-compose up --build
再次启动它(需要 --build
)。
如有任何疑问,请在评论中告诉我。
希望对您有所帮助。
感谢 Vladyslav Turak 回答 entrypoint.sh
我们将 node_modules
从容器复制到主机。
我实现了类似的东西,但我 运行 进入了 husky、@commitlint、tslint npm 包的问题。
我无法将任何内容推送到存储库。
原因:我从Linux复制了node_modules
到Windows。在我的例子中,<5% 的文件是不同的(.bin 和大多数 package.json),95% 是相同的。 example: image with diff
所以我首先返回解决方案 node_modules
的 npm install
用于 Windows(用于 IDE 和调试)。 Docker 图像将包含 Linux 版本的 node_modules
。
我知道这已经解决了,但是:
Docker 文件:
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"
volumes/app/package.json
{
... ,
"scripts": {
"start": "npm install && node server.js"
},
"dependencies": {
....
}
}
在 运行 之后,node_modules 将出现在您的卷中,但其内容是在容器内生成的,因此没有跨平台问题。
没有人提到实际使用 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#-}" != "" ] || [ -z "$(command -v "")" ]; 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 点,恕我直言,这是一种更简洁的方法 - 不需要四处移动文件。
将您的主机 node_modules 文件夹与您的容器 node_modules 绑定并不是您提到的好做法。我经常看到为此文件夹创建内部卷的解决方案。不这样做会在构建阶段引起问题。
我 运行 在尝试为 angular 应用程序构建 docker 开发环境时遇到了这个问题,当我在主机中编辑文件时显示 tslib 错误文件夹导致我的主机的 node_modules 文件夹是空的(如预期的那样)。
在这种情况下,对我有帮助的廉价解决方案是使用名为 "Remote-Containers".
的 Visual Studio 代码扩展
此扩展程序将允许您将 Visual Studio 代码 附加到您的容器,并在您的容器文件夹中编辑 运行 清晰的文件。为此,它将在您的开发容器中安装一个内部 vscode 服务器。有关更多信息,请查看 this link.
但是,请确保您的卷仍在 docker-compose.yml 文件中创建。
希望对您有所帮助:D!
运行 解决了这个问题,发现接受的答案很慢,无法将所有 node_modules
复制到每个容器 运行 中的主机,我设法通过安装依赖项解决了这个问题在容器中,镜像主机卷,如果存在 node_modules
文件夹,则跳过再次安装:
Docker 文件:
FROM node:12-alpine
WORKDIR /usr/src/app
CMD [ -d "node_modules" ] && npm run start || npm ci && npm run start
docker-compose.yml:
version: '3.8'
services:
service-1:
build: ./
volumes:
- ./:/usr/src/app
当您需要重新安装依赖项时,只需删除 node_modules
.
我不确定为什么你希望你的源代码存在于容器中 and host and bind mount other在开发过程中。通常,您希望您的源代码位于用于部署的容器内,而不是用于开发,因为代码在您的主机上可用并绑定安装。
你的docker-compose.yml
frontend:
volumes:
- ./app/frontend:/usr/src/app
你的Dockerfile
FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
当然你必须 运行 npm install
第一次和每次 package.json 改变,但是你 运行 它在容器里所以没有 cross-platform问题:docker-compose exec frontend npm install
终于启动你的服务器了docker-compose exec frontend npm start
然后,通常在针对部署的 CI 管道中,您构建最终映像并复制整个源代码并 node_modules 重新安装,但当然此时您不需要不再需要绑定安装和“同步”,因此您的设置可能如下所示:
docker-compose.yml
frontend:
build:
context: ./app/frontend
target: dev
volumes:
- ./app/frontend:/usr/src/app
Dockerfile
FROM node:10 as dev
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
FROM dev as build
COPY package.json package-lock.json ./
RUN npm install
COPY . ./
CMD ["npm", "start"]
稍后,您可以手动或在管道期间以 Dockerfile 的构建阶段为目标,以构建您的 deployment-ready 映像。
我知道这不是您问题的确切答案,因为您必须 运行 npm install 并且在开发过程中容器内没有任何东西,但它解决了您的 node_modules 问题,我觉得您的问题混合了开发和部署注意事项,所以您可能以错误的方式考虑了这个问题。
我的解决方法是在容器启动时而不是在 build-time 期间安装依赖项。
Docker 文件:
# We're using a multi-stage build so that we can install dependencies during build-time only for production.
# dev-stage
FROM node:14-alpine AS dev-stage
WORKDIR /usr/src/app
COPY package.json ./
COPY . .
# `yarn install` will run every time we start the container. We're using yarn because it's much faster than npm when there's nothing new to install
CMD ["sh", "-c", "yarn install && yarn run start"]
# production-stage
FROM node:14-alpine AS production-stage
WORKDIR /usr/src/app
COPY package.json ./
RUN yarn install
COPY . .
.dockerignore
将 node_modules
添加到 .dockerignore
以防止在 Dockerfile
运行 COPY . .
时复制它。我们使用卷来引入 node_modules
.
**/node_modules
docker-compose.yml
node_app:
container_name: node_app
build:
context: ./node_app
target: dev-stage # `production-stage` for production
volumes:
# For development:
# If node_modules already exists on the host, they will be copied
# into the container here. Since `yarn install` runs after the
# container starts, this volume won't override the node_modules.
- ./node_app:/usr/src/app
# For production:
#
- ./node_app:/usr/src/app
- /usr/src/app/node_modules
一个简单、完整的解决方案
您可以使用外部命名卷技巧 和 在容器中安装 node_modules 通过将卷的存储位置配置为指向主机的 将其与主机同步=54=]目录。这可以使用命名的 volume using the local driver and a bind mount 来完成,如下例所示。
该卷的数据无论如何都存储在您的主机上,类似于 /var/lib/docker/volumes/,因此我们只是将其存储在您的项目中。
要在 Docker Compose 中执行此操作,只需将 node_modules 卷添加到前端服务,然后在命名卷部分配置卷,其中“设备”是 相对路径(从docker-compose.yml的位置)到本地(主机)node_modules目录。
docker-compose.yml
version: '3.9'
services:
ui:
# Your service options...
volumes:
- node_modules:/path/to/node_modules
volumes:
node_modules:
driver: local
driver_opts:
type: none
o: bind
device: ./local/path/to/node_modules
此解决方案的关键是永远不要直接在主机中进行更改 node_modules,而是始终在容器中安装、更新或删除 Node 包。
版本控制提示:
当你的Node package.json/package-lock.json文件发生变化时,无论是拉取还是切换分支,除了重建Image之外,你还必须移除Volume,并删除其中的内容:
docker volume rm example_node_modules
rm -rf local/path/to/node_modules
mkdir local/path/to/node_modules
文档:
最适合发展
docker-compose.yml
...
frontend:
build: ./app/frontend
ports:
- 3000:3000
volumes:
- ./app/frontend:/usr/src/app
...
./app/frontend/Dockerfile
FROM node:lts
WORKDIR /usr/src/app
RUN npm install -g react-scripts
RUN chown -Rh node:node /usr/src/app
USER node
EXPOSE 3000
CMD [ "sh", "-c", "npm install && npm run start" ]
#FOR PROD
# CMD [ "sh", "-c", "npm install && npm run build" ]
用户node
将帮助您获得主人<->客人
的权利
文件夹 node_modules
将可从主机访问并同步主机<->来宾
您也可以使用 dockerized npm install
。这与 npm install
相同,但它在 docker 容器上运行。
node_modules 将写入主机。它应该开箱即用,您可以指定要使用的 npm 版本。如果需要,可以扩展或自定义容器。
请注意,某些 npm 包可能需要编译,并且生成的二进制文件可能与您的主机不兼容。如果您只需要源代码或 dist 文件,这不是问题。
免责声明:我是 Dockerized 的作者。
我在 Docker 容器中安装 node_modules
并将它们与主机同步时遇到问题。我的 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
on my host because of the possible cross-platform issues (e.g. the host is Windows or Mac and the Docker container is Debian 8 or Ubuntu 16.04). npm install
在我的 Dockerfile
而不是 运行 之后Docker 容器已启动。
另外,我发现了 this blog post。作者试图解决我面临的同样问题。问题是 node_modules
不会同步,因为我们只是将它们从 Docker 容器复制到主机。
我希望 Docker 容器内的 node_modules
与主机同步。请考虑我想要的:
- 自动安装
node_modules
而不是手动安装 - 在 Docker 容器而不是主机中安装
node_modules
- 让
node_modules
与主机同步(如果我在Docker容器中安装一些新包,它应该自动与主机同步,无需任何手动操作)
我需要在主机上安装 node_modules
,因为:
- 可以在需要时阅读源代码
- IDE 需要在本地安装
node_modules
以便它可以访问devDependencies
,例如eslint
或prettier
。我不想全局安装这些devDependencies
。
提前致谢。
这里发生了三件事:
- 当您 运行
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:
块中的第二行和 docker-compose.yml
文件末尾的 volumes:
部分。
我不建议重叠卷,虽然我没有看到任何官方文档禁止它,但我过去遇到过一些问题。我是怎么做的:
- 摆脱外部卷,因为您不打算实际使用它,它应该如何使用 - 在停止+删除它后,使用专门在容器中创建的数据重新生成容器。
以上内容可以通过稍微缩短您的撰写文件来实现:
frontend:
build: ./app/frontend
volumes:
- ./app/frontend:/usr/src/app
ports:
- 3000:3000
environment:
NODE_ENV: ${ENV}
command: npm start
- 避免在不必要时将卷数据与 Dockerfile 指令重叠。
这意味着您可能需要两个 Dockerfiles - 一个用于本地开发,一个用于部署包含所有应用程序 dist 文件的胖映像。
也就是说,考虑开发 Dockerfile:
FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN npm install
以上内容使应用程序创建一个完整的 node_modules 安装并将其映射到您的主机位置,而 docker-compose 指定的命令将启动您的应用程序。
首先,我要感谢David Maze and trust512 post他们的回答。不幸的是,他们没有帮助我解决我的问题。
我想post回答这个问题。
我的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
目录将出现在我们的主机上。
看我上面的问题我想:
- to install
node_modules
automatically instead of manually- to install
node_modules
inside the Docker container instead of the host- to have
node_modules
synchronized with the host (if I install some new package inside the Docker container, it should be synchronized with the host automatically without any manual actions
第一件事是:node_modules
是自动安装的。第二件事也完成了:node_modules
安装在 Docker 容器内(因此,不会有跨平台问题)。第三件事也完成了:安装在 Docker 容器内的 node_modules
将在我们的主机上 visible 并且它们将是 同步!如果我们在 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
.
你应该考虑一件更重要的事情。如果您 git pull
来自远程存储库的代码或 git checkout your-teammate-branch
当 Docker 为 运行 时,可能会有一些新包添加到 package.json
文件中。在这种情况下,您应该使用 CTRL + C
停止 Docker 并使用 docker-compose up --build
再次启动它(需要 --build
)。如果您的容器是 运行 作为守护进程,您应该只执行 docker-compose stop
来停止容器并使用 docker-compose up --build
再次启动它(需要 --build
)。
如有任何疑问,请在评论中告诉我。
希望对您有所帮助。
感谢 Vladyslav Turak 回答 entrypoint.sh
我们将 node_modules
从容器复制到主机。
我实现了类似的东西,但我 运行 进入了 husky、@commitlint、tslint npm 包的问题。
我无法将任何内容推送到存储库。
原因:我从Linux复制了node_modules
到Windows。在我的例子中,<5% 的文件是不同的(.bin 和大多数 package.json),95% 是相同的。 example: image with diff
所以我首先返回解决方案 node_modules
的 npm install
用于 Windows(用于 IDE 和调试)。 Docker 图像将包含 Linux 版本的 node_modules
。
我知道这已经解决了,但是:
Docker 文件:
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"
volumes/app/package.json
{
... ,
"scripts": {
"start": "npm install && node server.js"
},
"dependencies": {
....
}
}
在 运行 之后,node_modules 将出现在您的卷中,但其内容是在容器内生成的,因此没有跨平台问题。
没有人提到实际使用 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#-}" != "" ] || [ -z "$(command -v "")" ]; 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 点,恕我直言,这是一种更简洁的方法 - 不需要四处移动文件。
将您的主机 node_modules 文件夹与您的容器 node_modules 绑定并不是您提到的好做法。我经常看到为此文件夹创建内部卷的解决方案。不这样做会在构建阶段引起问题。
我 运行 在尝试为 angular 应用程序构建 docker 开发环境时遇到了这个问题,当我在主机中编辑文件时显示 tslib 错误文件夹导致我的主机的 node_modules 文件夹是空的(如预期的那样)。
在这种情况下,对我有帮助的廉价解决方案是使用名为 "Remote-Containers".
的 Visual Studio 代码扩展此扩展程序将允许您将 Visual Studio 代码 附加到您的容器,并在您的容器文件夹中编辑 运行 清晰的文件。为此,它将在您的开发容器中安装一个内部 vscode 服务器。有关更多信息,请查看 this link.
但是,请确保您的卷仍在 docker-compose.yml 文件中创建。
希望对您有所帮助:D!
运行 解决了这个问题,发现接受的答案很慢,无法将所有 node_modules
复制到每个容器 运行 中的主机,我设法通过安装依赖项解决了这个问题在容器中,镜像主机卷,如果存在 node_modules
文件夹,则跳过再次安装:
Docker 文件:
FROM node:12-alpine
WORKDIR /usr/src/app
CMD [ -d "node_modules" ] && npm run start || npm ci && npm run start
docker-compose.yml:
version: '3.8'
services:
service-1:
build: ./
volumes:
- ./:/usr/src/app
当您需要重新安装依赖项时,只需删除 node_modules
.
我不确定为什么你希望你的源代码存在于容器中 and host and bind mount other在开发过程中。通常,您希望您的源代码位于用于部署的容器内,而不是用于开发,因为代码在您的主机上可用并绑定安装。
你的docker-compose.yml
frontend:
volumes:
- ./app/frontend:/usr/src/app
你的Dockerfile
FROM node:10
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
当然你必须 运行 npm install
第一次和每次 package.json 改变,但是你 运行 它在容器里所以没有 cross-platform问题:docker-compose exec frontend npm install
终于启动你的服务器了docker-compose exec frontend npm start
然后,通常在针对部署的 CI 管道中,您构建最终映像并复制整个源代码并 node_modules 重新安装,但当然此时您不需要不再需要绑定安装和“同步”,因此您的设置可能如下所示:
docker-compose.yml
frontend:
build:
context: ./app/frontend
target: dev
volumes:
- ./app/frontend:/usr/src/app
Dockerfile
FROM node:10 as dev
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
FROM dev as build
COPY package.json package-lock.json ./
RUN npm install
COPY . ./
CMD ["npm", "start"]
稍后,您可以手动或在管道期间以 Dockerfile 的构建阶段为目标,以构建您的 deployment-ready 映像。
我知道这不是您问题的确切答案,因为您必须 运行 npm install 并且在开发过程中容器内没有任何东西,但它解决了您的 node_modules 问题,我觉得您的问题混合了开发和部署注意事项,所以您可能以错误的方式考虑了这个问题。
我的解决方法是在容器启动时而不是在 build-time 期间安装依赖项。
Docker 文件:
# We're using a multi-stage build so that we can install dependencies during build-time only for production.
# dev-stage
FROM node:14-alpine AS dev-stage
WORKDIR /usr/src/app
COPY package.json ./
COPY . .
# `yarn install` will run every time we start the container. We're using yarn because it's much faster than npm when there's nothing new to install
CMD ["sh", "-c", "yarn install && yarn run start"]
# production-stage
FROM node:14-alpine AS production-stage
WORKDIR /usr/src/app
COPY package.json ./
RUN yarn install
COPY . .
.dockerignore
将 node_modules
添加到 .dockerignore
以防止在 Dockerfile
运行 COPY . .
时复制它。我们使用卷来引入 node_modules
.
**/node_modules
docker-compose.yml
node_app:
container_name: node_app
build:
context: ./node_app
target: dev-stage # `production-stage` for production
volumes:
# For development:
# If node_modules already exists on the host, they will be copied
# into the container here. Since `yarn install` runs after the
# container starts, this volume won't override the node_modules.
- ./node_app:/usr/src/app
# For production:
#
- ./node_app:/usr/src/app
- /usr/src/app/node_modules
一个简单、完整的解决方案
您可以使用外部命名卷技巧 和 在容器中安装 node_modules 通过将卷的存储位置配置为指向主机的 将其与主机同步=54=]目录。这可以使用命名的 volume using the local driver and a bind mount 来完成,如下例所示。
该卷的数据无论如何都存储在您的主机上,类似于 /var/lib/docker/volumes/,因此我们只是将其存储在您的项目中。
要在 Docker Compose 中执行此操作,只需将 node_modules 卷添加到前端服务,然后在命名卷部分配置卷,其中“设备”是 相对路径(从docker-compose.yml的位置)到本地(主机)node_modules目录。
docker-compose.yml
version: '3.9'
services:
ui:
# Your service options...
volumes:
- node_modules:/path/to/node_modules
volumes:
node_modules:
driver: local
driver_opts:
type: none
o: bind
device: ./local/path/to/node_modules
此解决方案的关键是永远不要直接在主机中进行更改 node_modules,而是始终在容器中安装、更新或删除 Node 包。
版本控制提示: 当你的Node package.json/package-lock.json文件发生变化时,无论是拉取还是切换分支,除了重建Image之外,你还必须移除Volume,并删除其中的内容:
docker volume rm example_node_modules
rm -rf local/path/to/node_modules
mkdir local/path/to/node_modules
文档:
最适合发展
docker-compose.yml
...
frontend:
build: ./app/frontend
ports:
- 3000:3000
volumes:
- ./app/frontend:/usr/src/app
...
./app/frontend/Dockerfile
FROM node:lts
WORKDIR /usr/src/app
RUN npm install -g react-scripts
RUN chown -Rh node:node /usr/src/app
USER node
EXPOSE 3000
CMD [ "sh", "-c", "npm install && npm run start" ]
#FOR PROD
# CMD [ "sh", "-c", "npm install && npm run build" ]
用户node
将帮助您获得主人<->客人
文件夹 node_modules
将可从主机访问并同步主机<->来宾
您也可以使用 dockerized npm install
。这与 npm install
相同,但它在 docker 容器上运行。
node_modules 将写入主机。它应该开箱即用,您可以指定要使用的 npm 版本。如果需要,可以扩展或自定义容器。
请注意,某些 npm 包可能需要编译,并且生成的二进制文件可能与您的主机不兼容。如果您只需要源代码或 dist 文件,这不是问题。
免责声明:我是 Dockerized 的作者。