Cmd Vs Entrypoint In Dockerfile: Differences Explained

In a Dockerfile, both CMD
and ENTRYPOINT
instructions define which command gets executed when running a container. However, they serve different roles and behave differently when it comes to overriding their default behavior at runtime.
CMD
Purpose: The CMD
instruction provides default arguments to the ENTRYPOINT
or a default command to run when a container starts.
Behavior: If you do not provide a command or arguments when running a container, Docker uses the CMD
values. If you specify arguments after docker run <image>
, these arguments will override the CMD
specified in the Dockerfile.
Use Cases: It's ideal for setting a default command or setting default arguments that can be easily overridden when starting a container.
ENTRYPOINT
Purpose: The ENTRYPOINT
instruction sets the command that will be executed when the container starts. It is meant to set the primary command for the container.
Behavior: The ENTRYPOINT
makes a container run as if it were that command. Arguments passed to docker run <image>
are appended to the ENTRYPOINT
command.
Use Cases: It's used when you want to configure a container that will run as an executable. You can still override the ENTRYPOINT
at runtime using docker run --entrypoint
.
Combining CMD and ENTRYPOINT
You can use CMD
and ENTRYPOINT
together to set a default command and default parameters that can still be overridden with command-line arguments. For example, setting an ENTRYPOINT
defines the executable (command) and CMD
provides default arguments. When you pass additional arguments to docker run
, those arguments are passed to the ENTRYPOINT
.
Examples:
Using Only CMD
This simple Python app has 3 files, app.py
which serves the app usage instructions, add.py
which added all given numbers and mult.py
which multiply all given numbers.
# Using a Python base image
FROM python:3.8-slim
# Set the working directory
WORKDIR /app
# Copy application source code
COPY . /app
# Default command to run the application
CMD ["python", "app.py"]
Dockerfile
def main():
print("this program allows you to add or multiply numbers.")
print("Usage:")
print("python add.py <number1> <number2> ... <numberN>")
print("python mult.py <number1> <number2> ... <numberN>")
if __name__ == "__main__":
main()
app.py
import sys
def main():
# Check if at least two arguments are passed
if len(sys.argv) < 3:
print("Usage: python add.py <number1> <number2> ... <numberN>")
sys.exit(1)
total = 0
try:
# Iterate over each argument except the script name and sum them
for num in sys.argv[1:]:
total += int(num)
# Print the total sum
print(f"The sum is {total}")
except ValueError:
print("Please provide only integer numbers.")
if __name__ == "__main__":
main()
add.py
import sys
def main():
# Check if at least two arguments are passed
if len(sys.argv) < 3:
print("Usage: python mult.py <number1> <number2> ... <numberN>")
sys.exit(1)
total = 1
try:
# Iterate over each argument except the script name and sum them
for num in sys.argv[1:]:
total *= int(num)
# Print the total sum
print(f"The product is {total}")
except ValueError:
print("Please provide only integer numbers.")
if __name__ == "__main__":
main()
mult.py
After building the image with docker build -t <image_name>
we can use it with docker run
Running the image without arguments:

Running the image with the addition function and supplying numbers :

Running the image with the multiplication function and supplying numbers :

Using Only ENTRYPOINT
# Using Ubuntu base image
FROM ubuntu
# Install curl
RUN apt-get update && apt-get install -y curl
# Set the entrypoint as curl
ENTRYPOINT ["curl", "-s"]
Dockerfile
This sample image has one purpose only: fetch URLs that are given as arguments.
For example: let's fetch my gRPC blog post.

or my Load Balancing post

Using Both CMD and ENTRYPOINT
This example defines a number-fact fetcher image.
# Using Alpine Linux as the base image
FROM alpine:latest
# Install curl
RUN apk add --no-cache curl
# Copy the wrapper script into the image
COPY number-fact.sh /usr/local/bin/number-fact.sh
# Make the script executable
RUN chmod +x /usr/local/bin/number-fact.sh
# Set the entrypoint to use the wrapper script
ENTRYPOINT ["/usr/local/bin/number-fact.sh"]
# Provide the default argument
CMD ["42"]
Dockerfile
#!/bin/sh
# Concatenate the URL and the argument
curl -s "http://numbersapi.com/$1"
number fact fetch with an argument
When creating the image, i had to solve a small problem, arguments are being appended to the Entrypoint
command with a white space. For example if we were doing it plainy with Entrypoint ["curl", "-s",
http://numbersapi.com
/"]
and CMD ["42"]
it would run the command curl -s "
http://numbersapi.com/
42
with a white space before the number 42, resulting in an unexpected outcome.
Extracting the curl command to a .sh file and supplying it with the argument did the trick.
Let's run the image with 17

or with 12

[Always take facts you read online with a grain of salt.🧂]
Summary
Using only CMD offers the highest flexibility for overriding the executable and/or arguments.
Using only ENTRYPOINT restricts containers to a specific executable while allowing argument overrides.
Using both provides a balanced approach, allowing the container to operate as a specific application or tool with defaults that can be easily overridden or appended with additional arguments. This approach maximizes both flexibility and specificity in how the container operates.