4 min read

Cmd Vs Entrypoint In Dockerfile: Differences Explained

Cmd Vs Entrypoint In Dockerfile: Differences Explained
“Now is no time to think of what you do not have. Think of what you can do with what there is.” The Old Man And The Sea


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.