docker组成“向上”与“运行”产生不同的挂载量

更新2:我已经在Git上创build了一个示例项目来重现此问题 。 经过进一步的testing,testing用例与我在原文中描述的略有不同。

我包括了我在下面的github仓库中写的自述文件的内容。


用例

  • 一个简单的具有Dockerfile的nodejs项目。
  • 上述项目使用的一个本地NPM依赖项(通过Dockerfile复制到容器中)。 该项目通过本地path引用依赖项。
  • nodejs项目有一个web路由( / ),它从package.json打印本地npm依赖项的版本。 这用于validationtesting用例过程的结果。
  • docker-compose使用这种卷技术将主机的源代码树覆盖在容器的源代码树上,然后将容器上的node_modules覆盖在第一个卷的顶部。

重现步骤

  1. 克隆这个回购 。
  2. 通过docker rmdocker rmi清理与此回购项目相关的任何以前的容器和图像。
  3. 看看test2_run1标签。 此状态表示使用本地NPM依赖项的1.0.0版本的项目。
  4. docker-compose build 。 如果正确执行了第2步,则所有步骤都应运行而不使用caching。 请注意npm install命令中本地NPM依赖的版本,例如+-- my-npm@1.0.0
  5. 做一个docker-compose up 。 浏览到http://localhost:8000 。 该页面应报告版本1.0.0
  6. 停止正在运行的容器。 (在发出up命令的terminal上按Ctrl-C。)
  7. 看看test2_run2标签。 这会对NPM的index.js文件和package.json的版本index.js引入一个小的更改为1.0.1
  8. docker-compose build只有COPY ./my-npm ...的说明才能使用caching。 (例如,docker输出打印---> Using cache该指令。)所有后续步骤应由docker运行。 这是因为步骤7中引入的对NPM程序包COPY ./my-npm ...的更改应已使COPY ./my-npm ...命令的caching失效,并因此导致后续步骤失效。 确认在npm install命令期间,在摘要树输出中打印新版本的NPM,例如+-- my-npm@1.0.1
  9. 做一个docker-compose up 。 浏览到http://localhost:8000 。 该页面应报告版本1.0.1

预期的行为:步骤9中的页面应报告1.0.1 。 也就是说,本地npm的变化应该通过docker-compose up来反映在集装箱docker-compose up

实际行为:步骤9中的页面报告1.0.0

请注意,Docker本身正在按照预期重新构build图像。 观察到的问题不是docker重新使用caching的图像,因为输出显示重新运行NPM安装并显示新版本的本地NPM依赖关系。 问题是docker-compose没有看到包含dctest_service1容器的底层映像已经被更新了。

事实上,在容器中运行bash使我们能够看到容器有更新的my-npm模块文件,但是node_modules版本是陈旧的:

# docker exec -it dctest_service1_1 bash app@6bf2671b75c6:~/service1$ grep version my-npm/package.json node_modules/my-npm/package.json my-npm/package.json: "version": "1.0.1", node_modules/my-npm/package.json: "version": "1.0.0" app@6bf2671b75c6:~/service1$

解决方法:使用dctest_service1 docker rm删除dctest_service1容器。 然后重新运行docker-compose up ,这将使用现有的图像重新创build容器。 值得注意的是,没有底层的图像被重build。 在重新创build容器时, docker-compose似乎想要使用具有更新的node_modules的更新的node_modules

请参阅output目录中的第一次运行(步骤4和5)和第二次运行(步骤8和9)中output的输出。


原始post

我有一个基于本教程的nodejs Dockerfile (“在Docker中构build节点应用程序的教训”) 。 具体来说,请注意,本教程使用卷技巧从容器自身装入node_modules目录,并将其覆盖在与主机等效的目录之上。 例如:

 volumes: - .:/home/app/my-app - /home/app/my-app/node_modules 

