Skip to main content

[SOLVED] Difference between RUN and CMD in a Dockerfile - docker

[SOLVED] Understanding the Difference Between RUN and CMD in a Dockerfile

In Docker, it is important for us to know the difference between RUN and CMD in a Dockerfile. These two commands have different jobs during the life of a Docker container. In this guide, we will look at these differences closely. This will help us understand when and how to use each command in our Dockerfiles.

What You Will Learn:

  • Solution 1 - Understanding RUN: Build-Time Instructions
  • Solution 2 - Understanding CMD: Run-Time Instructions
  • Solution 3 - Practical Example of RUN in a Dockerfile
  • Solution 4 - Practical Example of CMD in a Dockerfile
  • Solution 5 - When to Use RUN vs CMD in Your Dockerfile
  • Solution 6 - Common Mistakes with RUN and CMD
  • Conclusion

When we understand the small details between RUN and CMD, we can make better Dockerfiles. This also helps us build our Docker images faster. If we want to learn more about Docker commands and best ways to use them, we can check our articles on Docker Commands and Dockerfile Best Practices. Now let’s look into the details of RUN and CMD to improve our Docker skills!

Solution 1 - Understanding RUN: Build-Time Instructions

In a Dockerfile, the RUN instruction helps us to run commands while we build the image. This instruction lets us install packages, copy files, and set up the environment before we create the final image. The commands we write with RUN run during build time. The results get saved into the new image layer.

Usage of RUN

  • Syntax: The RUN command can be in two forms:
    • Shell form: This runs commands in a shell. We can link commands using operators like && or ||.

      RUN apt-get update && apt-get install -y curl
    • Exec form: This runs commands directly without a shell. We usually prefer this for better control over how the command runs.

      RUN ["apt-get", "install", "-y", "curl"]

Key Points

  • Layering: Each RUN command makes a new layer in the Docker image. This layering can change the size of the final image. It is better to combine many commands into one RUN statement. This way, we make fewer layers.

  • Caching: Docker saves the results of each RUN command. If we change a line in the Dockerfile, Docker will rebuild that layer and all layers after it. This can slow down build times.

  • Environment Variables: We can use environment variables in RUN commands. For example:

    ENV NODE_VERSION=14
    RUN curl -O https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz

Example

Here is an example of using the RUN instruction in a Dockerfile to set up a simple web server with Nginx:

FROM ubuntu:latest

# Install Nginx and clean up
RUN apt-get update && \
    apt-get install -y nginx && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# Copy the default configuration file
COPY nginx.conf /etc/nginx/nginx.conf

In this example, we combine many commands into one RUN statement. This way, we reduce the number of layers we create. It helps to make the image size smaller.

For more tips on optimizing Dockerfile instructions, we can check Docker Image Layering and Caching.

Understanding how the RUN command works is very important in Dockerfile instructions. This is especially true when we build images that need a special setup or configuration.

Solution 2 - Understanding CMD: Run-Time Instructions

In a Dockerfile, the CMD instruction tells what command should run by default when we start a container from the image. This is different from RUN, which runs commands while we are building the image. CMD is for run-time settings. So, it decides how the container acts when we launch it.

Key Characteristics of CMD

  • Default Command: CMD sets the main command for the container. If we give another command when running the container, it will replace the command in CMD.

  • Execution: The command from CMD runs inside the container. This means it can use the container’s file system and network.

  • Forms: We can write CMD in three forms:

    1. Exec Form: This is the best way. We write it like a JSON array. This form does not use a shell, so signals go straight to the executable.

      CMD ["executable", "param1", "param2"]
    2. Shell Form: This form runs the command in a shell. It is not as good because it handles signals differently.

      CMD executable param1 param2
    3. Parameter Form: We use this with ENTRYPOINT to give default arguments.

      CMD ["param1", "param2"]

Example of CMD in a Dockerfile

Here is an example of using CMD in a Dockerfile:

FROM ubuntu:latest

# Install necessary packages
RUN apt-get update && apt-get install -y curl

# Copy a script into the image
COPY start.sh /usr/local/bin/start.sh

# Make the script executable
RUN chmod +x /usr/local/bin/start.sh

# Use CMD to specify the default command
CMD ["/usr/local/bin/start.sh"]

In this example, when we start a container from this image, it will run the start.sh script located at /usr/local/bin/start.sh. If we want to change this command when we run the container, we can just give another command:

docker run myimage echo "Hello, World!"

When to Use CMD

  • We use CMD when we want to set the default action of our container.
  • It is good for apps that need a specific command to run when the container starts.

Important Considerations

  • If we do not use CMD, the container will not know what to run and will show an error.
  • We can only have one CMD instruction in a Dockerfile. If we write many CMD instructions, only the last one will work.
  • For more complicated apps, we can use ENTRYPOINT with CMD to make the container actions more flexible.

