How to Build Docker Images with Dockerfile

A Docker image is the blueprint of Docker containers that contains the application and everything you need to run the application. A container is a runtime instance of an image.
In this tutorial, we will explain what Dockerfile is, how to create one, and how to build a Docker image with Dockerfile.
The walkthrough below uses a practical Ubuntu 24.04 Dockerfile example so you can see the full build process from Dockerfile to running container.
Quick Reference
For a printable quick reference, see the Docker cheatsheet .
| Command | Description |
|---|---|
docker build -t name . | Build image from Dockerfile in current directory |
docker build -t name:tag . | Build with a specific tag |
docker build -f path/Dockerfile . | Use a custom Dockerfile location |
docker build --no-cache -t name . | Build without using the layer cache |
docker build --build-arg VAR=val . | Pass a build-time argument |
docker image ls | List all local images |
docker rmi image-name | Remove an image |
docker run -d -p host:container image | Run a container from an image |
What is Dockerfile
A Dockerfile is a text file that contains all the commands a user could run on the command line to create an image. It includes all the instructions needed by Docker to build the image.
Docker images are made up of a series of filesystem layers representing instructions in the image’s Dockerfile that make up an executable software application.
The Dockerfile takes the following form:
# Comment
INSTRUCTION argumentsINSTRUCTION is not case-sensitive, but the convention is to use UPPERCASE for its names.
Below is the list with a short description of some of the most used Dockerfile instructions:
- ARG - This instruction allows you to define variables that can be passed at build-time. You can also set a default value.
- FROM - The base image for building a new image. This instruction must be the first non-comment instruction in the Dockerfile. The only exception from this rule is when you want to use a variable in the
FROMargument. In this case,FROMcan be preceded by one or moreARGinstructions. - LABEL - Used to add metadata to an image, such as description, version, author, etc. You can specify more than one
LABEL, and eachLABELinstruction is a key-value pair. - RUN - The commands specified in this instruction will be executed during the build process. Each
RUNinstruction creates a new layer on top of the current image. - ADD - Used to copy files and directories from the specified source to the specified destination on the Docker image. The source can be local files or directories or a URL. If the source is a local tar archive, then it is automatically unpacked into the Docker image.
- COPY - Similar to
ADDbut the source can be only a local file or directory. - ENV - This instruction allows you to define an environment variable.
- CMD - Used to specify a command that will be executed when you run a container. You can use only one
CMDinstruction in your Dockerfile. - ENTRYPOINT - Similar to
CMD, this instruction defines what command will be executed when running a container. - WORKDIR - This directive sets the current working directory
for the
RUN,CMD,ENTRYPOINT,COPY, andADDinstructions. - USER - Set the username or
UIDto use when running any followingRUN,CMD,ENTRYPOINT,COPY, andADDinstructions. - VOLUME - Enables you to mount a host machine directory to the container.
- EXPOSE - Used to specify the port on which the container listens at runtime.
To exclude files and directories from being added to the image, create a .dockerignore file in the context directory. The syntax of the .dockerignore is similar to the one of the Git’s .gitignore file
.
For a complete reference and detailed explanation of Dockerfile instructions see the official Dockerfile reference page.
Ubuntu 24.04 Dockerfile Example
The most common scenario when creating Docker images is to pull an existing image from a registry (usually from Docker Hub) and specify the changes you want to make on the base image. The most commonly used base image when creating Docker images is Alpine because it is small and optimized to be run in RAM.
In this example, we will create a Docker image for the Redis server. We will use Ubuntu 24.04 as a base image.
First, create a directory that will contain the Dockerfile and all the necessary files:
mkdir ~/redis_dockerNavigate to the directory and create the following Dockerfile:
cd ~/redis_docker
nano DockerfileFROM ubuntu:24.04
RUN apt-get update && \
apt-get install -y redis-server && \
apt-get clean
EXPOSE 6379
CMD ["redis-server", "--protected-mode", "no"]Here is what each line in the Dockerfile does:
- Line
1defines the base image. - The
RUNinstruction on line3updates the apt index, installs theredis-serverpackage, and cleans the apt cache. - The
EXPOSEinstruction defines the port on which the Redis server listens. - The
CMDinstruction on the last line sets the default command that will be executed when the container starts.
Save the file and close the editor.
Building the Image
The next step is to build the image. To do so run the following command from the directory where the Dockerfile is located:
docker build -t linuxize/redis .The option -t specifies the image name and optionally a username and tag in the username/imagename:tag format.
The output of the build process will look something like this:
[+] Building 38.4s (6/6) FINISHED
=> [internal] load build definition from Dockerfile
=> [internal] load metadata for docker.io/library/ubuntu:24.04
=> [1/2] FROM docker.io/library/ubuntu:24.04
=> [2/2] RUN apt-get update && apt-get install -y redis-server && apt-get clean
=> exporting to image
=> => naming to docker.io/linuxize/redis:latest
Successfully built and tagged linuxize/redis:latestWhen the build process is completed the new image will be listed in the image list:
docker image lsREPOSITORY TAG IMAGE ID CREATED SIZE
linuxize/redis latest d8acc14d9b6b 2 minutes ago 148MB
ubuntu 24.04 a04dc4851cbc 5 days ago 78.1MBIf you want to push the image to Docker Hub see Pushing a Docker container image to Docker Hub .
Running a Container
Now that the image is created you can run a container from it by running:
docker run -d -p 6379:6379 --name redis linuxize/redisThe -d option tells Docker to run the container in detached mode, the -p 6379:6379 option publishes port 6379 to the host machine, and the --name redis option specifies the container name. The last argument linuxize/redis is the name of the image used to run the container.
When the container starts, use the following command to list all running containers :
docker container lsCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6b7d424cd915 linuxize/redis "redis-server '--pro…" 2 minutes ago Up 2 minutes 0.0.0.0:6379->6379/tcp redisTo verify that everything works as it should, use redis-cli to connect to the Docker container:
redis-cli pingThe Redis server should respond with PONG.
Troubleshooting
Cannot connect to the Docker daemon
The Docker service is not running, or your user does not have permission to access it. Start Docker with sudo systemctl start docker, or add your user to the docker group with sudo usermod -aG docker $USER and log out and back in.
pull access denied or manifest unknown
The base image in FROM does not exist or the tag is incorrect. Check the image name and tag on Docker Hub
and update the FROM line accordingly.
Build succeeds but changes are not reflected
Docker reuses cached layers by default. If you changed a file that is copied in early in the build, run docker build --no-cache -t name . to force a full rebuild.
Dockerfile not found
The build command must be run from the directory containing the Dockerfile, or you must specify its path with -f. For example: docker build -f path/to/Dockerfile ..
FAQ
What is the difference between CMD and ENTRYPOINT?ENTRYPOINT defines the main executable that always runs when the container starts. CMD provides default arguments that can be overridden at runtime. Use ENTRYPOINT for the command and CMD for its default flags, or use CMD alone for a fully overridable default command.
What is the difference between COPY and ADD?
Prefer COPY for copying local files and directories — it does exactly what it says. Use ADD only when you need its extra features: fetching a remote URL or auto-extracting a local tar archive. Using COPY makes Dockerfiles easier to reason about.
How do I reduce the size of a Docker image?
Use a smaller base image such as alpine instead of ubuntu. Combine RUN commands into a single layer and clean the package cache in the same step (as shown in the example above). For compiled applications, use multi-stage builds to keep only the runtime artifacts in the final image.
What is .dockerignore?
A .dockerignore file in the build context directory tells Docker which files and directories to exclude from the build context. This prevents large or sensitive files — such as node_modules, .git, or .env — from being sent to the Docker daemon and potentially ending up in the image.
Conclusion
This tutorial covered the basics of using Dockerfiles to build Docker images. To learn more about recommended best practices see Best practices for writing Dockerfiles .
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page