我遇到了一个问题,其中package.json的更新如预期的那样触发npm install (与使用dockercaching相反),但是当使用docker构build服务docker-compose up ,最终的容器不知何故以最后版本的node_modules数据,因为新添加的已添加的NPM软件包从目录中丢失。 然而,如果通过docker-compose run --rm手工运行指定的CMD ,那么我确实看到了更新的卷!

我可以用几种方法来证实这一点:

node_modules时间戳

容器通过“up”启动:

 app@88614c5599b6:~/my-app$ ls -l ... drwxr-xr-x 743 app app 28672 Dec 12 16:41 node_modules 

容器通过“运行”启动:

 app@bdcbfb37b4ba:~/my-app$ ls -l ... drwxr-xr-x 737 app app 28672 Jan 9 02:25 node_modules 

不同的docker inspect “装载”条目ID

容器通过“up”启动:

 "Name": "180b82101433ab159a46ec1dd0edb9673bcaf09c98e7481aed7a32a87a94e76a", "Source": "/var/lib/docker/volumes/180b82101433ab159a46ec1dd0edb9673bcaf09c98e7481aed7a32a87a94e76a/_data", "Destination": "/home/app/my-app/node_modules", 

容器通过“运行”启动:

 "Name": "8eb7454fb976830c389b54f9480b1128ab15de14ca0b167df8f3ce880fb55720", "Source": "/var/lib/docker/volumes/8eb7454fb976830c389b54f9480b1128ab15de14ca0b167df8f3ce880fb55720/_data", "Destination": "/home/app/my-app/node_modules", 

主机configuration – >绑定

我不确定这是否相关,但我也注意到(也在HostConfig docker inspectHostConfig下的HostConfig部分在这两种情况下HostConfig不同的:

容器通过“up”启动:

 "Binds": [ "180b82101433ab159a46ec1dd0edb9673bcaf09c98e7481aed7a32a87a94e76a:/home/app/my-app/node_modules:rw", "/Volumes/my-mount/my-app:/home/app/my-app:rw" ], 

容器通过“运行”启动:

 "Binds": [ "/Volumes/my-mount/my-app:/home/app/my-app:rw" ], 

(两者都显示了镜像上的主机源,但只有“up”显示了node_modules的二次覆盖卷,这看起来像是另一个奇怪的皱纹。)

理论

根据docker-compose CLI参考 :

如果服务有现有的容器,并且在创build容器后服务的configuration或图像被更改,则docker-compose up通过停止并重新创build容器来获取更改

因此,看起来docker-compose up不认为configuration或图像被改变了。 我只是不知道如何debugging,以确认。 当然,我可以使用--force-recreate来解决这个问题,但是我想解决我的configuration不正确的问题。

更新 :如果我在docker-compose build之前做了一个显式的docker-compose build ,问题仍然存在。 因此,目前我对这个理论不太自信。

这是整个Dockefile

 FROM node:6.9.1 RUN useradd --user-group --create-home --shell /bin/false app ENV HOME=/home/app ENV APP=my-app ENV NPM_CONFIG_LOGLEVEL warn RUN npm install --global gulp-cli COPY ./package.json $HOME/$APP/package.json RUN chown -R app:app $HOME/* USER app WORKDIR $HOME/$APP RUN npm install && npm cache clean USER root COPY . $HOME/$APP RUN chown -R app:app $HOME/* && chmod u+x ./node_modules/.bin/* ./bin/* USER app ENTRYPOINT ["/home/app/my-app/bin/entrypoint.sh"] CMD ["npm", "run", "start:dev"] 

命令docker docker-compose使用docker-compose.yml文件作为您的集装箱service的configuration文件。 默认情况下,它会在运行docker docker-compose的目录中查找这个.ymlconfiguration文件。 所以可能是因为你的docker-compose.yml文件不是最新的,当你运行docker-compose up时,看到你的一个卷没有安装。

docker run忽略docker-compose.yml文件,并使用Dockerimagebuild立容器。 所以Dockerimage文件和docker-compose.yml文件可能会有configuration差异。