Docker 101: Run and Manage Containers
Skill Path ( EasyMedium )

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.

Docker: Layered Architecture with the high-level dockerd, mid-level containerd, and low-level runc runtimes.

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.

docker run command under the hood: pulling the image, creating a container, attaching to the container, connecting the container to the network, and finally starting it.

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.

docker run command under the hood: Allocating a pseudo-TTY (terminal) for the containerized application.

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.

Containers are isolated execution environments: Environment variables set in the host shell session are not visible to 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.

docker exec command under the hood: executing a new process in the already running container, sharing the same namespaces and cgroups.

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.

Container rootfs is prepared from read-only image layers and an extra copy-on-write layer to persist any changes done by the containerized application.

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.

Container lifecycle: create, start, pause, unpause, stop, restart, kill, and remove a container.

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