Back to blog

Docker Images and Containers Explained

dockercontainersdevopsbackendtutorial
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 info

Once installed, run the classic smoke test:

docker run hello-world

If 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:15

Docker 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 prune

What 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

FeatureContainerVirtual Machine
SizeMBsGBs (full OS)
StartupSecondsMinutes
IsolationProcess-levelHardware-level
PerformanceNear-native~5–10% overhead
DensityHundreds per hostTens 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-world

This 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 nginx

Open 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 ps
CONTAINER ID   IMAGE   COMMAND   CREATED        STATUS         PORTS                  NAMES
a3f1b2c4d5e6   nginx   ...       2 minutes ago  Up 2 minutes   0.0.0.0:8080->80/tcp   my-nginx

Stop and Remove

docker stop my-nginx
docker rm my-nginx

Or force-remove a running container:

docker rm -f my-nginx

Building 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-app

Visit http://localhost:3000 — you'll see "Hello from Docker!"

What Each Dockerfile Instruction Does

InstructionPurpose
FROM node:24Start from the official Node.js 24 image
WORKDIR /appSet the working directory inside the container
COPY index.js .Copy your file into the container
EXPOSE 3000Document 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 images

Containers

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 containers

System Cleanup

docker system df               # Check disk usage
docker system prune            # Remove unused resources
docker system prune --volumes  # Include volumes in cleanup

Common 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.3

Storing 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:15

Not Cleaning Up

Containers, images, and volumes accumulate quickly. Run this periodically:

docker system prune --volumes

Summary

✅ 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.