【发布时间】:2017-01-10 13:23:50
【问题描述】:
更新 2:我创建了a sample project on Git to reproduce this issue。经过进一步测试,测试用例与我在原帖中描述的略有不同。
我在下面的 github 存储库中包含了我写的 README 的内容。
用例
- 一个带有
Dockerfile的简单nodejs 项目。 - 上述项目使用的一个本地 NPM 依赖项(通过 Dockerfile 复制到容器)。该项目通过local path 引用依赖项。
- nodejs 项目有一个 Web 路由 (
/),它从其package.json打印本地 npm 依赖项的版本。这用于验证测试用例过程的结果。 - docker-compose 使用this volume technique 覆盖宿主机的源代码树
在容器的源树顶部,然后将容器中的
node_modules覆盖在第一个卷的顶部。
复制步骤
- 克隆this repo。
- 通过
docker rm和docker rmi清理与此repo 项目相关的任何以前的容器和图像。 - 查看
test2_run1标签。此状态表示使用本地 NPM 依赖项的 1.0.0 版本的项目。 - 做一个
docker-compose build。如果正确执行了第 2 步,则所有步骤都应在不使用任何缓存的情况下运行。 在npm install命令期间注意本地 NPM 依赖项的版本,例如+-- my-npm@1.0.0. - 做一个
docker-compose up。浏览至http://localhost:8000。该页面应报告版本1.0.0。 - 停止正在运行的容器。 (在发出
up命令的终端上按Ctrl-C。) - 查看
test2_run2标签。这将 a small change 引入 NPM 的index.js文件,以及一个版本 将其package.json撞到1.0.1。 - 做一个
docker-compose build。 只有直到COPY ./my-npm ...的指令才应该使用缓存。(例如,docker 输出为该指令打印---> Using cache。)所有后续步骤都应由 docker 运行。这是因为在步骤 7 中对 NPM 包引入的更改应该使COPY ./my-npm ...命令的缓存无效,因此,后续步骤也会失效。确认在npm install命令期间,新版本的 NPM 打印在摘要树输出中,例如+-- my-npm@1.0.1。 - 做一个
docker-compose up。浏览至http://localhost:8000。该页面应报告版本1.0.1。
预期行为:第 9 步中的页面应报告 1.0.1。也就是说,本地 npm 的变化应该通过docker-compose up 反映在容器中。
实际行为:第 9 步中的页面报告 1.0.0。
请注意,docker 本身正在按预期重新构建图像。 观察到的问题不是 docker 重新使用缓存的图像作为输出
显示它重新运行 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$
解决方法:使用docker rm 删除dctest_service1 容器。然后重新运行docker-compose up,它将使用现有图像重新创建容器。在此步骤中值得注意的是,没有重新构建任何底层图像。在重新创建容器时,docker-compose 似乎想出使用更新后的 node_modules 的新卷。
查看output 目录,了解第一次运行(步骤 4 和 5)和第二次运行(步骤 8 和 9)期间打印的输出。
原帖
我有一个基于this tutorial ("Lessons from Building a Node App in Docker") 的nodejs Dockerfile。具体来说,请注意本教程使用卷技巧从容器本身挂载node_modules 目录,以覆盖在主机上的等效目录之上。例如:
volumes:
- .:/home/app/my-app
- /home/app/my-app/node_modules
我遇到了一个问题,即 package.json 的更新按预期触发了 npm install(与使用 docker 缓存相反),但是当使用 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",
HostConfig -> 绑定
我不确定这是否相关,但我也注意到(也在docker inspect 中)HostConfig 下的Binds 部分在两种情况下有所不同:
容器通过“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"
],
(两者都显示安装在映像上的主机源,但只有“向上”显示带有node_modules 的辅助覆盖卷,这似乎是另一个奇怪的皱纹。)
理论
根据docker-compose CLI reference:
如果存在服务的现有容器,并且该服务的 容器创建后配置或图像被更改, docker-compose up 通过停止并重新创建 容器
因此,docker-compose up 似乎不认为配置或图像已更改。我只是不确定如何调试它来确认。当然,我可以使用--force-recreate 来解决这个问题,但我希望解决我的配置不正确导致问题的原因。
更新:如果我在docker-compose up 之前执行明确的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-compose.yml文件吗?所以我们可以将该文件与您的Dockerfile进行比较。请参阅下面的答案 -
@Pitt 文件很大。话虽如此,我注意到如果我通过“docker rm
”删除容器,那么当 d-c 构建时,它会使用正确的图像来创建容器。所以关于 d-c 的某些东西导致它没有意识到底层图像已被更改。我将创建一个更小/更简单的项目来尝试和重现。 -
我仔细查看了您链接的教程,如果您的 docker-compose.yml 使用使用指令
build: .这意味着它不仅仅使用预构建映像来实例化您的 docker 容器将构建.(当前)目录。因此,如果您更改某些内容,则必须在运行docker-compose run之前运行docker-compose build,否则将使用较旧的缓存构建。 -
另外,如果你只想使用一个命令,你可以使用
docker-compose up --build。要真正了解发生了什么,您必须发布您使用的完整docker run命令,以及定义您要运行的服务的docker-compose命令和docker-compose.yml文件。 -
@Pitt - 我不确定你是否看到了我的“更新” - 但似乎构建,无论是否明确,都不能解决问题。
标签: node.js npm docker-compose