Docker is a tool that makes it easier for developers to create, deploy, and run applications using containers. Containers package your application code with all its dependencies. So, the application can run smoothly across different computing environments.
Think of a container as a lightweight, self-sufficient box that carries everything your application needs to operate.
Unlike virtual machines (VMs), which emulate an entire operating system, containers share the host system’s kernel. This makes them far more efficient in terms of resource use.
With Docker, you can run more applications on a single server and start them much faster than you could with VMs. Also, Docker guarantees consistency –– a container that works on your laptop will work the same way in the cloud.
In this tutorial, you’ll learn everything you need to set up a Docker container.
Prerequisites
To follow this tutorial, the first step is installing Docker on your machine. Here’s what you need to know:
Operating System Support: Docker works on the following:
macOS
Windows
Various Linux distros (Ubuntu, Debian, CentOS, etc.)
Specific Installation Instructions: The installation process differs depending on your OS. You can find the latest instructions for your specific OS on the official documentation site.
Regardless of your operating system, make sure your computer meets the general system requirements for running Docker. You can usually find these requirements listed on the installation page for your OS in the Docker documentation.
Key Docker Concepts
Before you go hands-on into using Docker, let’s get familiar with the building blocks of this technology. Here’s a quick overview of the essential elements:
Images
Docker images are like the blueprints for your applications. They contain everything needed to create a functional container:
The operating system
Your application code
Necessary libraries
Any special settings
You can find ready-made images for many popular tools on Docker Hub or create your own custom images.
Containers
Containers are running instances of your images. Think of them as lightweight, self-contained environments where your application lives. You can run multiple containers from the same image simultaneously, and each container operates independently.
Dockerfile
A Dockerfile is a special text file that contains a list of instructions on how to build a custom Docker image. It’s your recipe for crafting an image tailored to your specific application. Using a Dockerfile, you can define everything from starting the operating system to the exact steps needed to install and configure your software.
Pulling and Running Your First Container
One of the easiest ways to get a feel for Docker is to pull a pre-built image and run a container based on it. Let’s use Nginx, a popular web server, as our example:
Step 1: Pull the Image
The general syntax for pulling a Docker image is:
$ docker pull <image>:<image_tag>
Where:
docker pull
: core command to download a Docker image from a repository<image>
: name of the image you want to pull. For example,nginx
orubuntu
:<image_tag>
: an optional tag that specifies a particular version or variant of the image. Here are some common tags:latest
: the most recently updated version of the image (this is the default if you don’t specify a tagSpecific version numbers: for example,
1.23.1,
to get a precise versionOther tags: some images might have tags indicating their purpose like
alpine
(a small Linux distro)-slim
(a more minimal version of an image).
For example:
$ docker pull nginx:latest
latest: Pulling from library/nginx
f546e941f15b: Pull complete
2d258780861a: Pull complete
a7d6e9feb830: Pull complete
42e0f9421c7a: Pull complete
14a95f763a2f: Pull complete
164c21b63fde: Pull complete
5b452a5fd809: Pull complete
Digest: sha256:c26ae7472d624ba1fafd296e73cecc4f93f853088e6a9c13c0d52f6ca5865107
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
What's Next?
View a summary of image vulnerabilities and recommendations → docker scout quickview nginx:latest
The above command downloads the latest version of the Nginx image from Docker Hub. The Hub is a vast public repository where you can find images for many popular software, databases, and tools.
Images often have different tags, like latest
, or a specific version number (e.g., nginx:1.23.1
). Tags help you choose the most suitable version for your needs.
While using docker pull
, you’ll see output indicating multiple layers being downloaded. Images are built in layers, promoting efficiency. Each layer represents a change in the image’s filesystem. This layered approach means any updates often download just the changed layers, not the entire image.
Step 2: Run the Container
Here’s the general syntax for running a Docker container:
$ docker run <image_name>
Below is a breakdown of the syntax:
docker run
: command to start a new container based on a specific image<image_name>
: mandatory name of the image from which you want to create the container. If the image isn’t found locally, Docker will try to pull it from a registry (usually Docker Hub).
Furthermore, the docker run
command can be used with a variety of additional options like -d
, -p
, etc.) to customize the container’s behavior.
For example:
$ docker run -d -p 8080:80 nginx
Let’s break the command down:
-d
: runs the container in detached mode (it’ll run in the background)-p 8080:80
: maps port8080
of your host machine to port80
inside the container
Nginx, by default, listens on port 80
for web requests. This mapping allows you to interact with the webserver from your machine as if it were directly on your system.
Step 3: Test it Out
After implementing docker run
, the next step is to check if your Nginx server is functional. Open a browser and go to: http://localhost:8080
. You should see the Nginx welcome page.
Congratulations! You’ve successfully run your first Docker container.
Managing Docker Containers
Effective container management is crucial as you start using Docker more frequently. Here, we’ll explore some essential commands to help you view, stop, remove, and keep track of your running containers and images.
1. Listing Your Running Containers: docker ps
Let’s begin by understanding what containers are currently running on your system. The docker ps
command provides a convenient way to list them.
Here’s the basic syntax:
$ docker ps [OPTIONS]
Where:
docker ps
: is the base command to list containersYou can optionally use flags (denoted by
[OPTIONS]
) to customize the output. A common flag is-a
which shows all containers (including stopped ones)
For example:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e34b2345f7bd nginx "nginx -g 'daemon off;'" 2 hours ago Up 2 hours 0.0.0.0:8080->80/tcp my_nginx_container
This output shows a single running container named my_nginx_container
based on the nginx
image. It’s been running for 2 hours and has port 80
mapped to port 8080
on the host machine.
2. Stopping Running Containers: docker stop
When you need to halt a running container, the docker stop
command is your friend. Let’s take a look at the syntax:
$ docker stop [OPTIONS] CONTAINER [CONTAINER...]
Where:
docker stop
: base command to stop containersYou must provide one or more container IDs or names (found with
docker ps
)
For example:
$ docker stop e34b2345f7bd # Using the container ID
$ docker stop my_nginx_container # Using the container name
Docker attempts a graceful shutdown by sending a signal to the container’s main process. If the process ignores it, Docker resorts to a forceful termination after a timeout.
3. Removing Stopped Containers: docker rm
Stopped containers still consume disk space. The docker rm
command allows you to clean these up. Take a look at the basic syntax below:
$ docker rm [OPTIONS] CONTAINER [CONTAINER...]
Where:
docker rm
: base command to remove stopped containersYou must provide one or more container IDs or names
For example:
$ docker rm e34b2345f7bd 58df8a2168eb # Removing multiple containers by ID
Removing containers is permanent. If you think you might need a stopped container, don’t remove it.
4. Listing Your Images: docker images
It’s important to track the images stored on your system. The docker images
command provides a snapshot of those images. Below is the basic syntax of the command:
$ docker images [OPTIONS] [REPOSITORY[:TAG]]
Where:
docker images
: base command to list imagesIt optionally accepts
REPOSITORY[:TAG]
to filter the list to images with a specific name and tag combination
For example:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 760b7cbba31e 3 weeks ago 192MB
ubuntu latest a50ab9f16797 3 weeks ago 69.2MB
warpdotdev/warp 0.0.23 499fa48260b8 3 months ago 8.08MB
The output indicates we have three Docker images stored locally. There’s Nginx (a web server), Ubuntu (a Linux distro), and a custom image named “warp”. You can use these images as the base to launch new containers whenever needed.
Building Your Own Docker Image
While pre-built images for popular software are incredibly useful, the true power of Docker shines when you create images precisely tailored to your applications. This is where Dockerfile comes in.
The Dockerfile: Your Image Blueprint
A Dockerfile is a text file containing a series of instructions that tell Docker how to assemble your image. Some of the common instructions you’ll use include:
FROM
: specifies the base image to start from (e.g., Ubuntu, Python, etc.)WORKDIR
: sets the working directory for subsequent commandsCOPY
: copies files or directories from your computer into the imageRUN
: executes commands to install dependencies or configure your application within the imageCMD
: defines the default command that runs when a container starts from this image
The Build Process
Here’s a brief step-by-step process showing how to build your Docker image:
1. Create a Dockerfile: Place a file named, Dockerfile
in the root of your project directory.
2. Build the image: Use the docker build
command. Below is the basic syntax:
$ docker build -t <image_name>:<optional_tag> .
Where:
-t
: tags your image with a name and optional tag for versioning.
: specifies the location of your Dockerfile (`.` means the current directory)
Example
Let’s imagine you have a basic index.html
file. Here’s how you could build a Docker image to serve it using Nginx:
Dockerfile:
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
COPY index.html
RUN apk update && apk add curl
CMD ["nginx", "-g", "daemon off;"]
Let’s break down the content of the above file:
FROM nginx:alpine
: we’ll use a lightweight Alpine-based Nginx image as our starting pointWORKDIR
: sets the working directory for any subsequent COPY, RUN, or CMD instructions. This keeps things organized within our imageCOPY index.html: this copies our
index.html` into the default Nginx web directory within the imageRUN
: executes a command during the image building process. Here, we are using Alpine's package manager (`apk`) to update the package lists and install thecurl
tool. This demonstrates how you can add necessary dependencies to your image.CMD
: specifies the default command to execute when a container starts from this image. This ensures Nginx runs in the foreground, keeping the container alive."-g", "daemon off;"
: tells Nginx to run in the foreground, instead of the background.
Now, let’s build the image. Open your terminal, navigate to your project directory and run:
$ docker build -t my-first-image .
Where:
docker build
: the command to build images from Dockerfiles-t my-first-image
: tags your image, giving it a name.
: final dot tells Docker to use the current directory as the location of your Dockerfile
To test, let’s run a container from our newly built image:
$ docker run -d -p 8080:80 my-first-image
Open http://localhost:8080
in your web browser to see your website!
Conclusion
In this tutorial, we’ve covered the essentials of the exciting world of Docker such as:
Understanding the difference between images and containers
Using Docker Hub to find pre-built images
Crafting your own custom images using Dockerfiles
Managing containers with core Docker commands
This foundation now opens the door to even more powerful concepts. You can explore more advanced concepts such as container networking, streamlining the management of complex applications with Docker Compose, and how to make your application data persistent using volumes.
Thanks for reading! If you found this article helpful (which I bet you did 😉), got a question or spotted an error/typo... do well to leave your feedback in the comment section.
And if you’re feeling generous (which I hope you are 🙂) or want to encourage me, you can put a smile on my face by getting me a cup (or thousand cups) of coffee below. :)
Also, feel free to connect with me via LinkedIn.