To sum up, knowing the CMD instruction is very important for deciding how our Docker container works when it runs. It goes well with the RUN instruction, which we use during the building phase. This helps us clearly see the difference between build-time and run-time actions in Dockerfiles. For more details about Dockerfile instructions, we can look at the differences between RUN and CMD.

Solution 3 - Practical Example of RUN in a Dockerfile

The RUN instruction in a Dockerfile is very important. It helps us run commands while we build the image. We can use it to install packages, change settings, or do other tasks that prepare our application before the container runs. Here is a simple example to show how RUN works in a Dockerfile.

Example: Using RUN to Install Packages

Let’s say we want to make a Docker image for a Node.js application. We need to install Node.js and some other tools. Below is an example Dockerfile that shows how to use the RUN instruction.

# Use the official Node.js image as the base image
FROM node:14

# Set the working directory inside the container
WORKDIR /usr/src/app

# Copy package.json and package-lock.json to the working directory
COPY package*.json ./

# Use RUN to install dependencies
RUN npm install

# Copy the rest of the application code to the container
COPY . .

# Expose the application port
EXPOSE 3000

# Command to run the application
CMD ["node", "app.js"]

Breakdown of the Dockerfile

  1. Base Image:

    • FROM node:14: This line says we are using the official Node.js version 14 image as our base.
  2. Working Directory:

    • WORKDIR /usr/src/app: This sets where we will run commands in the container.
  3. Copying Files:

    • COPY package*.json ./: This copies package.json and package-lock.json to our working directory.
  4. Installing Dependencies:

    • RUN npm install: This line runs the npm install command to get all the tools we need from package.json. This step is very important for our application to work.
  5. Copy Application Code:

    • COPY . .: This copies the rest of our application files into the container.
  6. Expose Port:

    • EXPOSE 3000: This tells us that our application will listen on port 3000.
  7. Command to Run Application:

    • CMD ["node", "app.js"]: This sets the command that runs when the container starts. It will launch our Node.js application.

Key Points

  • The RUN instruction runs when we build the image. So any changes it makes will be part of the final image.
  • Each RUN command makes a new layer in the image. This can change the size of the image and how long it takes to build.
  • It is often a good idea to combine many RUN instructions into one command using &&. This can make the image smaller.

For more information on Dockerfile best practices, we can check out this article.

By knowing how to use the RUN instruction well, we can create good and functional Docker images that fit our application’s needs.

Solution 4 - Practical Example of CMD in a Dockerfile

In this part, we will look at how to use the CMD instruction in a Dockerfile with a simple example. The CMD instruction tells Docker what command to run by default when we start a container from the image. This is different from RUN, which runs commands while we build the image. CMD only runs when the container starts.

Syntax of CMD

We can use the CMD instruction in three ways:

  1. Exec form (preferred):

    CMD ["executable", "param1", "param2"]
  2. Shell form:

    CMD command param1 param2
  3. Multiple CMD instructions: Only the last CMD instruction will work.

Example of CMD in a Dockerfile

Here is a simple example of a Dockerfile that uses CMD to run a Python app:

# Use a base image with Python installed
FROM python:3.9-slim

# Set the working directory
WORKDIR /app

# Copy the application files into the container
COPY . .

# Install any necessary dependencies
RUN pip install -r requirements.txt

# Specify the command to run the application
CMD ["python", "app.py"]

Explanation of the Dockerfile

  1. FROM python:3.9-slim: This line says we are using a slim version of Python 3.9 as our base image.

  2. WORKDIR /app: This line sets the working directory inside the container to /app. This is where our app files will be.

  3. COPY . .: This command copies all files from the current folder on the host to the working directory in the container.

  4. RUN pip install -r requirements.txt: This command installs the Python packages we need from requirements.txt during the build.

  5. CMD [“python”, “app.py”]: This line tells Docker what command to run when the container starts. It runs the Python app app.py.

Running the Docker Container

After we build the image with the Dockerfile, we can run the container using:

docker build -t my-python-app .
docker run my-python-app

Important Notes

  • The CMD instruction is not a substitute for ENTRYPOINT, but we can use them together. For example, if we want to give default arguments to an ENTRYPOINT, we can use CMD for that.
  • If we give a command when running the container, it will replace the default command in CMD.

Using CMD the right way helps us define what our container does when it starts. This makes it very important to write Dockerfiles for apps. For more details about Dockerfile instructions, you can check out this guide.

In short, knowing how to use CMD in a Dockerfile is key for managing how containers behave.

Solution 5 - When to Use RUN vs CMD in Your Dockerfile

