Docker Images and Containers Explained

You've heard it a hundred times: "Just use Docker." But if you've never touched it before, the concepts can feel abstract. What even is a Docker image? What's a container? And why does everyone keep talking about "it works on my machine"?
This post will clear all of that up — with hands-on examples you can follow along with right now.
What is Docker?
Docker is a platform that lets you package your application and everything it needs (runtime, libraries, configs) into a single, portable unit — and run it consistently anywhere.
The classic problem it solves:
Developer: "It works on my machine!"
Server: "Well, it doesn't work here."Why? Because the developer's machine has Node 20, but the server has Node 16. Or the developer has a library installed globally that the server doesn't. Or the environment variables are different.
Docker fixes this by packaging everything the app needs into one bundle that behaves the same everywhere:
- Your laptop
- Your teammate's machine
- CI/CD pipeline
- Staging server
- Production
No more "works on my machine" problems.
Other Benefits
Onboard new teammates fast:
Instead of a 2-hour setup guide, they just run docker compose up and start coding. No need to install MySQL, Redis, Node, Java — all of it comes with the project.
Keep your machine clean:
Don't want to install PostgreSQL, Redis, or Java directly on your laptop? Run them in Docker containers. When you're done with a project, docker compose down -v --rmi all removes everything.
Installing Docker
macOS
Download Docker Desktop from the Docker website.
Windows
Download Docker Desktop from the Docker website.
Ubuntu / Linux
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Verify it works
docker infoOnce installed, run the classic smoke test:
docker run hello-worldIf you see "Hello from Docker!" — you're good to go.
What is a Docker Image?
An image is a read-only package that contains everything needed to run an app:
- The operating system layer (e.g. Ubuntu, Alpine Linux)
- The runtime (Node.js, Python, Java, etc.)
- Libraries and dependencies
- Your application code
- Configuration
Think of it like a shipping container template — it's a blueprint. You don't run the image directly; you create a container from it.
Images are Made of Layers
Every image is built up from layers stacked on top of each other:
Why layers matter:
- Caching — unchanged layers are reused. If you only change your app code, Docker doesn't re-download Node.js or re-install your dependencies.
- Sharing — if two images share the same base layer (e.g.,
ubuntu:22.04), Docker only stores it once on disk. - Immutable — you can't modify an existing image. You either build a new one or add a new layer on top.
Docker Hub: The Image Registry
Docker Hub is a public registry where thousands of ready-made images live. Need PostgreSQL? Just run:
docker pull postgres:15Docker downloads the official PostgreSQL 15 image from Docker Hub. You can also find images for Nginx, Redis, Node.js, Python, MySQL, and virtually any tool you'd need.
Listing and Removing Images
# See all images on your machine
docker images
# Remove an image
docker rmi nginx:1.25
# Remove all unused images
docker image pruneWhat is a Docker Container?
A container is a running instance of an image. The relationship is:
Image (blueprint) → Container (running app)You can create multiple containers from the same image:
nginx:1.25 image → container: web-1 (running)
→ container: web-2 (running)
→ container: web-test (stopped)Containers are isolated from each other and from the host system. They have their own filesystem, process space, and network interface. Yet they're much lighter than virtual machines — they start in seconds, not minutes, and use MBs of memory, not GBs.
Containers vs Virtual Machines
| Feature | Container | Virtual Machine |
|---|---|---|
| Size | MBs | GBs (full OS) |
| Startup | Seconds | Minutes |
| Isolation | Process-level | Hardware-level |
| Performance | Near-native | ~5–10% overhead |
| Density | Hundreds per host | Tens per host |
Containers share the host OS kernel, which is why they're so lightweight. VMs run a full guest OS on top of a hypervisor.
Running Your First Containers
Hello World
docker run hello-worldThis pulls the hello-world image (if not already downloaded) and runs a container from it.
Nginx Web Server
# Run Nginx and map host port 8080 to container port 80
docker run -p 8080:80 nginxOpen http://localhost:8080 in your browser — you'll see the Nginx welcome page.
The -p 8080:80 flag means: "forward traffic from host port 8080 into container port 80."
Run in Background (Detached Mode)
docker run -d --name my-nginx -p 8080:80 nginx-d runs the container in the background. --name my-nginx gives it a memorable name.
View Running Containers
docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f1b2c4d5e6 nginx ... 2 minutes ago Up 2 minutes 0.0.0.0:8080->80/tcp my-nginxStop and Remove
docker stop my-nginx
docker rm my-nginxOr force-remove a running container:
docker rm -f my-nginxBuilding Your Own Image (Dockerfile)
So far we've used images from Docker Hub. But how do you package your own app?
You write a Dockerfile — a script that tells Docker how to build your image.
Here's a simple Node.js example:
index.js:
const http = require('http');
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello from Docker!\n');
});
server.listen(3000, () => {
console.log('Server running on port 3000');
});Dockerfile:
FROM node:24
WORKDIR /app
COPY index.js .
EXPOSE 3000
CMD ["node", "index.js"]Build and run:
# Build the image (tag it as "my-app")
docker build -t my-app .
# Run a container from it
docker run -p 3000:3000 my-appVisit http://localhost:3000 — you'll see "Hello from Docker!"
What Each Dockerfile Instruction Does
| Instruction | Purpose |
|---|---|
FROM node:24 | Start from the official Node.js 24 image |
WORKDIR /app | Set the working directory inside the container |
COPY index.js . | Copy your file into the container |
EXPOSE 3000 | Document that the app listens on port 3000 |
CMD [...] | The command to run when the container starts |
Essential Commands Cheat Sheet
Images
docker pull nginx:1.25 # Download image
docker images # List local images
docker rmi nginx:1.25 # Remove image
docker build -t my-app . # Build from Dockerfile
docker image prune # Remove unused imagesContainers
docker run -d --name web -p 8080:80 nginx # Run container
docker ps # List running containers
docker ps -a # List all containers
docker stop web # Stop container
docker start web # Start stopped container
docker rm web # Remove container
docker rm -f web # Force remove running container
docker logs web # View logs
docker logs -f web # Follow logs
docker exec -it web bash # Open shell inside container
docker container prune # Remove all stopped containersSystem Cleanup
docker system df # Check disk usage
docker system prune # Remove unused resources
docker system prune --volumes # Include volumes in cleanupCommon Mistakes
Using :latest in Production
# Risky — "latest" changes without notice
docker run nginx:latest
# Safe — pin to a specific version
docker run nginx:1.25.3Storing Data Inside Containers
Containers are ephemeral — when you docker rm a container, all data inside it is gone. For databases, always use volumes:
# Bad — data lost when container is removed
docker run postgres:15
# Good — data persists in a named volume
docker run -v pgdata:/var/lib/postgresql/data postgres:15Not Cleaning Up
Containers, images, and volumes accumulate quickly. Run this periodically:
docker system prune --volumesSummary
✅ Docker packages apps and their dependencies into portable containers
✅ An image is a read-only blueprint; a container is a running instance
✅ Images are built from layers — unchanged layers are cached for fast builds
✅ Containers are lightweight compared to VMs (MB vs GB, seconds vs minutes)
✅ Use docker run to start containers, -p to map ports, -d to run in background
✅ Write a Dockerfile to package your own app into an image
✅ Use volumes for persistent data; never rely on the container's filesystem
Series: Docker & Kubernetes Learning Roadmap
Next: Docker Fundamentals: Complete Beginner's Guide
Ready to go deeper? The next post covers Docker in full detail — networking, volumes, Docker Compose, and production best practices.
📬 Subscribe to Newsletter
Get the latest blog posts delivered to your inbox every week. No spam, unsubscribe anytime.
We respect your privacy. Unsubscribe at any time.
💬 Comments
Sign in to leave a comment
We'll never post without your permission.