How to Build Docker Images with Dockerfile

By 

Updated on

8 min read

Dockerfile example used to build a Docker image on Ubuntu

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 .

CommandDescription
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 lsList all local images
docker rmi image-nameRemove an image
docker run -d -p host:container imageRun 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:

dockerfile
# Comment
INSTRUCTION arguments

INSTRUCTION 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 FROM argument. In this case, FROM can be preceded by one or more ARG instructions.
  • LABEL - Used to add metadata to an image, such as description, version, author, etc. You can specify more than one LABEL, and each LABEL instruction is a key-value pair.
  • RUN - The commands specified in this instruction will be executed during the build process. Each RUN instruction 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 ADD but 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 CMD instruction 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, and ADD instructions.
  • USER - Set the username or UID to use when running any following RUN, CMD, ENTRYPOINT, COPY, and ADD instructions.
  • 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.

Info
Docker Hub is a cloud-based registry service used for storing and distributing Docker images in public or private repositories.

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:

Terminal
mkdir ~/redis_docker

Navigate to the directory and create the following Dockerfile:

Terminal
cd ~/redis_docker
nano Dockerfile
Dockerfiledockerfile
FROM 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 1 defines the base image.
  • The RUN instruction on line 3 updates the apt index, installs the redis-server package, and cleans the apt cache.
  • The EXPOSE instruction defines the port on which the Redis server listens.
  • The CMD instruction 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:

Terminal
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:

output
[+] 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:latest

When the build process is completed the new image will be listed in the image list:

Terminal
docker image ls
output
REPOSITORY        TAG       IMAGE ID       CREATED          SIZE
linuxize/redis    latest    d8acc14d9b6b   2 minutes ago    148MB
ubuntu            24.04     a04dc4851cbc   5 days ago       78.1MB

If 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:

Terminal
docker run -d -p 6379:6379 --name redis linuxize/redis

The -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 :

Terminal
docker container ls
output
CONTAINER 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   redis

To verify that everything works as it should, use redis-cli to connect to the Docker container:

Terminal
redis-cli ping

The 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

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