Clear up the confusions with Dockerfile instructions
Tags: docker, dockerfile, containerisation, dockerfileinstructions
Published: 2023-03-19 07:04:18

Yes, We all get confusions while writing the Dockerfile for the first time on our own(without copying from internet ¯\(°_o)/¯ ). People usually get confused with CMD vs RUN, ENTRYPOINT VS CMD etc, So in this article we will try to resolve all the confusions.

Let's start with some basics,
A Dockerfile contains a set of instructions that are executed step by step when you use the docker build command to build the docker image. It contains certain instructions and commands that decide the structure of your image, contains information related to the packages and libraries to be installed in the container and many more.

Here is a list of all the important instructions that are extensively used in a Dockerfile and their functions.

![Dockerfile instructions](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tim9v3wyuyl8k2gz9wd2.png)

**Example:**

```
#To deploy a simple node.js app
FROM node:10
LABEL authors="Username"
# update dependencies and install curl
RUN apt-get update && apt-get install -y \
    curl \
    && rm -rf /var/lib/apt/lists/*
# Create app directory
WORKDIR /usr/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
COPY package*.json ./
# update each dependency in package.json to the latest version
RUN npm install -g npm-check-updates \
    ncu -u \
    npm install \
    npm install express 
# If you are building your code for production
RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 3000
CMD [ "node", "server.js" ]
```

Now let's learn more about each instruction,

**FROM**
The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions. The FROM command is of the form −
`FROM <image name>:<tag name>`
A FROM command allows you to create a base image which is actually an operating system, comes with necessary tools preinstalled. All the instructions executed after this command take place on this base image. It contains an image name and an optional tag name.
Example:
`FROM ubuntu
 FROM centos:7
 FROM python:3 `

**RUN**
A RUN instruction is used to run specified commands. Suppose,
we may need to install a bunch of packages & libraries which we will be required by our application to start, these can be installed using RUN.
A Dockerfile can have many RUN steps that layer on top of one another to build the image. But the efficient approach is to combine all the RUN instructions into a single one.
Some example of RUN commands are −
`RUN apt−get −y install vim
 RUN apt−get −y update`
we can chain multiple RUN instructions in the following way −
`RUN apt−get −y update \
  && apt−get −y install firefox \
  && apt−get −y install vim`

**CMD**
If you want to run a docker container by specifying a default command that gets executed for all the containers of that image by default, you can use a CMD command. In case you specify a command during the docker run command, it overrides the default one. Specifying more than one CMD instructions, will allow only the last one to get executed.

Example of a CMD command −
`CMD echo "Container is ready"`
If you specify the above line in the Dockerfile and run the container using the following command without specifying any arguments, the output will be “Container is ready”

`sudo docker run −it <image_name>`
`Output − “Container is ready”`
Note: In case you try to specify any other arguments such as /bin/bash, etc, the default CMD command will be overridden.

Do RUN and CMD can be used interchangeably?
Answer is NO!, 
RUN - command triggers while we build the docker image.
      Can be many, e.g. install multiple libraries
CMD - command triggers while we launch the created docker 
      Can only have 1, which is your execute start point (e.g. 
      ["npm", "start"], ["node", "app.js"])

**ENTRYPOINT**
The difference between ENTRYPOINT and CMD is that, if you try to specify default arguments in the docker run command, it will not ignore the ENTRYPOINT arguments. The exec form of an ENTRYPOINT command is −
`ENTRYPOINT [“<executable-command>”, “<parameter 1>”, “<parameter 2>”, ….]`

If you have used the exec form of the ENTRYPOINT instruction, you can also set additional parameters with the help of CMD command. For example −
`ENTRYPOINT ["/bin/echo", "Welcome"]
CMD ["Hello World!"]`

Running docker run command without any argument would output −
`Welcome Hello World!`

If you specify any other CLI arguments, “Hello World!” will get overridden.

**WORKDIR**
You can specify your working directory inside the container using the WORKDIR instruction. Any other instruction after that, in the Dockerfile, will be executed on that particular working directory only.

For example,
`WORKDIR /usr/src/app`
Sets the working directory to /usr/src/app inside the container.

**COPY**
This instruction allows you to copy a directory from your local machine to the docker container.
For example,
`FROM ubuntu
 WORKDIR /usr/src/app
 COPY ∽/Desktop/myapp .`

This would copy all the files inside the directory ∽/Desktop/myapp in your local machine to your current working directory inside the docker container.

**ADD**
Similar to COPY instruction, you can use ADD to copy files and folders from your local machine to docker containers. However, ADD also allows you to copy files from a URL as well as a tar file.
For example,
`ADD ∽/Desktop/myapp/practice.tar.gz /usr/src/app`
Would copy all the contents inside the tar file to /usr/src/app inside the container.

`ADD <URL such as a github url> <Destination path inside the container>`
This command would copy all the files inside the GitHub URL to the destination.

**EXPOSE**
The EXPOSE instruction inside the Dockerfile informs that the container is listening to the specified port in the network. The default protocol is TCP.

Example
`EXPOSE 8080`
Will map the 8080 port to the container.
You can use the −p flag with the docker run command to make the container listen to another container or the host machine.

**LABEL**
You can use a LABEL instruction to add description or metadata for a docker image. It's a key−value pair.

Example −
`LABEL description="This is a sample image"`