We need to understand when to use RUN and when to use CMD in our Dockerfile. This is important for making good Docker images. Both commands have different roles in a Docker container’s life. Choosing the right one can change how our application works and performs.

When to Use RUN

  1. Building the Image: We use RUN when we want to install packages or change the filesystem while we build the Docker image. This usually happens when we create the image.

    Example:

    FROM ubuntu:20.04
    RUN apt-get update && apt-get install -y \
        curl \
        git
  2. Creating Layers: Each RUN command makes a new layer in the Docker image. If the commands are for setting up the environment, like installing software, we should put them together in one RUN command. This helps to keep the number of layers low and makes the image smaller.

    Example:

    RUN apt-get update && \
        apt-get install -y python3 && \
        apt-get install -y python3-pip
  3. Not for Runtime Behavior: We should remember that RUN does not run when the container starts. It runs while we build the image. So, we should not use it for commands that need to run when the container starts.

When to Use CMD

  1. Default Command Execution: We use CMD to set the default command that will run when we start a container from the image. We can change this command by giving another command when we run the container.

    Example:

    CMD ["python3", "app.py"]
  2. Single Command: CMD is for running one command. If we need to run many commands, we can use a shell form with && or we can use a script.

    Example:

    CMD ["sh", "-c", "echo Hello World && exec python3 app.py"]
  3. Environment Configuration: We can use CMD to set the default environment for our application. It gives us flexibility to pass different arguments or commands when we run the container.

Summary of When to Use Each

  • Use RUN:

    • To install packages and change the image.
    • To make layers while building the image.
    • For commands that do not need to run when the container starts.
  • Use CMD:

    • To define the default command that runs when the container starts.
    • For commands that relate to how the application runs.
    • To allow for changing commands at runtime.

Knowing the difference between RUN and CMD helps us make our Dockerfile better for both image size and how it works when running. This knowledge is important for managing our Docker containers and images in development and production. For more tips on Docker commands, check our guide on Docker commands.

Solution 6 - Common Mistakes with RUN and CMD

When we work with Dockerfiles, it is very important to know the differences between RUN and CMD. If we do not understand, we can make mistakes that lead to inefficient images or errors when we run them. Below are some common mistakes we see developers make with these two commands.

Misunderstanding Usage Context

One big mistake is using RUN when we should use CMD, or using CMD when we should use RUN.

  • Using RUN for Runtime Commands: Sometimes, we mix up RUN and CMD. We think that commands meant to run when a container starts should go under RUN. But RUN runs commands while we build the image. The results get saved in the image. For example:

    RUN apt-get update && apt-get install -y curl

    This command installs curl when we build the image.

  • Using CMD for Build Commands: On the other hand, if we use CMD to install dependencies or set up the environment, it can make our images inefficient. For example:

    CMD apt-get update && apt-get install -y curl

    This command will not run when we build the image, so curl will not be ready when the container starts.

Overriding CMD with Docker Run

Another common mistake is not knowing that we can override the CMD instruction when we start a container. If we run a container like this:

docker run myimage mycommand

Then mycommand will replace the CMD in the Dockerfile. Many developers think that CMD will always run. This can lead to surprises. We should always check the command we use when starting a container.

Forgetting to Use ENTRYPOINT

A common oversight is not combining CMD and ENTRYPOINT. If we want a default command to always run, we should use ENTRYPOINT with CMD. For example:

ENTRYPOINT ["python"]
CMD ["app.py"]

Here, python is the entrypoint, and app.py is the default argument. If we want to run a different script, we can do it when we start the container:

docker run myimage another_script.py

Not Using Shell Form vs. Exec Form

Using the wrong form can cause problems. The shell form (CMD command) runs in a shell. This has different behavior than the exec form (CMD ["executable", "param1", "param2"]). For example, using shell form might not pass environment variables correctly.

Ignoring Layer Caching

When we use many RUN commands, we should combine them to use layer caching. Each RUN command makes a new layer in the image. This can make our images bigger and slow down build times if we do not optimize. For example:

RUN apt-get update
RUN apt-get install -y curl

We can combine this into one RUN command:

RUN apt-get update && apt-get install -y curl

Conclusion

If we avoid these common mistakes with RUN and CMD, we will have better Docker images and smoother container runs. By understanding the different roles of build-time and run-time commands, we can make our Dockerfiles better and avoid runtime problems. For more about Docker best practices, check out this resource. In conclusion, we need to understand the difference between RUN and CMD in a Dockerfile. This is important for making our Docker images and containers better.

We talked about how RUN runs commands when we build. CMD tells us what the default command is when we run the container. Knowing this helps us improve our Docker workflows. It makes everything work better and clearer.

For more help, check out our guides on locating data volumes in Docker and the difference between Docker and other technologies.

Comments