docker-在 node_modules 上撰写卷但为空
docker-compose volume on node_modules but is empty
我是 Docker 的新手,我想在我的计算机上映射 node_modules 文件夹(用于调试目的)。
这是我的docker-compose.yml
web:
build: .
ports:
- "3000:3000"
links:
- db
environment:
PORT: 3000
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
db:
image: mongo:3.3
ports:
- "27017:27017"
command: "--smallfiles --logpath=/dev/null"
我支持 Docker Mac。当我 运行 docker-compose up -d
一切正常时,它会在我的计算机上创建一个 node_modules 文件夹,但它是空的。我进入容器的 bash 和 ls node_modules,所有包裹都在那里。
如何在我的计算机上也获取容器中的内容?
谢谢
变化:
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
收件人:
volumes:
- .:/usr/src/app
它会将 node_modules 放入您的本地映射卷中。按照您的方式,/usr/src/app/node_modules
将存储在不同的卷中,您需要 docker inspect {container-name}
才能找到该位置。如果您确实要指定位置,请指定为:
- /path/to/my_node_modules:/usr/src/app/node_modules
首先,有一个操作顺序。构建映像时,不会安装卷,只有在 运行 容器时才会安装它们。因此,当您完成构建时,所有更改将只存在于图像内部,而不存在于任何卷中。如果你在一个目录上安装一个卷,它会覆盖该位置的图像中的任何内容,从视图中隐藏这些内容(有一个初始化异常,见下文)。
接下来是卷语法:
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
告诉docker-compose从当前目录创建一个主机卷到容器内的/usr/src/app
,然后将/usr/src/app/node_modules
映射到由[=52维护的匿名卷=].后者会以卷的形式出现在docker volume ls
中,uuid串比较长,比较没用。
要将 /usr/src/app/node_modules
映射到您主机上的一个文件夹,您需要在其前面包含一个文件夹名称和冒号,就像您在上面的行中所做的那样。例如。 /host/dir/node_modules:/usr/src/app/node_modules
.
命名卷与主机卷有点不同,因为 docker 使用您可以在 docker volume ls
中看到的名称维护它们。您仅使用名称而不是路径来引用这些卷。因此 node_modules:/usr/src/app/node_modules
将创建一个名为 node_modules
的卷,您可以将其挂载到仅具有该名称的容器中。
我分散描述命名卷,因为它们带有一个功能,该功能会变成主机卷的陷阱。 Docker 通过使用该位置的图像内容初始化它们来帮助您使用命名卷。所以在上面的例子中,如果命名卷 node_modules
是空的(或新的),它会首先将 /usr/src/app/node_modules` 中的图像内容复制到这个卷,然后将它挂载到你的容器中。
对于主机卷,您将永远看不到任何初始化,无论那是什么
位置,即使是一个空目录,也是您在容器中看到的全部。无法从该目录位置的图像中获取内容以首先复制到该位置的主机卷。这也意味着容器内所需的目录权限不会自动继承,您需要手动设置将在容器内运行的主机目录的权限。
最后,docker 对于 windows 和 mac 有一个小问题,它们 运行 在 VM 中,并且您的主机卷已安装到 VM。要将卷挂载到主机,您必须将应用程序配置为将主机中的文件夹共享给 VM,然后将 VM 中的卷挂载到容器中。默认情况下,在 Mac 上,包含 /Users 文件夹,但如果您使用其他目录,例如/Projects 目录,甚至是小写的 /users(unix 和 bsd 区分大小写),您将不会在容器内看到 Mac 中的内容。
有了这些基础知识,一种可能的解决方案是重新设计您的工作流程,以从复制到主机的图像中获取目录内容。首先,您需要将文件复制到图像中的不同位置。然后,您需要在容器启动时将文件从该保存的图像位置复制到卷安装位置。当你执行后者时,你应该注意到你正在破坏拥有一个卷(持久性)的目的,并且可能需要考虑添加一些逻辑以便在你 运行 副本时更具选择性。首先,将 entrypoint.sh 添加到您的构建中,如下所示:
#!/bin/sh
# copy from the image backup location to the volume mount
cp -a /usr/src/app_backup/node_modules/* /usr/src/app/node_modules/
# this next line runs the docker command
exec "$@"
然后更新您的 Docker 文件以包含入口点和备份命令:
FROM node:6.3
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install -g babel babel-runtime babel-register mocha nodemon
RUN npm install
# Bundle app source
COPY . /usr/src/app
RUN cp -a /usr/src/app/. /usr/src/app_backup
EXPOSE 1234
ENTRYPOINT [ "/usr/src/app/entrypoint.sh" ]
CMD [ "npm", "start" ]
然后从 docker-compose.yml:
中删除多余的音量
volumes:
- .:/usr/src/app
TL;DR 工作示例,克隆并尝试: https://github.com/xbx/base-server
首先(在 运行 容器之前),您的计算机(外部图像)需要一个 node_modules 用于调试目的。
如果你只想调试 node_modules:
volumes:
- /path/to/node_modules:/usr/src/app/node_modules
如果你想同时调试你的代码和 node_modules:
volumes:
- .:/usr/src/app/
请记住,在容器外至少需要一次 运行 npm install
(或复制 docker build
生成的 node_modules 目录)。如果您需要更多详细信息,请立即联系我。
编辑。因此,在 OSX 中不需要 npm,您可以:
docker build
然后 docker cp <container-id>:/path/to/node-modules ./local-node-modules/
。然后在你的 docker-compose.yml 中挂载这些文件并解决你想要的任何问题。
- 或者,
docker build
并且 (Dockerfile) 在另一个目录中执行 npm install
。然后在你的命令(CMD 或 docker-compose 命令)中复制(cp
)到正确的目录,但是这个目录从你的计算机上挂载为空(docker 中的一个卷) -compose.yml) 然后解决你想要的任何问题。
编辑 2。(选项 2)工作示例,克隆并尝试: https://github.com/xbx/base-server
我在这个从你的分叉的回购协议中自动完成了这一切。
Docker 文件
FROM node:6.3
# Install app dependencies
RUN mkdir /build-dir
WORKDIR /build-dir
COPY package.json /build-dir
RUN npm install -g babel babel-runtime babel-register mocha nodemon
RUN npm install
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN ln -s /build-dir/node_modules node_modules
# Bundle app source
COPY . /usr/src/app
EXPOSE 1234
CMD [ "npm", "start" ]
docker-compose.yml
web:
build: .
ports:
- "1234:1234"
links:
- db # liaison avec la DB
environment:
PORT: 1234
command: /command.sh
volumes:
- ./src/:/usr/src/app/src/
- ./node_modules:/usr/src/app/node_modules
- ./command.sh:/command.sh
db:
image: mongo:3.3
ports:
- "27017:27017"
command: "--smallfiles --logpath=/dev/null"
command.sh
#!/bin/bash
cp -r /build-dir/node_modules/ /usr/src/app/
exec npm start
请克隆我的存储库并执行 docker-compose up
。它做你想做的。
PS:可以改进以更好的方式做同样的事情(即最佳实践等)
我在 OSX,它适合我。
我在 上添加了一些内容,因为它没有考虑到一些事情;即:
cp
耗时过长,用户无法查看进度。
- 如果是通过主机安装的,我希望
node_modules
被覆盖。
- 我希望能够
git pull
当容器 运行ning 而不是 运行ning 并相应地更新 node_modules
,如果有任何变化。
- 我只希望在开发环境中有这种行为。
为了解决第一个问题,我在我的图片上安装了rsync
,还有pv
(因为我想在删除的同时查看进度)。由于我使用的是高山,所以我在 Dockerfile
:
中使用了 apk add
# Install rsync and pv to view progress of moving and deletion of node_modules onto host volume.
RUN apk add rsync && apk add pv
然后我将 entrypoint.sh
更改为如下所示(您可以将 yarn.lock
替换为 package-lock.json
):
#!/bin/ash
# Declaring variables.
buildDir=/home/node/build-dir
workDir=/home/node/work-dir
package=package.json
lock=yarn.lock
nm=node_modules
#########################
# Begin Functions
#########################
copy_modules () { # Copy all files of build directory to that of the working directory.
echo "Calculating build folder size..."
buildFolderSize=$( du -a $buildDir/$nm | wc -l )
echo "Copying files from build directory to working directory..."
rsync -avI $buildDir/$nm/. $workDir/$nm/ | pv -lfpes "$buildFolderSize" > /dev/null
echo "Creating flag to indicate $nm is in sync..."
touch $workDir/$nm/.docked # Docked file is a flag that tells the files were copied already from the build directory.
}
delete_modules () { # Delete old module files.
echo "Calculating incompatible direcotry $nm folder size..."
folderSize=$( du -a /$nm | wc -l )
echo "Deleting incompatible directory $nm folder..."
rm -rfv /$nm/* | pv -lfpes "$folderSize" > /dev/null # Delete all files in node_modules.
rm -rf /$nm/.* 2> /dev/null # Delete all hidden files in node_modules.node_modules.
}
#########################
# End Functions
# Begin Script
#########################
if cmp -s $buildDir/$lock $workDir/$lock >/dev/null 2>&1 # Compare lock files.
then
# Delete old modules.
delete_modules "build" "$buildDir"
# Remove old build package.
rm -rf $buildDir/$package 2> /dev/null
rm -rf $buildDir/$lock 2> /dev/null
# Copy package.json from working directory to build directory.
rsync --info=progress2 $workDir/$package $buildDir/$package
rsync --info=progress2 $workDir/$lock $buildDir/$lock
cd $buildDir/ || return
yarn
delete_modules "working" "$workDir"
copy_modules
# Check if the directory is empty, as it is when it is mounted for the first time.
elif [ -z "$(ls -A $workDir/$nm)" ]
then
copy_modules
elif [ ! -f "$workDir/$nm/.docked" ] # Check if modules were copied from build directory.
then
# Delete old modules.
delete_modules "working" "$workDir"
# Copy modules from build directory to working directory.
copy_modules
else
echo "The node_modules folder is good to go; skipping copying."
fi
#########################
# End Script
#########################
if [ "" != "git" ] # Check if script was not run by git-merge hook.
then
# Change to working directory.
cd $workDir/ || return
# Run yarn start command to start development.
exec yarn start:debug
fi
我添加了 pv
至少可以向用户显示正在发生的事情的进展情况。另外,我添加了一个标志来表明 node_modules
是通过容器安装的。
每当安装包时,我都会利用 package.json
文件的 postinstall
和 postuninstall
挂钩从中复制 package.json
和 yarn.lock
文件工作目录到构建目录以保持它们是最新的。我还安装了 postinstall-postinstall
包以确保 postuninstall
挂钩有效。
"postinstall" : "if test $DOCKER_FLAG = 1; then rsync -I --info=progress2 /home/node/work-dir/package.json /home/node/build-dir/package.json && rsync -I --info=progress2 /home/node/work-dir/yarn.lock /home/node/build-dir/yarn.lock && echo 'Build directory files updated.' && touch /home/node/work-dir/node_modules/.docked; else rm -rf ./node_modules/.docked && echo 'Warning: files installed outside container; deleting docker flag file.'; fi",
"postuninstall": "if test $DOCKER_FLAG = 1; then rsync -I --info=progress2 /home/node/work-dir/package.json /home/node/build-dir/package.json && rsync -I --info=progress2 /home/node/work-dir/yarn.lock /home/node/build-dir/yarn.lock && echo 'Build directory files updated.' && touch /home/node/work-dir/node_modules/.docked; else rm -rf ./node_modules/.docked && echo 'Warning: files installed outside container; deleting docker flag file.'; fi",
我使用了一个名为 DOCKER_FLAG
的环境变量,并在 docker-compose.yml
文件中将其设置为 1
。这样,当有人在容器外安装时,它就不会运行。此外,我确保删除 .docked
标志文件,以便脚本知道它已使用主机命令安装。
关于每次拉取时同步node_modules
的问题,我用了git钩子;即 post-merge 钩子。每次我拉,它会尝试 运行 entrypoint.sh
脚本,如果容器是 运行ning。它还会向脚本 git
提供一个参数,该脚本检查是否 运行 exec yarn:debug
,因为容器已经 运行ning。这是我在 .git/hooks/post-merge
:
的脚本
#!/bin/bash
if [ -x "$(command -v docker)" ] && [ "$(docker ps -a | grep <container_name>)" ]
then
exec docker exec <container_name> sh -c "/home/node/build-dir/entrypoint.sh git"
exit 1
fi
如果容器不是 运行ning,并且我获取了更改,那么 entrypoint.sh
脚本将首先检查锁定文件之间是否有任何差异,如果有,它将在构建目录中重新安装,并在第一次创建图像和容器时执行它所做的操作 运行。此 tutorial 可用于与队友共享钩子。
注意:请务必使用 docker-compose run...
,因为 docker-compose up...
不允许显示进度指示器。
最简单的解决方案
使用 Docker Compose 和本地 Volume Driver with a Bind Mount.
配置 node_modules 卷以使用本地 node_modules 目录作为其存储位置
首先,确保你有一个本地 node_modules 目录,或者创建它,然后在你的 docker-compose 的命名卷部分为它创建一个 Docker 卷文件:
volumes:
node_modules:
driver: local
driver_opts:
type: none
o: bind
device: ./local/relative/path/to/node_modules
然后,将您的 node_modules 卷添加到您的服务中:
ui:
volumes:
- node_modules:/container/path/to/node_modules
只需确保您始终在 Docker 容器内进行 node_module 更改(使用 docker-compose exec),它将完美同步并在主机上用于 IDE、代码完成、调试等
版本控制提示:
当你的Node package.json/package-lock.json文件发生变化时,无论是拉取还是切换分支,除了重建Image之外,你还必须移除Volume,并删除它的内容:
docker volume rm example_node_modules
rm -rf local/relative/path/to/node_modules
mkdir local/relative/path/to/node_modules
我是 Docker 的新手,我想在我的计算机上映射 node_modules 文件夹(用于调试目的)。
这是我的docker-compose.yml
web:
build: .
ports:
- "3000:3000"
links:
- db
environment:
PORT: 3000
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
db:
image: mongo:3.3
ports:
- "27017:27017"
command: "--smallfiles --logpath=/dev/null"
我支持 Docker Mac。当我 运行 docker-compose up -d
一切正常时,它会在我的计算机上创建一个 node_modules 文件夹,但它是空的。我进入容器的 bash 和 ls node_modules,所有包裹都在那里。
如何在我的计算机上也获取容器中的内容?
谢谢
变化:
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
收件人:
volumes:
- .:/usr/src/app
它会将 node_modules 放入您的本地映射卷中。按照您的方式,/usr/src/app/node_modules
将存储在不同的卷中,您需要 docker inspect {container-name}
才能找到该位置。如果您确实要指定位置,请指定为:
- /path/to/my_node_modules:/usr/src/app/node_modules
首先,有一个操作顺序。构建映像时,不会安装卷,只有在 运行 容器时才会安装它们。因此,当您完成构建时,所有更改将只存在于图像内部,而不存在于任何卷中。如果你在一个目录上安装一个卷,它会覆盖该位置的图像中的任何内容,从视图中隐藏这些内容(有一个初始化异常,见下文)。
接下来是卷语法:
volumes:
- .:/usr/src/app
- /usr/src/app/node_modules
告诉docker-compose从当前目录创建一个主机卷到容器内的/usr/src/app
,然后将/usr/src/app/node_modules
映射到由[=52维护的匿名卷=].后者会以卷的形式出现在docker volume ls
中,uuid串比较长,比较没用。
要将 /usr/src/app/node_modules
映射到您主机上的一个文件夹,您需要在其前面包含一个文件夹名称和冒号,就像您在上面的行中所做的那样。例如。 /host/dir/node_modules:/usr/src/app/node_modules
.
命名卷与主机卷有点不同,因为 docker 使用您可以在 docker volume ls
中看到的名称维护它们。您仅使用名称而不是路径来引用这些卷。因此 node_modules:/usr/src/app/node_modules
将创建一个名为 node_modules
的卷,您可以将其挂载到仅具有该名称的容器中。
我分散描述命名卷,因为它们带有一个功能,该功能会变成主机卷的陷阱。 Docker 通过使用该位置的图像内容初始化它们来帮助您使用命名卷。所以在上面的例子中,如果命名卷 node_modules
是空的(或新的),它会首先将 /usr/src/app/node_modules` 中的图像内容复制到这个卷,然后将它挂载到你的容器中。
对于主机卷,您将永远看不到任何初始化,无论那是什么 位置,即使是一个空目录,也是您在容器中看到的全部。无法从该目录位置的图像中获取内容以首先复制到该位置的主机卷。这也意味着容器内所需的目录权限不会自动继承,您需要手动设置将在容器内运行的主机目录的权限。
最后,docker 对于 windows 和 mac 有一个小问题,它们 运行 在 VM 中,并且您的主机卷已安装到 VM。要将卷挂载到主机,您必须将应用程序配置为将主机中的文件夹共享给 VM,然后将 VM 中的卷挂载到容器中。默认情况下,在 Mac 上,包含 /Users 文件夹,但如果您使用其他目录,例如/Projects 目录,甚至是小写的 /users(unix 和 bsd 区分大小写),您将不会在容器内看到 Mac 中的内容。
有了这些基础知识,一种可能的解决方案是重新设计您的工作流程,以从复制到主机的图像中获取目录内容。首先,您需要将文件复制到图像中的不同位置。然后,您需要在容器启动时将文件从该保存的图像位置复制到卷安装位置。当你执行后者时,你应该注意到你正在破坏拥有一个卷(持久性)的目的,并且可能需要考虑添加一些逻辑以便在你 运行 副本时更具选择性。首先,将 entrypoint.sh 添加到您的构建中,如下所示:
#!/bin/sh
# copy from the image backup location to the volume mount
cp -a /usr/src/app_backup/node_modules/* /usr/src/app/node_modules/
# this next line runs the docker command
exec "$@"
然后更新您的 Docker 文件以包含入口点和备份命令:
FROM node:6.3
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install -g babel babel-runtime babel-register mocha nodemon
RUN npm install
# Bundle app source
COPY . /usr/src/app
RUN cp -a /usr/src/app/. /usr/src/app_backup
EXPOSE 1234
ENTRYPOINT [ "/usr/src/app/entrypoint.sh" ]
CMD [ "npm", "start" ]
然后从 docker-compose.yml:
中删除多余的音量 volumes:
- .:/usr/src/app
TL;DR 工作示例,克隆并尝试: https://github.com/xbx/base-server
首先(在 运行 容器之前),您的计算机(外部图像)需要一个 node_modules 用于调试目的。
如果你只想调试 node_modules:
volumes:
- /path/to/node_modules:/usr/src/app/node_modules
如果你想同时调试你的代码和 node_modules:
volumes:
- .:/usr/src/app/
请记住,在容器外至少需要一次 运行 npm install
(或复制 docker build
生成的 node_modules 目录)。如果您需要更多详细信息,请立即联系我。
编辑。因此,在 OSX 中不需要 npm,您可以:
docker build
然后docker cp <container-id>:/path/to/node-modules ./local-node-modules/
。然后在你的 docker-compose.yml 中挂载这些文件并解决你想要的任何问题。- 或者,
docker build
并且 (Dockerfile) 在另一个目录中执行npm install
。然后在你的命令(CMD 或 docker-compose 命令)中复制(cp
)到正确的目录,但是这个目录从你的计算机上挂载为空(docker 中的一个卷) -compose.yml) 然后解决你想要的任何问题。
编辑 2。(选项 2)工作示例,克隆并尝试: https://github.com/xbx/base-server 我在这个从你的分叉的回购协议中自动完成了这一切。
Docker 文件
FROM node:6.3
# Install app dependencies
RUN mkdir /build-dir
WORKDIR /build-dir
COPY package.json /build-dir
RUN npm install -g babel babel-runtime babel-register mocha nodemon
RUN npm install
# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
RUN ln -s /build-dir/node_modules node_modules
# Bundle app source
COPY . /usr/src/app
EXPOSE 1234
CMD [ "npm", "start" ]
docker-compose.yml
web:
build: .
ports:
- "1234:1234"
links:
- db # liaison avec la DB
environment:
PORT: 1234
command: /command.sh
volumes:
- ./src/:/usr/src/app/src/
- ./node_modules:/usr/src/app/node_modules
- ./command.sh:/command.sh
db:
image: mongo:3.3
ports:
- "27017:27017"
command: "--smallfiles --logpath=/dev/null"
command.sh
#!/bin/bash
cp -r /build-dir/node_modules/ /usr/src/app/
exec npm start
请克隆我的存储库并执行 docker-compose up
。它做你想做的。
PS:可以改进以更好的方式做同样的事情(即最佳实践等)
我在 OSX,它适合我。
我在
cp
耗时过长,用户无法查看进度。- 如果是通过主机安装的,我希望
node_modules
被覆盖。 - 我希望能够
git pull
当容器 运行ning 而不是 运行ning 并相应地更新node_modules
,如果有任何变化。 - 我只希望在开发环境中有这种行为。
为了解决第一个问题,我在我的图片上安装了rsync
,还有pv
(因为我想在删除的同时查看进度)。由于我使用的是高山,所以我在 Dockerfile
:
apk add
# Install rsync and pv to view progress of moving and deletion of node_modules onto host volume.
RUN apk add rsync && apk add pv
然后我将 entrypoint.sh
更改为如下所示(您可以将 yarn.lock
替换为 package-lock.json
):
#!/bin/ash
# Declaring variables.
buildDir=/home/node/build-dir
workDir=/home/node/work-dir
package=package.json
lock=yarn.lock
nm=node_modules
#########################
# Begin Functions
#########################
copy_modules () { # Copy all files of build directory to that of the working directory.
echo "Calculating build folder size..."
buildFolderSize=$( du -a $buildDir/$nm | wc -l )
echo "Copying files from build directory to working directory..."
rsync -avI $buildDir/$nm/. $workDir/$nm/ | pv -lfpes "$buildFolderSize" > /dev/null
echo "Creating flag to indicate $nm is in sync..."
touch $workDir/$nm/.docked # Docked file is a flag that tells the files were copied already from the build directory.
}
delete_modules () { # Delete old module files.
echo "Calculating incompatible direcotry $nm folder size..."
folderSize=$( du -a /$nm | wc -l )
echo "Deleting incompatible directory $nm folder..."
rm -rfv /$nm/* | pv -lfpes "$folderSize" > /dev/null # Delete all files in node_modules.
rm -rf /$nm/.* 2> /dev/null # Delete all hidden files in node_modules.node_modules.
}
#########################
# End Functions
# Begin Script
#########################
if cmp -s $buildDir/$lock $workDir/$lock >/dev/null 2>&1 # Compare lock files.
then
# Delete old modules.
delete_modules "build" "$buildDir"
# Remove old build package.
rm -rf $buildDir/$package 2> /dev/null
rm -rf $buildDir/$lock 2> /dev/null
# Copy package.json from working directory to build directory.
rsync --info=progress2 $workDir/$package $buildDir/$package
rsync --info=progress2 $workDir/$lock $buildDir/$lock
cd $buildDir/ || return
yarn
delete_modules "working" "$workDir"
copy_modules
# Check if the directory is empty, as it is when it is mounted for the first time.
elif [ -z "$(ls -A $workDir/$nm)" ]
then
copy_modules
elif [ ! -f "$workDir/$nm/.docked" ] # Check if modules were copied from build directory.
then
# Delete old modules.
delete_modules "working" "$workDir"
# Copy modules from build directory to working directory.
copy_modules
else
echo "The node_modules folder is good to go; skipping copying."
fi
#########################
# End Script
#########################
if [ "" != "git" ] # Check if script was not run by git-merge hook.
then
# Change to working directory.
cd $workDir/ || return
# Run yarn start command to start development.
exec yarn start:debug
fi
我添加了 pv
至少可以向用户显示正在发生的事情的进展情况。另外,我添加了一个标志来表明 node_modules
是通过容器安装的。
每当安装包时,我都会利用 package.json
文件的 postinstall
和 postuninstall
挂钩从中复制 package.json
和 yarn.lock
文件工作目录到构建目录以保持它们是最新的。我还安装了 postinstall-postinstall
包以确保 postuninstall
挂钩有效。
"postinstall" : "if test $DOCKER_FLAG = 1; then rsync -I --info=progress2 /home/node/work-dir/package.json /home/node/build-dir/package.json && rsync -I --info=progress2 /home/node/work-dir/yarn.lock /home/node/build-dir/yarn.lock && echo 'Build directory files updated.' && touch /home/node/work-dir/node_modules/.docked; else rm -rf ./node_modules/.docked && echo 'Warning: files installed outside container; deleting docker flag file.'; fi",
"postuninstall": "if test $DOCKER_FLAG = 1; then rsync -I --info=progress2 /home/node/work-dir/package.json /home/node/build-dir/package.json && rsync -I --info=progress2 /home/node/work-dir/yarn.lock /home/node/build-dir/yarn.lock && echo 'Build directory files updated.' && touch /home/node/work-dir/node_modules/.docked; else rm -rf ./node_modules/.docked && echo 'Warning: files installed outside container; deleting docker flag file.'; fi",
我使用了一个名为 DOCKER_FLAG
的环境变量,并在 docker-compose.yml
文件中将其设置为 1
。这样,当有人在容器外安装时,它就不会运行。此外,我确保删除 .docked
标志文件,以便脚本知道它已使用主机命令安装。
关于每次拉取时同步node_modules
的问题,我用了git钩子;即 post-merge 钩子。每次我拉,它会尝试 运行 entrypoint.sh
脚本,如果容器是 运行ning。它还会向脚本 git
提供一个参数,该脚本检查是否 运行 exec yarn:debug
,因为容器已经 运行ning。这是我在 .git/hooks/post-merge
:
#!/bin/bash
if [ -x "$(command -v docker)" ] && [ "$(docker ps -a | grep <container_name>)" ]
then
exec docker exec <container_name> sh -c "/home/node/build-dir/entrypoint.sh git"
exit 1
fi
如果容器不是 运行ning,并且我获取了更改,那么 entrypoint.sh
脚本将首先检查锁定文件之间是否有任何差异,如果有,它将在构建目录中重新安装,并在第一次创建图像和容器时执行它所做的操作 运行。此 tutorial 可用于与队友共享钩子。
注意:请务必使用 docker-compose run...
,因为 docker-compose up...
不允许显示进度指示器。
最简单的解决方案
使用 Docker Compose 和本地 Volume Driver with a Bind Mount.
配置 node_modules 卷以使用本地 node_modules 目录作为其存储位置首先,确保你有一个本地 node_modules 目录,或者创建它,然后在你的 docker-compose 的命名卷部分为它创建一个 Docker 卷文件:
volumes:
node_modules:
driver: local
driver_opts:
type: none
o: bind
device: ./local/relative/path/to/node_modules
然后,将您的 node_modules 卷添加到您的服务中:
ui:
volumes:
- node_modules:/container/path/to/node_modules
只需确保您始终在 Docker 容器内进行 node_module 更改(使用 docker-compose exec),它将完美同步并在主机上用于 IDE、代码完成、调试等
版本控制提示: 当你的Node package.json/package-lock.json文件发生变化时,无论是拉取还是切换分支,除了重建Image之外,你还必须移除Volume,并删除它的内容:
docker volume rm example_node_modules
rm -rf local/relative/path/to/node_modules
mkdir local/relative/path/to/node_modules