RUN Instruction Reference
Execute commands in a new layer on top of the current image and commit the results
Syntax
The RUN instruction executes commands in a new layer on top of the current image and commits the results. The resulting committed image will be used for the next step in the Dockerfile.
The RUN instruction is one of the most frequently used instructions in Dockerfiles. It allows you to execute commands inside your container during the build process, such as installing packages, compiling code, or setting up the environment.
Each RUN instruction creates a new layer in your Docker image. The committed changes are then used in the next step of the Dockerfile. This layering mechanism is part of what makes Docker images efficient and enables caching during builds.
Forms of the RUN Instruction
The RUN instruction can be used in two forms:
The command is run in a shell, which by default is /bin/sh -c
on Linux or cmd /S /C
on Windows.
RUN apt-get update && apt-get install -y python3
The command is executed directly, without shell processing. This is the preferred form for RUN instructions in production Dockerfiles.
RUN ["apt-get", "update"]
RUN ["apt-get", "install", "-y", "python3"]
The exec form is parsed as a JSON array, which means that you must use double-quotes (") around words, not single-quotes (').
Description
The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
Layering RUN instructions and generating commits conforms to the core concepts of Docker where commits are cheap and containers can be created from any point in an image's history, much like source control.
The cache for RUN instructions isn't invalidated automatically during the next build. The cache for an instruction like RUN apt-get dist-upgrade -y
will be reused during the next build. The cache for RUN instructions can be invalidated by using the --no-cache
flag, for example docker build --no-cache
.
The cache for a RUN instruction can also be invalidated by changes to the instruction itself. If the RUN instruction is exactly the same as the previous build, the cached layer will be used. If any part of the RUN instruction changes, a new layer will be created.
For example, if a previously cached layer used the RUN instruction RUN apt-get update && apt-get install -y python
, and a new build uses RUN apt-get update && apt-get install -y python3
, the new build will not reuse the cached layer.
Examples
Basic Package Installation
Installing packages using the shell form:
FROM ubuntu:20.04
RUN apt-get update && apt-get install -y \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*
This updates the package lists and installs Python 3 and pip, then cleans up to reduce the image size.
Multiple Commands
Running multiple commands in a single RUN instruction:
FROM debian:bullseye-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
It's best practice to combine related commands in a single RUN instruction using && to create a single layer and reduce image size.
Using Exec Form
Running commands using the exec form:
FROM alpine:3.14
RUN ["apk", "add", "python3", "nginx"]
This uses the exec form to add packages in Alpine Linux without shell processing.
Running Shell Scripts
Creating and running a shell script:
FROM ubuntu:20.04
COPY setup.sh /
RUN chmod +x /setup.sh && /setup.sh
This copies a script into the container, makes it executable, and runs it.
Running as Different User
Running a command as a non-root user:
FROM node:18-alpine
USER node
WORKDIR /home/node/app
COPY --chown=node:node package*.json ./
RUN npm install
This runs npm install as the node user for better security.
Complex Build Operations
Compiling software from source:
FROM ubuntu:20.04 AS build
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git
WORKDIR /src
RUN git clone https://github.com/example/project.git . \
&& mkdir build \
&& cd build \
&& cmake .. \
&& make -j$(nproc) \
&& make install
This example shows how to use RUN commands to clone and compile a project from source.
Best Practices
- Chain commands: Combine multiple commands in a single RUN instruction using
&&
to reduce the number of layers and image size. - Clean up: Always clean up after package installations (e.g.,
rm -rf /var/lib/apt/lists/*
afterapt-get
) to reduce image size. - Use non-interactive flags: Include flags like
-y
for apt-get to avoid build interruptions. - Set versions explicitly: Specify exact versions of packages to ensure reproducible builds.
- Break long RUN instructions: Use backslashes (\) to break long RUN instructions into multiple lines for better readability.
- Prefer exec form in production: Use the exec form of RUN for more predictable behavior, especially in non-bash shells.
- Sort multi-line arguments: Sort multi-line arguments alphanumerically to avoid duplication and make maintenance easier.
- Use the buildkit cache: With Docker BuildKit, you can use
RUN --mount=type=cache
to cache dependencies between builds. - Consider layer size: Be mindful of the size of each layer created by RUN instructions, especially when working with large files.
Notes and Limitations
- Each RUN instruction creates a new layer in your Docker image, which increases the final image size.
- In the shell form, the command is run using
/bin/sh -c
on Linux orcmd /S /C
on Windows. - The exec form does not invoke a command shell, so normal shell processing does not happen. For example, environment variable substitution doesn't happen when using the exec form.
- If you want to use shell processing with the exec form, you can explicitly specify the shell, e.g.,
RUN ["/bin/bash", "-c", "echo $HOME"]
. - The cache for RUN instructions isn't invalidated automatically during the next build. Use
--no-cache
to force re-execution of all instructions. - In multi-stage builds, each stage has its own filesystem, so RUN instructions in one stage don't affect other stages.
- The maximum length of a single RUN instruction is limited to the maximum command length supported by the shell or executable being used.