Docker Training Course for the Absolute Beginner

Docker Images

Commands vs Entrypoint

In this article, we explore how Docker handles commands, arguments, and entrypoints, and how these affect container behavior. Understanding these differences is crucial for building images that run as expected.

Let's start with a simple example using the Ubuntu image. Consider the following commands:

docker run ubuntu
docker ps
# (No running container will appear.)
docker ps -a
# (The container will be shown in an "exited" state.)

When you run these commands, Docker creates a container from the Ubuntu image and launches it. However, because the container’s default process (typically bash) expects a terminal, it exits immediately when no terminal is attached. Unlike virtual machines, containers are designed to run a specific task or process (e.g., hosting a web server, application server, or database). Once that task completes or the process crashes, the container stops running.

Key Insight

Containers are meant to run specific tasks rather than continuously running processes. The default behavior of many images reflects this design philosophy.

Defining the Default Process in a Dockerfile

Most Docker images use the CMD instruction in their Dockerfile to specify the process that should run inside the container. For example:

  • Nginx image: Uses CMD ["nginx"] to start the Nginx server.
  • MySQL image: Uses CMD ["mysqld"] to launch the MySQL daemon.

Consider this excerpt from a Dockerfile that installs both Nginx and MySQL:

# Install Nginx.
RUN \
    add-apt-repository -y ppa:nginx/stable && \
    apt-get update && \
    apt-get install -y nginx && \
    rm -rf /var/lib/apt/lists/* && \
    echo "\ndaemon off;" >> /etc/nginx/nginx.conf && \
    chown -R www-data:www-data /var/lib/nginx

# Define mountable directories.
VOLUME ["/etc/nginx/sites-enabled", "/etc/nginx/certs"]

# Define working directory.
WORKDIR /etc/nginx

# Define default command.
CMD ["nginx"]

# Install MySQL server.
RUN rpmkeys --import https://repo.mysql.com/RPM-GPG-KEY-mysql \
    && yum install -y $MYSQL_SERVER_PACKAGE_URL $MYSQL_SHELL_PACKAGE_URL libpwquality \
    && yum clean all \
    && mkdir /docker-entrypoint-initdb.d

VOLUME /var/lib/mysql

COPY docker-entrypoint.sh /entrypoint.sh
COPY healthcheck.sh /healthcheck.sh
ENTRYPOINT ["/entrypoint.sh"]
HEALTHCHECK CMD /healthcheck.sh
EXPOSE 3306 33060
CMD ["mysqld"]

The Ubuntu image Dockerfile is structured similarly:

# Pull base image.
FROM ubuntu:14.04

# Install dependencies.
RUN \
    sed -i 's/# \(.*multiverse\)/\1/g' /etc/apt/sources.list && \
    apt-get update && \
    apt-get -y upgrade && \
    apt-get install -y build-essential software-properties-common && \
    apt-get install -y byobu curl git htop man unzip vim wget && \
    rm -rf /var/lib/apt/lists/*

# Add custom files.
ADD root/.bashrc /root/.bashrc
ADD root/.gitconfig /root/.gitconfig
ADD root/.scripts /root/.scripts

# Set environment variables.
ENV HOME /root

# Define working directory.
WORKDIR /root

# Define default command.
CMD ["bash"]

In this Ubuntu example, Docker launches bash as the default command. However, since Docker does not attach a terminal by default, the shell exits immediately, and the container stops.

Overriding the Default Command

You can override the default CMD by appending a new command to the docker run command. For example, running the Ubuntu container with the sleep command:

docker run ubuntu sleep 5

Here, the container runs the sleep program for 5 seconds before exiting.

Making the Change Permanent

If you prefer that your image always executes the sleep command when started, you can create a new image based on Ubuntu with an updated CMD:

FROM ubuntu
CMD ["sleep", "5"]

After building the image:

docker build -t ubuntu-sleeper .
docker run ubuntu-sleeper

The container runs sleep 5 each time it starts. However, if you want the flexibility to change the sleep duration without rebranding the image, you can override the CMD at runtime:

docker run ubuntu-sleeper sleep 10

While this works, the image name (ubuntu-sleeper) might misleadingly imply that the container always runs sleep.

Using ENTRYPOINT with CMD for Flexibility

The ENTRYPOINT instruction allows you to fix the executable while still providing flexibility for command-line arguments to override or extend the CMD settings. With ENTRYPOINT, any command-line arguments are appended to the entrypoint command.

For example:

FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]

When you run the container without additional arguments:

docker run ubuntu-sleeper

The container executes sleep 5. If you run:

docker run ubuntu-sleeper 10

Docker executes sleep 10, replacing the default operand defined in CMD with the provided one.

Important

If you define only ENTRYPOINT without a default CMD, the container may fail to execute properly if no command-line arguments are provided. For instance, removing CMD can result in errors like "sleep: missing operand".

Overriding Entrypoint at Runtime

If you need to change the entrypoint entirely—say, switching from sleep to a different executable like sleep2.0—you can override it at runtime using the --entrypoint option:

docker run --entrypoint sleep2.0 ubuntu-sleeper 10

In this case, the container executes sleep2.0 10.

Summary of Docker Commands and Dockerfile Configurations

Below is a summary table of key commands and their effects:

Command/ConfigurationDescriptionExample
Default CMD in Ubuntu containerExecutes bash but exits when no terminal is attacheddocker run ubuntu
Overridden CMD at runtimeReplaces default command with a specified one (e.g., sleep 5)docker run ubuntu sleep 5
Permanent CMD update in DockerfileBuilds an image with a permanent command changeCMD ["sleep", "5"]
Using ENTRYPOINT with CMDFixes the executable while allowing dynamic command-line argument replacementENTRYPOINT ["sleep"] & CMD ["5"]
Override ENTRYPOINT at runtimeReplaces the image's fixed executable with an alternative onedocker run --entrypoint sleep2.0 ubuntu-sleeper 10

Consolidated Dockerfile Example

Below is the consolidated Dockerfile example using both ENTRYPOINT and CMD:

# Dockerfile for Ubuntu sleeper image with ENTRYPOINT and CMD
FROM ubuntu
ENTRYPOINT ["sleep"]
CMD ["5"]

After building the image:

docker build -t ubuntu-sleeper .
  • Running without additional parameters:

    docker run ubuntu-sleeper
    

    Executes the command: sleep 5

  • Overriding the sleep duration:

    docker run ubuntu-sleeper 10
    

    Executes the command: sleep 10

  • Overriding the entrypoint and the sleep duration:

    docker run --entrypoint sleep2.0 ubuntu-sleeper 10
    

    Executes the command: sleep2.0 10

That concludes our exploration of Docker's CMD versus ENTRYPOINT. Happy containerizing!

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Environment Variables