Welcome back, future Docker master! In our last chapter, you learned how to bring containers to life using docker run, turning static images into active, isolated environments. That was a huge step! But what happens after a container is running? How do you stop it? Restart it? Peek inside? Or even clean it up when you’re done?
This chapter is all about becoming a master “container juggler.” We’ll dive into the essential commands and concepts for managing your Docker containers effectively. Think of it like learning to control the individual performers in your grand Docker circus. By the end of this chapter, you’ll be able to start, stop, pause, inspect, and remove containers with confidence, gaining full control over your containerized applications.
Ready to get hands-on and make your containers dance to your tune? Let’s dive in!
The Container Lifecycle: A Quick Overview
Before we start issuing commands, let’s quickly understand the different states a container can be in. Just like any application on your computer, Docker containers have a lifecycle:
- Created: You’ve issued a
docker createcommand (ordocker runimplicitly does this first), but the container isn’t actually running yet. It’s like building the stage for a performer, but they haven’t stepped onto it. - Running: The container is active, its primary process is executing, and it’s doing its job. The performer is on stage, lights are up!
- Paused: The container’s processes have been temporarily suspended. It’s still in memory, but not using CPU cycles. The performer has frozen in place, waiting for their cue.
- Exited: The container’s main process has finished executing, or it was explicitly stopped. The performer has left the stage. It’s still there, but not active.
- Removed: The container has been completely deleted from your system. The stage has been dismantled.
Understanding these states will help you choose the right command for the job!
Core Commands for Container Management
Let’s explore the essential Docker commands you’ll use daily to manage your containers. We’ll explain each one and then put them into practice.
docker ps - The “What’s Running?” Command
This is your go-to command to see which containers are currently active on your system.
- What it is:
docker ps(short for “process status”) lists all running containers. - Why it’s important: It’s the first thing you’ll type when you want to check if your application is up, or to get the ID/name of a container you want to interact with.
- How it functions: It queries the Docker daemon for information about active containers and displays it in a table format.
Key Flags:
-aor--all: Shows all containers, including those that have exited. Super useful for cleanup!-sor--size: Displays the total file size of each container.-qor--quiet: Only displays container IDs. Great for scripting!
docker start, docker stop, docker restart - Controlling Your Containers
These commands allow you to control the execution state of your containers.
- What they are:
docker start <container_id_or_name>: Starts one or more stopped containers.docker stop <container_id_or_name>: Gracefully stops one or more running containers.docker restart <container_id_or_name>: Stops and then starts one or more containers.
- Why they’re important: These are fundamental for bringing your applications online, taking them offline for maintenance, or simply giving them a fresh start.
- How they function:
start: Tells the Docker daemon to resume the main process of the specified container.stop: Sends aSIGTERMsignal (a polite request to shut down) to the container’s main process. If the process doesn’t shut down within a default timeout (usually 10 seconds), Docker will send aSIGKILL(a forceful termination).restart: Essentially performs astopfollowed by astart.
docker pause, docker unpause - Freezing Time
Sometimes you don’t want to stop a container, just temporarily freeze its operations.
- What they are:
docker pause <container_id_or_name>: Suspends all processes within one or more containers.docker unpause <container_id_or_name>: Unpauses all processes within one or more containers.
- Why they’re important: Useful for debugging, resource management, or taking a snapshot of a container’s state without fully stopping it.
- How they function: Docker uses Linux cgroups to suspend and resume all processes inside the container without terminating them.
docker rm - Cleaning Up Your Act
When you’re completely done with a container, you need to remove it to free up resources.
- What it is:
docker rm <container_id_or_name>removes one or more containers. - Why it’s important: Prevents clutter, reclaims disk space, and avoids naming conflicts.
- How it functions: Deletes the container’s writable layer and metadata from the Docker daemon.
- Critical Note: You can only remove stopped containers by default.
- Key Flag:
-for--force: Forces the removal of a running container. Use with caution, as it’s equivalent todocker stopfollowed bydocker rm.
docker logs - Listening to Your Containers
Containers often output information to their standard output (stdout) and standard error (stderr). This is where you find your application’s logs.
- What it is:
docker logs <container_id_or_name>fetches the logs of a container. - Why it’s important: Essential for debugging, monitoring application health, and understanding what your container is doing.
- How it functions: Retrieves the collected stdout/stderr output from the Docker daemon for the specified container.
- Key Flag:
-for--follow: Follows log output. Liketail -fon Linux, it will continuously stream new logs.
docker inspect - The Detective’s Tool
Need to know every detail about a container? docker inspect is your friend.
- What it is:
docker inspect <container_id_or_name>returns low-level information about Docker objects (containers, images, networks, volumes) in JSON format. - Why it’s important: Invaluable for debugging networking issues, checking resource limits, seeing exposed ports, or verifying configuration.
- How it functions: Queries the Docker daemon for comprehensive metadata about the specified object.
docker exec - Stepping Inside
Sometimes, you need to run a command inside a running container, perhaps to install a tool, check a file, or debug an issue.
- What it is:
docker exec <container_id_or_name> <command>runs a new command in a running container. - Why it’s important: Provides a way to interact with a running container without stopping and restarting it. It’s like SSH-ing into a tiny virtual machine.
- How it functions: The Docker daemon creates a new process inside the container’s existing environment and attaches to its standard input/output.
- Key Flags:
-ior--interactive: Keep STDIN open even if not attached. Essential for interactive shells.-tor--tty: Allocate a pseudo-TTY. Essential for interactive shells to get a proper terminal experience.- You’ll almost always use
-ittogether for interactive sessions.
Step-by-Step Implementation: Juggling an Nginx Container
Let’s put these commands into action! We’ll use a simple Nginx web server container for our demonstration.
For this chapter, we’ll assume you have Docker Desktop (or Docker Engine) installed and running. As of December 4th, 2025, the latest stable Docker Desktop version is likely Docker Desktop 4.26.x (or similar, following the typical monthly release cycle), bundling Docker Engine 25.x.x. You can always check the latest official releases at the Docker Desktop Releases GitHub page or the official Docker documentation.
1. Launch Our Nginx Performer
First, let’s start a new Nginx container. We’ll run it in detached mode (-d) so it runs in the background, and give it a memorable name (--name).
Open your terminal or command prompt and type:
docker run -d --name my-nginx -p 8080:80 nginx:latest
Explanation:
docker run: The command to create and start a new container.-d: Stands for “detached” mode. This means the container will run in the background, and your terminal will be free for other commands. Without this, the Nginx logs would stream directly to your terminal.--name my-nginx: Assigns the name “my-nginx” to our container. This makes it much easier to refer to than a random ID.-p 8080:80: This is crucial! It maps port 8080 on your host machine to port 80 inside the container. Nginx listens on port 80 by default. So, you can access Nginx viahttp://localhost:8080in your web browser.nginx:latest: The image we want to use.latestrefers to the most recent stable version of the Nginx image available on Docker Hub.
Go ahead and visit http://localhost:8080 in your web browser. You should see the friendly “Welcome to nginx!” page. Our performer is on stage!
2. See Who’s Running (docker ps)
Now, let’s check if our container is actually running.
docker ps
You should see output similar to this (your CONTAINER ID will be different):
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 nginx:latest "/docker-entrypoint.…" 5 seconds ago Up 4 seconds 0.0.0.0:8080->80/tcp my-nginx
What to observe:
CONTAINER ID: A unique identifier for your container.IMAGE: The image it was built from (nginx:latest).COMMAND: The command executed when the container started.CREATED: How long ago the container was created.STATUS: Crucially, it saysUp X seconds, confirming it’s running.PORTS: Shows our port mapping0.0.0.0:8080->80/tcp.NAMES: Our chosen name,my-nginx.
Now try docker ps -a. You’ll likely only see my-nginx unless you have other stopped containers from previous exercises.
3. Gracefully Stop the Container (docker stop)
Let’s tell Nginx to take a bow.
docker stop my-nginx
This command will send a SIGTERM signal to the Nginx process inside the container, giving it a chance to shut down cleanly. It usually takes a few seconds.
Now, check docker ps again:
docker ps
You should see no output, because my-nginx is no longer running!
But if you run docker ps -a:
docker ps -a
You’ll now see my-nginx listed, but its STATUS will be Exited (0) X seconds ago. This means it’s stopped but still exists on your system.
4. Bring it Back to Life (docker start)
Our Nginx performer is ready for an encore!
docker start my-nginx
Check docker ps again. You’ll see it’s Up and running! Refresh http://localhost:8080 and you’ll see the welcome page again.
5. Pause and Unpause (docker pause, docker unpause)
Let’s freeze our Nginx mid-performance.
docker pause my-nginx
Now, try refreshing http://localhost:8080. What happens? The page will likely hang or give a connection error, because Nginx is paused and not responding!
Check docker ps:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 nginx:latest "/docker-entrypoint.…" 2 minutes ago Up 2 minutes (Paused) 0.0.0.0:8080->80/tcp my-nginx
Notice the (Paused) in the status.
Time to unpause:
docker unpause my-nginx
Refresh your browser, and Nginx is back in action!
6. Peeking at the Logs (docker logs)
Let’s see what Nginx has been saying.
docker logs my-nginx
You’ll see a stream of access logs and possibly some startup messages. These are the standard output and error streams from the Nginx process inside the container.
Now, try to follow the logs in real-time:
docker logs -f my-nginx
While this command is running, go back to your browser and refresh http://localhost:8080 a few times. You should see new access log entries appear in your terminal!
Press Ctrl+C to stop following the logs.
7. Deep Dive with docker inspect
Let’s get all the juicy details about our Nginx container.
docker inspect my-nginx
This will output a large JSON object with tons of information: network settings, volumes, environment variables, image details, and much more.
Scroll through the output. Can you find:
- The
IPAddressof the container? (Hint: Look underNetworkSettings.Networks.bridge) - The
Pathto the Nginx executable? (Hint: Look underPathnear the beginning) - The port bindings? (Hint:
HostConfig.PortBindings)
This command is incredibly powerful for debugging and understanding the intricate details of your container’s configuration.
8. Stepping Inside (docker exec)
Now for some real magic: let’s run a command inside our running Nginx container. We’ll get an interactive shell.
docker exec -it my-nginx bash
Explanation:
docker exec: The command to execute a new process inside a running container.-it: The combination of-i(interactive) and-t(TTY) is crucial for getting a proper, interactive terminal session.my-nginx: The name of our target container.bash: The command we want to run inside the container (in this case, start a Bash shell).
You should now see your terminal prompt change, indicating you’re inside the Nginx container (e.g., root@a1b2c3d4e5f6:/#).
Try some basic Linux commands:
ls -l /usr/share/nginx/html
You’ll see the default Nginx HTML files.
To exit the container’s shell and return to your host terminal:
exit
9. Cleaning Up (docker rm)
Finally, when you’re done with a container, it’s good practice to remove it. First, we need to stop it if it’s running.
docker stop my-nginx
Now that it’s stopped, we can remove it:
docker rm my-nginx
If you try docker ps -a now, my-nginx should be gone!
What if it’s running and I want to remove it immediately? You can use the force flag, but remember, this is like pulling the plug:
# Don't run this if my-nginx is already removed!
# First, let's restart it for demonstration:
docker run -d --name my-nginx-force -p 8080:80 nginx:latest
docker ps
# Now, force remove it while it's running
docker rm -f my-nginx-force
docker ps -a # It should be gone
Mini-Challenge: Curl Your Way In!
Alright, container juggler, it’s your turn to shine!
Challenge:
- Run a new
ubuntu:latestcontainer in detached mode, naming itmy-ubuntu. - Using
docker exec, get an interactive Bash shell insidemy-ubuntu. - Inside the
my-ubuntucontainer, update its package list and install thecurlutility. - Still inside
my-ubuntu, usecurlto fetch the contents ofhttp://example.com. - Exit the container’s shell.
- Stop and remove your
my-ubuntucontainer.
Hint:
- Remember the
apt updateandapt install -y <package_name>commands for Ubuntu. - The
-itflags are your best friends for interactivedocker execsessions.
What to observe/learn:
- How
docker exectruly allows you to interact with a container’s internal environment. - That containers often start with minimal tools, and you might need to install extras for specific tasks.
- The temporary nature of changes made inside a container (these changes won’t persist if you remove and re-run the
ubuntuimage).
Take your time, try it out, and don’t worry if you hit a snag. That’s part of learning!
Click for Solution (if you get stuck!)
# 1. Run a new ubuntu:latest container
docker run -d --name my-ubuntu ubuntu:latest
# Verify it's running
docker ps
# 2. Get an interactive Bash shell inside my-ubuntu
docker exec -it my-ubuntu bash
# You are now inside the container. Your prompt will change.
# Example: root@<container_id>:/#
# 3. Update package list and install curl
# (Inside the container)
apt update
apt install -y curl
# 4. Use curl to fetch http://example.com
# (Inside the container)
curl http://example.com
# You should see the HTML content of example.com printed to your terminal.
# 5. Exit the container's shell
# (Inside the container)
exit
# You are now back in your host terminal.
# 6. Stop and remove your my-ubuntu container
docker stop my-ubuntu
docker rm my-ubuntu
# Verify it's gone
docker ps -a
Common Pitfalls & Troubleshooting
Even the best container jugglers drop a ball sometimes! Here are a few common issues you might encounter:
- “Error: No such container:
” : This usually means you’ve misspelled the container name/ID, or the container has already been removed.- Solution: Use
docker ps -ato list all containers (including stopped ones) and verify the correct name or ID.
- Solution: Use
- “Error response from daemon: You cannot remove a running container
. Stop the container before attempting removal or use -f” : You tried todocker rma container that’s still running.- Solution: First
docker stop <name>, thendocker rm <name>. Or, if you’re sure and want to force it, usedocker rm -f <name>.
- Solution: First
- “Error: container name “
” is already in use by container “ : You tried to”. You must remove (or rename) that container to be able to reuse that name.” docker run --name <name>but a container with that name already exists (even if it’s stopped).- Solution: Either choose a different name for your new container, or
docker rm <old_container_name>the existing one first.
- Solution: Either choose a different name for your new container, or
docker exec -it <container> bashdoesn’t give an interactive prompt: You might have forgotten the-itflags, or the container’s base image might not havebashinstalled (some minimal images only havesh).- Solution: Always use
-itfor interactive shells. Ifbashisn’t found, tryshinstead:docker exec -it <container> sh.
- Solution: Always use
Summary: You’re a Container Juggling Pro!
Wow, you’ve covered a lot of ground in this chapter! You’re no longer just running containers; you’re actively managing them, making them perform exactly as you wish.
Here’s a quick recap of the essential commands you’ve mastered:
docker ps: See what containers are currently running.docker ps -a: See all containers, including stopped ones.docker start <name>: Bring a stopped container back to life.docker stop <name>: Gracefully shut down a running container.docker restart <name>: Stop and then start a container.docker pause <name>: Temporarily freeze a container’s processes.docker unpause <name>: Resume a paused container.docker rm <name>: Remove a stopped container (use-fto force remove a running one).docker logs <name>: View a container’s output (use-fto follow in real-time).docker inspect <name>: Get detailed low-level information about a container.docker exec -it <name> <command>: Run a command inside a running container (e.g.,bashfor an interactive shell).
You’re building an incredible foundation for working with Docker. Knowing these commands is absolutely crucial for your day-to-day Docker operations, debugging, and maintaining a clean environment.
What’s next? So far, we’ve treated containers as individual, isolated units. But what if your application needs to talk to a database container, or another service? How do they find each other? In the next chapter, we’ll unravel the mysteries of Docker Networking, learning how containers communicate and connect to the outside world. Get ready to build multi-container applications!