Docker RUN vs CMD vs ENTRYPOINT: Demystifying the Differences
Tags: webdev, beginners, docker, programming
Published: 2023-08-19 07:34:58

## Introduction 💡
Docker, with its powerful containerization capabilities, offers developers a versatile environment to package, distribute, and run applications seamlessly. However, the similarity in syntax between certain Docker instructions can often lead to confusion, especially for newcomers to the technology. In this article, we will delve into the distinctions between the **RUN**, **CMD**, and **ENTRYPOINT** instructions, with clear examples to help you navigate this Docker trio.

## A Quick Overview
- **RUN:** Executes commands in a new layer, creating a new image. Commonly used for installing software packages.
- **CMD:** Sets a default command or parameters that can be overridden when launching a Docker container.
- **ENTRYPOINT:** Configures a container to run as an executable.

Let's break down each of these instructions to better understand their roles and implications.

## Shell Form vs. Exec Form
Before exploring the instructions, it's crucial to differentiate between two forms of syntax: `shell form` and `exec form`. The choice of form significantly influences how instructions are executed.

## Shell form
```
<instruction> <command>
```
**Examples**
```docker
RUN apt-get -y update
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
```
When instruction is executed in shell form it calls `/bin/sh -c` under the hood and normal shell processing happens. For example, the following snippet in Dockerfile
```docker
ENV variable Tutorials
ENTRYPOINT echo “$variable”
```
when container runs as `docker run -it <image>` will produce output
```
Tutorials
```
Note that variable name is replaced with its value.

## Exec form
```
<instruction> ["executable", "param1", "param2", ...]
```
**Examples**
```docker
RUN ["apt-get", "install", "python3"]
ENTRYPOINT [“/bin/echo”, “Tutorials”]
CMD [“/bin/echo”, “Tutorials”]
```
When instruction is executed in exec form it calls executable directly, and shell processing does not happen. For example, the following snippet in Dockerfile
```docker
ENV variable Tutorials
ENTRYPOINT [“/bin/echo”, “$variable”]
```
when container runs as docker run -it <image> will produce output
```
$variable
```
Note that variable name is not substituted.

## How to run bash?
If you need to run bash (or any other interpreter but sh), use exec form with `/bin/bash` as executable. In this case, normal shell processing will take place. For example, the following snippet in Dockerfile
```docker
ENV variable Tutorials
ENTRYPOINT ["/bin/bash", "-c", "echo $variable"]
```
when container runs as `docker run -it <image>` will produce output
```
Tutorials
```
## RUN
The **RUN** instruction is commonly used for installing software packages or performing actions during image creation. It executes commands, adds a new layer, and commits the results. Multiple **RUN** instructions are often used in a Dockerfile.

#### RUN has two forms:
- `RUN <command>` (shell form)
- `RUN ["executable", "param1", "param2"]` (exec form)

(The forms are described in detail in Shell and Exec forms section above.)

**Examples**
```docker
RUN apt-get update && apt-get install -y \
  vim \
  tzdata \
  git \
  mercurial \
  subversion
```
## CMD
The **CMD** instruction specifies a default command to run when the container starts. It can be overridden by providing a command during container launch. If there are multiple **CMD** instructions, only the last one is effective.

#### CMD has three forms:
- `CMD ["executable","param1","param2"]` (exec form, preferred)
- `CMD ["param1","param2"]` (sets additional default parameters for **ENTRYPOINT** in exec form)
- `CMD command param1 param2` (shell form)

> The second one is used together with **ENTRYPOINT** instruction in exec form. It sets default parameters that will be added after **ENTRYPOINT** parameters if container runs without command line arguments. See **ENTRYPOINT** for example.

Let’s have a look how CMD instruction works. The following snippet in Dockerfile
```docker
CMD echo "Hello world" 
```
when container runs as `docker run -it <image>` will produce output
```
Hello world
```
but when container runs with a command, e.g., `docker run -it <image> /bin/bash`, **CMD** is ignored and bash interpreter runs instead:
```
root@7de4bed89922:/#
```
## ENTRYPOINT
The **ENTRYPOINT** instruction configures a container to run as an executable. It is similar to **CMD**, but the difference lies in how they handle command line parameters. **ENTRYPOINT** arguments are always used, while **CMD** arguments can be replaced by command line arguments when launching the container.

#### ENTRYPOINT has two forms:
- `ENTRYPOINT ["executable", "param1", "param2"]` (exec form, preferred)
- `ENTRYPOINT command param1 param2` (shell form)

When you use an `exec form` of **ENTRYPOINT** command, it will allow you to set additional parameters using **CMD** command. If you use it in `shell form`, it will ignore **CMD** parameters or any CLI arguments.

**Examples**
```docker
ENTRYPOINT ["/bin/echo", "Tutorials"]
CMD ["Docker"]
```
when container runs as `docker run -it <image>` will produce output
```
Tutorials Docker
```
but when container runs as `docker run -it <image> DockerTutorials ` will result in
```
Tutorials DockerTutorials
```

## Conclusion 🥂 
In summary, Docker's **CMD** offers flexible default commands that can be overridden, while **ENTRYPOINT** guarantees a fixed command execution. **RUN** builds image layers atop the base. These commands play pivotal roles in containerization. **CMD** prioritizes adaptability, **ENTRYPOINT** enforces steadfastness, and **RUN** constructs the image foundation. Understanding their nuances is crucial for effective Dockerfile composition and streamlined container management.

### The content is referenced from 
https://codewithyury.com/docker-run-vs-cmd-vs-entrypoint/.