【问题标题】:docker-compose "up" vs. "run" yields different mounted volumedocker-compose "up" 与 "run" 产生不同的挂载卷
【发布时间】: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 覆盖在第一个卷的顶部。

复制步骤

  1. 克隆this repo
  2. 通过docker rmdocker rmi 清理与此repo 项目相关的任何以前的容器和图像。
  3. 查看test2_run1 标签。此状态表示使用本地 NPM 依赖项的 1.0.0 版本的项目。
  4. 做一个docker-compose build。如果正确执行了第 2 步,则所有步骤都应在不使用任何缓存的情况下运行。 在 npm install 命令期间注意本地 NPM 依赖项的版本,例如+-- my-npm@1.0.0.
  5. 做一个docker-compose up。浏览至http://localhost:8000。该页面应报告版本1.0.0
  6. 停止正在运行的容器。 (在发出up 命令的终端上按Ctrl-C。)
  7. 查看test2_run2 标签。这将 a small change 引入 NPM 的 index.js 文件,以及一个版本 将其package.json 撞到1.0.1
  8. 做一个docker-compose build只有直到 COPY ./my-npm ... 的指令才应该使用缓存。(例如,docker 输出为该指令打印 ---> Using cache。)所有后续步骤都应由 docker 运行。这是因为在步骤 7 中对 NPM 包引入的更改应该使 COPY ./my-npm ... 命令的缓存无效,因此,后续步骤也会失效。确认在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 反映在容器中。

实际行为:第 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


【解决方案1】:

命令 docker-compose 使用 docker-compose.yml 文件作为容器化 service 的配置文件。默认情况下,它会在您运行 docker-compose 的目录中查找此 .yml 配置文件。 因此,可能是您的 docker-compose.yml 文件不是最新的,当您运行 docker-compose up 时看到您的一个卷未安装。

docker run 忽略 docker-compose.yml 文件,只使用Dockerimage 构建容器。因此Dockerimage 文件和docker-compose.yml 文件之间可能存在配置差异。

【讨论】:

    猜你喜欢
    • 2020-07-05
    • 2018-09-24
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多