0

I made a simple hello world node.js application with the dockerfile

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

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

If I change the CMD to RUN in my dockerfile it still works. It is documented in dockerfile to use CMD as it will then start the node server upon the running of the container.

I would like to know what will happen underhood if I use RUN cmd instead of CMD. Basically what happens if I make a docker image which itself is in running state.

kalatabe
  • 2,909
  • 2
  • 15
  • 24
  • Does this answer your question? [Difference between RUN and CMD in a Dockerfile](https://stackoverflow.com/questions/37461868/difference-between-run-and-cmd-in-a-dockerfile) – tgogos Dec 12 '19 at 15:33

3 Answers3

4

RUN will execute a command during the build process. CMD is used as the default command when executing a container, as opposed to building. If you run node index.js in a RUN instruction, your build will never finish and you don't have a container to share with others.

Refer to the dockerfile documentation for more detail: RUN and CMD.

Relevant bits from that documentation:

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.


EDIT: using OP's index.json, package.json, and Dockerfile files, the docker image build does not complete when using RUN node index.js and does complete (as expected) when using CMD node index.js.

Contents of 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!')
})

Contents of 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"
  }
}

When using the Dockerfile as follows:

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

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

then the build hangs. Here is the output:

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!

This hangs indefinitely.

When using the Dockerfile

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

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

the build output is:

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
Community
  • 1
  • 1
jkr
  • 17,119
  • 2
  • 42
  • 68
  • I tried building the image after using RUN command, it does create an image. Also, after building the image I can even run the container and it listens to my localhost. This is where I am not clear about. – Debojit Kangsa Banik Dec 13 '19 at 02:33
  • Are you saying you used `RUN node index.js`, the build finished, and you were able to run the container? If you did, it's a misuse of `RUN`. `node index.js` should be executed when the container is run, so it should be in a `CMD` (or possibly `ENTRYPOINT`) instruction – jkr Dec 13 '19 at 05:35
  • Yeah, I did that. I know it's against documentation but I wanted to know if there are any repercussions of that. What are the possible problems which I might face because of it? – Debojit Kangsa Banik Dec 13 '19 at 06:13
  • I tried to reproduce your behavior with an `index.js` file from [here](https://codeburst.io/node-js-by-example-part-1-668376cd4f96), and the build does not pass `RUN nodex index.js` because it is running the server. To get a better answer, you will have to share a [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example). – jkr Dec 15 '19 at 15:46
  • My index.js is: https://pastebin.com/u9qhDJvU , package.json file is: https://pastebin.com/cURsvj0w & Dockerfile is mentioned above. – Debojit Kangsa Banik Dec 16 '19 at 02:46
  • @DebojitKangsaBanik - I cannot reproduce your behavior. please see my edits – jkr Dec 16 '19 at 16:19
  • Hi Jakub, the fault was from my side. I created a docker image with CMD node index.js with a tag as 'nodeapp', then I tried creating a docker image with RUN node index.js with the same tag 'nodeapp' and thought that the previous image was overwritten. Actually, as you rightly mentioned the image was never created as it hangs indefinitely. Sorry for the trouble. – Debojit Kangsa Banik Dec 17 '19 at 08:50
  • @DebojitKangsaBanik - no trouble. it's good to get to the bottom of these things. If this answer solved your question, you can click the green check mark select it as the solution. – jkr Dec 17 '19 at 14:43
1

The RUN step executes a temporary container with the provided command, waits for that command to exit, and then captures to changes to the container filesystem as another layer of the resulting image. It does not store the running processes, changes to environment variables, or any changes to the state of the shell since those are not written to the filesystem. It also does not capture changes to volumes since temporary containers are started with the volumes defined in the image, and changes to a volume are not applied the container filesystem. This is a build time step.

The CMD step replaces the existing default command that docker runs when the image is run as a container. Containers exist for as long as this command is running, and you can only have a single value for the command. If you define CMD a second time, the previous value is replaced. And if you start a container with an overridden command, the image value for CMD is ignored.

Therefore you want to separate the steps to modify the filesystem at image build time from the steps to perform when the container is run into RUN and CMD respectively.

BMitch
  • 231,797
  • 42
  • 475
  • 450
0

First of all, if you start any long-running process in build stage with RUN command your build process will be stuck.

The RUN command execute at build time and this is designed for build-time configuration and installation packages and tools, with RUN command your prepare your Docker image, for example installing npm modules and some other application dependency that will be available when the process is up in the container.

The CMD execute when you start the container, it does not execute at build time, CMD should be a long-running process to keep your container.

Adiii
  • 54,482
  • 7
  • 145
  • 148