Using ENTRYPOINT vs CMD in Dockerfile
In Docker, there are two instructions for specifying what command should run when a container starts: CMD
and ENTRYPOINT
. They have different purposes and behaviors, and understanding the difference is important for container management.
Understanding ENTRYPOINT and CMD
ENTRYPOINT
: Defines the executable that will run when the container starts. It's harder to override at runtime.
CMD
: Provides default arguments for the ENTRYPOINT
or can specify the entire command if ENTRYPOINT
is not used. It's easy to override at runtime.
Let's explore the difference by creating two different Dockerfiles.
First, create a new Python script that accepts command-line arguments:
nano greeting.py
Add the following code:
import sys
print("Script started!")
if len(sys.argv) > 1:
print(f"Arguments provided: {sys.argv[1:]}")
for arg in sys.argv[1:]:
print(f"- {arg}")
else:
print("No arguments provided.")
print("Script finished!")
Save and exit nano.
Now, let's create a Dockerfile that uses CMD
:
nano Dockerfile.cmd
Add the following content:
FROM python:3.9-slim
WORKDIR /app
COPY greeting.py .
CMD ["python", "greeting.py", "default", "arguments"]
Save and exit nano.
Build the image:
docker build -t python-cmd -f Dockerfile.cmd .
Now, create another Dockerfile that uses ENTRYPOINT
:
nano Dockerfile.entrypoint
Add the following content:
FROM python:3.9-slim
WORKDIR /app
COPY greeting.py .
ENTRYPOINT ["python", "greeting.py"]
CMD ["default", "arguments"]
Save and exit nano.
Build the image:
docker build -t python-entrypoint -f Dockerfile.entrypoint .
Testing CMD vs ENTRYPOINT
Let's run containers from both images and observe the differences.
First, run a container using the CMD
image without additional arguments:
docker run --name cmd-container python-cmd
Output should be similar to:
Script started!
Arguments provided: ['default', 'arguments']
- default
- arguments
Script finished!
Now, run a container with the CMD
image but provide custom arguments:
docker run --name cmd-container-custom python-cmd hello world
Output:
Script started!
No arguments provided.
Script finished!
Notice that the entire command was replaced with hello world
, which are not passed as arguments to our script.
Now, let's run a container using the ENTRYPOINT
image without additional arguments:
docker run --name entrypoint-container python-entrypoint
Output:
Script started!
Arguments provided: ['default', 'arguments']
- default
- arguments
Script finished!
Finally, run a container with the ENTRYPOINT
image and provide custom arguments:
docker run --name entrypoint-container-custom python-entrypoint hello world
Output:
Script started!
Arguments provided: ['hello', 'world']
- hello
- world
Script finished!
This time, our arguments are properly passed to the Python script because ENTRYPOINT
defines the executable, and any additional arguments provided to docker run
are passed to that executable.
Best Practices
- Use
ENTRYPOINT
for containers that should always run a specific command (like our Python script)
- Use
CMD
to provide default arguments that can be easily overridden
- Combine both by using
ENTRYPOINT
for the command and CMD
for default arguments
Clean up the containers:
docker rm cmd-container cmd-container-custom entrypoint-container entrypoint-container-custom
You've now learned the difference between CMD
and ENTRYPOINT
in Docker, which is essential for controlling how your Python scripts run when a container starts.