The RUN, CMD, and ENTRYPOINT Dockerfile instructions are all used to run commands. However, there are two ways to specify the command to run:
- shell form; RUN yarn run build: The command is run inside a new shell process, which, by default, is /bin/sh -c on Linux and cmd /S /C on Windows
- exec form; RUN ["yarn", "run", "build"]: The command is not run inside a new shell process
The shell form exists to allow you to use shell processing features like variable substitution and to chain multiple commands together. However, not every command requires these features. In those cases, you should use the exec form.
When shell processing is not required, the exec form is preferred because it saves resources by running one less process (the shell process).
We can demonstrate this by using ps, which is a Linux command-line tool that shows you a snapshot of the current processes. First, let’s enter into our container using docker exec:
$ docker exec -it hobnob bash
root@23694a23e80b#
Now, run ps to get a list of currently-running processes. We are using the -o option to select only the parameters we are interested in:
root@23694a23e80b# ps -eo pid,ppid,user,args --sort pid
PID PPID USER COMMAND
1 0 root /bin/sh -c node dist/index.js
7 1 root node dist/index.js
17 0 root bash
23 17 root ps -eo pid,ppid,user,args --sort pid
As you can see, with the shell form, /bin/sh is run as the root init process (PID 1), and it is the parent process that invokes the node.
Ignore the bash and ps processes. Bash is the process we were using to interact with the container when we ran docker exec -it hobnob bash, and ps is the process we ran to get the output.
Now, if we update the RUN and CMD commands inside our Dockerfile to the exec form, we get the following:
FROM node:8
WORKDIR /root
COPY . .
RUN ["yarn"]
RUN ["yarn", "run", "build"]
CMD ["node", "dist/index.js"]
If we run this new image and enter into the container, we can run our ps command again, and see that the node process is now the root process:
# ps -eo pid,ppid,user,args --sort pid
PID PPID USER COMMAND
1 0 root node dist/index.js
19 0 root bash
25 19 root ps -eo pid,ppid,user,args --sort pid