

Sarthak Varshney is a Docker Captain, 5x C# Corner MVP, and 2x Alibaba Cloud MVP, with over six years of hands-on experience in the IT industry, specializing in cloud computing, DevOps, and modern application infrastructure. He is an Author and Associate Consultant, known for working extensively with cloud platforms and container-based technologies in real-world environments.
You know that feeling when you first sat behind the wheel of a car? Your instructor didn't just throw you onto the highway. They started in an empty parking lot, explained what the pedals do, why mirrors matter, and let you get a feel for the controls before anything serious happened.
That's exactly how we're going to learn Docker's three most fundamental commands: run, ps, and stop. And just like learning to drive, we'll start slow, explain everything, and build up your confidence before we do anything fancy.
Think of Docker containers like rental cars. The run command is how you pick up a car from the lot and start driving it. The ps command is like checking your driveway to see which cars you currently have. And stop is how you park the car and turn off the engine.
These three commands form the foundation of everything you'll do with Docker. Master these, and you're already halfway to understanding containerization.
For this lesson, we're using nginx. What's nginx? It's a web server—basically a program that serves web pages to browsers. It's what powers a huge chunk of the internet, from tiny blogs to massive websites.
Why nginx? Because it's simple, it does something visible (serves a webpage you can actually see), and it's perfect for learning. Plus, it won't break anything on your computer. It's the Honda Civic of web servers—reliable, well-understood, and perfect for beginners.
Let's start your first container. Open your terminal and type:
docker run nginx
Hit enter. What happens? Your terminal suddenly fills with text that looks something like this:
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete
a9edb18cadd1: Pull complete
589b7251471a: Pull complete
186b1aaa4aa6: Pull complete
b4df32aa5a72: Pull complete
a0bcbecc962e: Pull complete
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
Okay, what just happened? Let's break it down line by line, because this is important.
"Unable to find image 'nginx:latest' locally"
Docker just checked your computer to see if you already have nginx downloaded. You don't (it's your first time), so Docker says "no worries, I'll grab it for you."
"latest: Pulling from library/nginx"
Docker is now downloading nginx from Docker Hub, which is basically the app store for containers. The "latest" part means you're getting the most recent version. Think of it like downloading an app from the Apple App Store or Google Play.
Those "Pull complete" lines
Each line represents a layer being downloaded. Containers are built in layers, like a cake. Each layer adds something—the operating system files, the nginx program itself, configuration files, and so on. Docker downloads each layer separately, which makes updates faster later (it only needs to download changed layers).
The Digest and Status lines
These are just confirmation messages. The digest is like a fingerprint that proves you got the exact version of nginx you asked for. The status line tells you everything worked.
Now here's the thing—your terminal is stuck. You can't type new commands. Why? Because nginx is running in the foreground, and it's showing you its logs. You'll see something like:
2024/02/25 10:30:15 [notice] 1#1: using the "epoll" connection processing method
2024/02/25 10:30:15 [notice] 1#1: nginx/1.25.3
2024/02/25 10:30:15 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2024/02/25 10:30:15 [notice] 1#1: OS: Linux 5.15.0-91-generic
2024/02/25 10:30:15 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2024/02/25 10:30:15 [notice] 1#1: start worker processes
What's all this? These are nginx's startup messages. It's telling you what version it is, how it was built, and that it's starting its worker processes (the parts that actually handle web requests).
But here's the problem—you can't access this nginx server! It's running, but it's trapped inside the container. It's like having a car running in a locked garage. The engine works, but you can't drive it anywhere.
Press Ctrl+C to stop it. The container will shut down.
Let's try again, but this time with some flags that make nginx actually useful. Type this:
docker run -d -p 8080:80 --name my-nginx nginx
Whoa, that's a lot more stuff! Let's break down every single piece:
docker run — This is the command itself. You're telling Docker "I want to run a container."
-d — This stands for "detached mode." Remember how your terminal got stuck before? This flag tells Docker "run this container in the background." It's like starting your car and letting it idle while you do other things. Your terminal stays free for other commands.
-p 8080:80 — This is port mapping, and it's super important. Let me explain with an analogy.
Imagine your computer is an apartment building, and each container is an apartment. Each apartment has its own door (port). The container's nginx server is listening on door number 80 inside its apartment. But the outside world can't see apartment doors—they can only see the building's main doors.
The -p 8080:80 flag creates a connection between the building's door 8080 (your computer) and apartment door 80 (inside the container). When someone knocks on your computer's port 8080, Docker forwards that knock to the container's port 80.
Why 8080 and 80? Port 80 is the standard port for web servers. But your computer might already have something using port 80, so we use 8080 on the outside, which is a common alternative port for web traffic.
--name my-nginx — This gives your container a name. Without this flag, Docker assigns a random name like "quirky_galileo" or "boring_tesla." Naming it yourself makes it easier to reference later. It's like naming your car instead of just calling it "that blue sedan over there."
nginx — This is the image name. You're telling Docker which container image to use.
When you run this command, you'll see something short, like:
89f3d2a1e5c7b8d9a0f1e2c3d4b5a6f7e8d9c0b1a2f3e4d5c6b7a8e9d0f1a2b3
That long string is your container ID. It's like a license plate—a unique identifier for this specific running container. Don't worry about memorizing it; Docker lets you use the name instead.
Open your web browser and go to:
http://localhost:8080
You should see the nginx welcome page! It says "Welcome to nginx!" and gives you some basic info. Congratulations—you just ran your first real container that does something visible!
Now open a new terminal window (or tab) and type:
docker ps
You'll see output that looks like this:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
89f3d2a1e5c7 nginx "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp my-nginx
This is your container dashboard. Let's decode each column:
CONTAINER ID — That's the shortened version of the long ID you saw earlier. Docker shows you just the first 12 characters because that's usually enough to uniquely identify a container.
IMAGE — Which image this container is based on. In our case, nginx.
COMMAND — The command that's running inside the container. The "..." means it's truncated. The full command is longer, but you don't usually need to see all of it.
CREATED — How long ago you created this container. Time flies when you're learning Docker!
STATUS — Is it running? For how long? "Up 2 minutes" means it's been running successfully for 2 minutes.
PORTS — This is crucial. It shows you the port mapping we set up. "0.0.0.0:8080->80/tcp" means "port 8080 on all network interfaces (0.0.0.0) maps to port 80 inside the container, using TCP protocol." This is why you could access nginx in your browser.
NAMES — The name we gave it (my-nginx) or the random name Docker would have assigned.
If you run docker ps and see empty output (just headers but no containers), it means you have no containers currently running. But that doesn't mean you never ran any containers!
Try this:
docker ps -a
The -a flag means "all"—show me all containers, even the stopped ones. This is like looking at your entire driving history, not just your current trip.
You might see containers with STATUS like "Exited (0) 5 minutes ago". That means the container ran and then stopped. The (0) means it stopped cleanly without errors (any other number would indicate something went wrong).
Now let's stop our nginx container. Type:
docker stop my-nginx
Docker will respond with:
my-nginx
It's just echoing back the name to confirm which container it stopped. If you refresh your browser (http://localhost:8080), the page won't load anymore. The server has been stopped.
Run docker ps again:
docker ps
Empty! No running containers. But run docker ps -a:
docker ps -a
There's your nginx container, but now the STATUS shows "Exited (0) X seconds ago".
You might wonder—what if I used the container ID instead of the name? You totally can:
docker stop 89f3d2a1e5c7
Docker's smart enough to match on partial IDs. You could even do:
docker stop 89f
As long as those first few characters uniquely identify a container, Docker will figure out which one you mean.
There's also a docker kill command, but stop is gentler. Think of it like this:
docker stop — Politely asks the container to shut down. It sends a SIGTERM signal, giving the application inside time to finish what it's doing, save files, close connections, and exit gracefully. After 10 seconds, if the container hasn't stopped, Docker will force it to stop.
docker kill — Immediately terminates the container. It sends a SIGKILL signal, which is like yanking the power cord. No cleanup, no goodbye. Use this only when a container is frozen or won't respond to stop.
For 99% of situations, use stop. It's the professional way to do it.
Want to start your stopped container? You don't need to run the whole docker run command again. Just use:
docker start my-nginx
The container comes back to life with all the same settings you gave it before (same ports, same name, everything). Check with docker ps and visit http://localhost:8080 again—it's back!
This is different from docker run, which creates a brand new container every time. Using start resurrects an existing one.
Mistake #1: Forgetting the -d flag
You run docker run -p 8080:80 nginx and your terminal gets stuck showing logs. You can't run other commands. Remember the -d flag for detached mode!
Mistake #2: Port conflicts
You try to run a second nginx container on the same port:
docker run -d -p 8080:80 --name my-nginx2 nginx
Docker throws an error: "port is already allocated". You can't have two containers using the same external port. Change it to 8081 or 9090 or any other available port.
Mistake #3: Forgetting container names
You run several containers without naming them, then Docker gives them names like "angry_newton" and "sleepy_curie". Good luck remembering which is which! Always use --name for important containers.
Mistake #4: Thinking stopped containers are gone
You stop a container and assume it's deleted. Nope! It's still there, just not running. Use docker ps -a to see everything. To actually remove a container, you need docker rm (but that's a lesson for another day).
Here's everything we learned in one place:
# Run a container (basic)
docker run nginx
# Run a container properly (detached, with port mapping and name)
docker run -d -p 8080:80 --name my-nginx nginx
# See running containers
docker ps
# See all containers (including stopped ones)
docker ps -a
# Stop a container by name
docker stop my-nginx
# Stop a container by ID
docker stop 89f3d2a1e5c7
# Start a stopped container
docker start my-nginx
# Kill a frozen container (use sparingly)
docker kill my-nginx
Ready to test your knowledge? Here's your challenge:
If you can do all that without looking back at the notes, you've got the fundamentals down!
Think back to the driving analogy. You now know how to:
docker run)docker ps)docker stop)These three commands form the absolute foundation of working with Docker. Everything else builds on this. You're not just memorizing commands—you're understanding what containers are and how they behave.
The next steps would be things like:
But for now, practice these three commands until they feel natural. Run containers, check their status, stop them. Do it with different images (try docker run hello-world for a simple test). The more you practice, the more intuitive it becomes.
Remember—every expert Docker user started exactly where you are now, typing these same commands for the first time and figuring out what all those flags mean. You're on the right path.
Happy containerizing!