如果我在 dockerfile 中写 运行 node index.js 而不是 CMD node index.js 会发生什么?

What happens if I write RUN node index.js instead of CMD node index.js in a dockerfile?

我用 docker 文件

创建了一个简单的 hello world node.js 应用程序
FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./

RUN npm install
COPY . .
EXPOSE 8080
CMD node index.js

如果我在 docker 文件中将 CMD 更改为 运行,它仍然有效。 docker 文件中记录了使用 CMD,因为它将在容器的 运行 上启动节点服务器。

我想知道如果我使用 运行 cmd 而不是 CMD 会发生什么。 如果我制作一个本身处于 运行 状态的 docker 图像,基本上会发生什么。

RUN 将在构建过程中执行命令。 CMD 执行 容器时用作默认命令,而不是构建。如果您在 RUN 指令中 运行 node index.js,您的构建将永远无法完成,并且您没有容器可与他人共享。

有关详细信息,请参阅 docker 文件文档:RUN and CMD

该文档中的相关位:

The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.

The main purpose of a CMD is to provide defaults for an executing container.


编辑:使用 OP 的 index.jsonpackage.jsonDockerfile 文件,docker 映像构建未完成使用 RUN node index.js 时并在使用 CMD node index.js.

时完成(如预期)

index.js 的内容:

//Load express module with `require` directive
var express = require('express')
var app = express()

//Define request response in root URL (/)
app.get('/', function (req, res) {
  res.send('Hello World!')
})

//Launch listening server on port 8081
app.listen(8080, function () {
  console.log('app listening on port 8080!')
})

package.json 的内容:

{
  "name": "dummy_nodejs_app",
  "version": "1.0.0",
  "description": "Node.js on Docker",
  "author": "Debojit",
  "main": "server.js",
  "scripts": {
    "start": "node server.js"
  },
  "dependencies": {
    "express": "^4.16.1"
  }
}

使用Dockerfile时如下:

FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./

RUN npm install
COPY . .
EXPOSE 8080
RUN node index.js

然后构建挂起。这是输出:

jakub@dash:/tmp/test-node$ docker build -t test .
Sending build context to Docker daemon  4.096kB
Step 1/7 : FROM node:10
 ---> d5680e53a228
Step 2/7 : WORKDIR /usr/src/app
 ---> Using cache
 ---> a4b4547833e5
Step 3/7 : COPY package*.json ./
 ---> Using cache
 ---> 2b19cc3e48a3
Step 4/7 : RUN npm install
 ---> Using cache
 ---> fe1f1e72d17d
Step 5/7 : COPY . .
 ---> eb6fe0e3d1a7
Step 6/7 : EXPOSE 8080
 ---> Running in e573b923fcb2
Removing intermediate container e573b923fcb2
 ---> b3590153eed7
Step 7/7 : RUN node index.js
 ---> Running in 08b408e6e6f3
app listening on port 8080!

这将无限期挂起。

使用 Dockerfile 时

FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./

RUN npm install
COPY . .
EXPOSE 8080
CMD node index.js

构建输出是:

jakub@dash:/tmp/test-node$ docker build -t test .
Sending build context to Docker daemon  4.096kB
Step 1/7 : FROM node:10
 ---> d5680e53a228
Step 2/7 : WORKDIR /usr/src/app
 ---> Using cache
 ---> a4b4547833e5
Step 3/7 : COPY package*.json ./
 ---> Using cache
 ---> 2b19cc3e48a3
Step 4/7 : RUN npm install
 ---> Using cache
 ---> fe1f1e72d17d
Step 5/7 : COPY . .
 ---> Using cache
 ---> fc036f428e34
Step 6/7 : EXPOSE 8080
 ---> Using cache
 ---> d1ede7276d34
Step 7/7 : CMD node index.js
 ---> Using cache
 ---> cf051929395b
Successfully built cf051929395b
Successfully tagged test:latest

首先,如果您在构建阶段使用 RUN 命令启动任何长 运行 进程,您的构建过程将被卡住。

RUN 命令在构建时执行,这是为构建时配置和安装包和工具而设计的,使用 RUN 命令准备你的 Docker 图像,例如安装 npm 模块和一些其他应用程序依赖项,当进程在容器中启动时这些依赖项将可用。

CMD在你启动容器时执行,它不会在构建时执行,CMD应该是一个很长的-运行进程来保持你的容器。

RUN 步骤使用提供的命令执行一个临时容器,等待该命令退出,然后捕获对容器文件系统的更改作为生成图像的另一层。它不存储 运行ning 进程、对环境变量的更改或对 shell 状态的任何更改,因为这些不会写入文件系统。它也不捕获对卷的更改,因为临时容器是使用映像中定义的卷启动的,并且对卷的更改不会应用到容器文件系统。这是构建时间步长。

当图像运行作为容器时,CMD步骤替换了现有的默认命令docker 运行s。只要此命令为 运行ning,容器就会存在,并且该命令只能有一个值。如果您第二次定义 CMD,则先前的值将被替换。如果您使用覆盖的命令启动容器,CMD 的图像值将被忽略。

因此,您希望将在镜像构建时修改文件系统的步骤与容器为 运行 时执行的步骤分开,分别为 RUNCMD