Containers are everywhere, and it's relatively easy to get started with Docker -
if you follow the right learning sequence.
This skill path starts with the basics of the docker run
command and gradually builds up to more advanced concepts.
You'll learn how to:
- Run different types of containerized applications (servers, databases, CLI tools, etc.)
- Send data to a container's STDIN and run interactive shells inside containers
- Execute commands in running containers (container debugging 101)
- List containers, check their statuses, and inspect their details
- Create, start, pause, unpause, stop, restart, kill, and remove containers
By the end of this skill path, you'll develop an intuition for the container lifecycle - paving the way for more advanced topics like container orchestration.

Run Your First Containers
Getting started with Docker is almost trivial - all you need are basic command-line skills. This challenge will walk you through running your first Hello World, a simple web server, and even an interactive shell container. Just follow the steps, and you'll be running containers in no time!
Run a Container in Background and Access Its Logs
The polished UX of the docker run
command makes it easy to forget that containers aren't just regular foreground processes.
Under the hood, running a container involves a client–server interaction:
the docker
CLI, acting as a foreground client, communicates with the dockerd
daemon,
which in turn delegates container management to lower-level runtimes such as containerd
and runc
.

This layered architecture allows you to run containers in the background by detaching the current terminal session from the containerized application's stdio streams. In fact, most real-world containerized applications run as background processes - so it's essential to be fluent in starting, inspecting, and reconnecting to detached containers.
In this challenge, you'll practice running a container in the background, reading its logs, and reattaching to its stdio streams:
Run a Container Overriding its Default Command
Some container images include more than one executable file, and you may want to run a container using other than the default command and/or pass some arguments to it. This is a quite common scenario, and many of the following steps in the skill path expect you to know how to do it, so despite being a very basic skill, it's essential to acquire it before moving on.
Run a Containerized CLI Tool and Send Data to Its STDIN
Container images often ship with CLI tools.
A very popular example is database clients,
such as psql
or redis-cli
, included in the corresponding database server images.
In this challenge, that builds upon the understanding of the docker run
command's implementation,
you'll practice running a containerized CLI tool and sending data to its STDIN:
Run a TTY-controlled Container
Some applications like REPLs (e.g., python
, node
, etc.) or text editors (e.g., vim
, nano
, etc.) require a controlling terminal for proper screen output and signal handling.
However, containers are always background daemon-like processes,
even when you run them in the attached mode (making them look like foreground processes).
Thus, if you want to run an interactive application in a container, you need to allocate a pseudo-TTY (terminal) for it.

In this challenge, you'll practice running an application that requires a controlling terminal and explore how it reacts to terminal resize events:
Run an Interactive Shell Container
Running shells in containers is an extremely common scenario. For instance, you may want to do it to when you need to quickly spin up a Linux distribution other than your current host, or to explore the filesystem of a containerized application.
Combine the skills from the previous challenges to override the container's entrypoint and run an interactive shell instead of the default command:
Pass Environment Variables to Containers
Containers are isolated execution environments, which means any environment variables set in your host shell session won't be visible to the process(es) running in the container.

In this challenge, you'll practice probably the most common way to configure a containerized application - passing environment variables to a container:
Docker Run and Exec - What is the Difference?
Loading tutorial...
So far, you've only used the docker run
command, which always starts a new container.
However, sometimes, you may want to run a command in an existing container,
or to start an interactive shell in it.
This is where the docker exec
command comes in.
This tutorial explores the difference between docker run
, docker attach
,
and docker exec
to help you understand when to use each one.
Execute Commands in a Running Container
The docker exec
command is an essential tool for troubleshooting and debugging containers,
so it's worth understanding how it works under the hood before adding it to your toolbox.

In this challenge, you'll practice using docker exec
to access an internal debug interface of a containerized application:
The Philosophy Behind Docker Container Commands
Loading tutorial...
Now that you've run your first containers, it's a good time for a short theory lesson on the philosophy behind the Docker container management commands.
The key takeaway is that containers are as much about the processes running inside them as they are about the files and directories they contain.
That's why some of the Docker commands sound like process management operations (e.g. start
, stop
, kill
, etc.),
while others sound more like operations on files (e.g. create
, update
, rm
, etc.).
List Containers and Identify Statuses
Time to put the theory from the previous unit into practice. In this challenge, you'll learn how to list and inspect containers to distinguish running, exited, and failed tasks:
How Container Filesystem Works
Loading tutorial...
When you create (or run) a new container, Docker extracts its future root filesystem from a container image, and stores it on the host as a regular folder, potentially uncompressing and "squashing" the image layers on the way.
This tutorial dives pretty deep into the internals of the container filesystem preparation, so you may want to skip through the most advanced parts if you're not interested in the details.
The main goal is to shed enough light on the process to show that there is no magic behind the scenes, and everything boils down to standard Linux commands and filesystem operations.
Stop and Restart a Container Preserving Data
When you stop and then restart the container, Docker reuses the same writable layer (and any attached volumes), so application state and data persist across restarts even though the process gets a new PID.

In this challenge, you'll gracefully stop, restart, and finally remove an app container, validating that application data persists across restarts but is wiped clean when the container is removed:
Restart Containers on Failure Automatically
Sometimes, containers exit unexpectedly - due to bugs in the application code or external factors (OOM events, host reboots, etc.). Luckily, Docker and most other container runtimes provide a way to configure an automatic restart policy for a container.
In this challenge, you'll configure a restart policy to auto-recover the container on crash, and then trigger a failure to see the policy in action:
Signal a Containerized Application
Signals can be used not only to terminate or forcefully kill applications, but also to influence their behavior. For example:
- Nginx will reload its configuration and reopen log files upon receiving
SIGUSR1
. - HAProxy and Gunicorn will reload their configuration upon receiving
SIGHUP
. - Custom apps may implement
SIGUSR1
/SIGUSR2
handlers for debug dumps.
In this challenge, you'll practice sending a signal to a containerized application, the Docker-native way:
Pause and Unpause a Containerized Application
Pausing a container suspends its process(es) using the cgroups freezer, keeping memory and state intact while CPU scheduling is halted. This is different from stopping, which completely terminates the container's process(es), because it allows to seamlessly resume the container's execution later.
Pausing can be useful during peak load hours for reducing the impact of the non-critical workloads, maintenance windows, or when you want to "stop the world" to investigate a security incident or troubleshoot a bug.
In this challenge, you'll pause and unpause a running container, inspecting its state on both sides of the operation:
Full Container Lifecycle - Create to Remove
The docker run
command is a handy way to quickly spin up a container,
but many real-world use cases require more granular control over the container lifecycle.
Understanding the key states and operations on containers is essential for working with Docker
(and other container runtimes like containerd or Kubernetes) efficiently.

In the capstone challenge of this skill path, you'll walk through the full lifecycle of a single container using granular container management commands and observing how the container's status, PID, and the root filesystem change throughout the state transitions:
Level up your Server Side game — Join 14,000 engineers who receive insightful learning materials straight to their inbox