DockerImagesContainers Beginner 4 min read

02-Docker Images & Containers

Learn how Docker images work, how to pull images from Docker Hub, run containers, inspect them, and manage their lifecycle.

Understanding Docker Images

A Docker image is a read-only template made up of layers. Each instruction in a Dockerfile adds a new layer on top of the previous one.

┌─────────────────────────────┐  ← Your App Layer
├─────────────────────────────┤  ← npm install Layer
├─────────────────────────────┤  ← COPY package.json Layer
├─────────────────────────────┤  ← node:18-alpine Base Layer
└─────────────────────────────┘
Why layers matter
Docker caches each layer. If only your app code changes, Docker reuses all the earlier layers — making builds dramatically faster.

Pulling Images from Docker Hub

Docker Hub is the default public registry. Images follow the format: name:tag

# Pull the official Nginx image (latest tag)
docker pull nginx

# Pull a specific version
docker pull nginx:1.25-alpine

# Pull Node.js 18 on Alpine Linux (very small base)
docker pull node:18-alpine

# Pull Ubuntu 22.04
docker pull ubuntu:22.04

Listing and Inspecting Images

# List all locally available images
docker images
# or
docker image ls

# Example output:
# REPOSITORY   TAG          IMAGE ID       CREATED        SIZE
# nginx        latest       a6bd71f48f68   2 weeks ago    187MB
# nginx        1.25-alpine  1ae23480369f   3 weeks ago    43.2MB
# node         18-alpine    b5b9bec2fc07   1 month ago    127MB

# Inspect image details (layers, env vars, entrypoint)
docker image inspect nginx

# See the layer history of an image
docker image history nginx

Running Your First Container

# Run Nginx and map port 80 on host to port 80 in container
docker run -p 80:80 nginx

Visit http://localhost — you’ll see the Nginx welcome page!

Important docker run Flags

FlagPurposeExample
-dRun in background (detached mode)docker run -d nginx
-pPort mapping host:container-p 8080:80
--nameGive container a name--name my-nginx
-eSet environment variable-e NODE_ENV=production
-vMount a volume-v $(pwd):/app
--rmAuto-remove container when stoppeddocker run --rm ubuntu echo hi
-itInteractive + TTY (for shells)docker run -it ubuntu bash

Detached Mode (Background)

# Run Nginx in the background
docker run -d -p 8080:80 --name my-nginx nginx

# Run a named container with environment variable
docker run -d \
  --name my-postgres \
  -e POSTGRES_PASSWORD=secret \
  -p 5432:5432 \
  postgres:15-alpine

Managing Container Lifecycle

# List running containers
docker ps

# List ALL containers (including stopped)
docker ps -a

# Stop a container gracefully (SIGTERM → waits 10s → SIGKILL)
docker stop my-nginx

# Start a stopped container
docker start my-nginx

# Restart a container
docker restart my-nginx

# Kill a container immediately (SIGKILL)
docker kill my-nginx

# Remove a stopped container
docker rm my-nginx

# Force remove a running container
docker rm -f my-nginx

# Remove ALL stopped containers
docker container prune

Interacting with Running Containers

# Execute a command inside a running container
docker exec my-nginx ls /etc/nginx

# Open an interactive shell inside a running container
docker exec -it my-nginx /bin/sh

# View container logs (stdout/stderr)
docker logs my-nginx

# Follow logs in real time (like tail -f)
docker logs -f my-nginx

# Show last 50 lines
docker logs --tail 50 my-nginx

# Inspect container details (IP, mounts, env vars)
docker inspect my-nginx

# View resource usage (CPU, memory, network)
docker stats
docker stats my-nginx   # single container

Practical Exercise

Let’s run a real development database:

# 1. Start a PostgreSQL container
docker run -d \
  --name dev-postgres \
  -e POSTGRES_USER=admin \
  -e POSTGRES_PASSWORD=secret123 \
  -e POSTGRES_DB=myapp \
  -p 5432:5432 \
  postgres:15-alpine

# 2. Check it's running
docker ps

# 3. Connect to it with psql (inside the container)
docker exec -it dev-postgres psql -U admin -d myapp

# 4. Inside psql, create a table
# CREATE TABLE users (id serial PRIMARY KEY, name varchar);
# INSERT INTO users (name) VALUES ('Alice'), ('Bob');
# SELECT * FROM users;
# \q

# 5. Stop and clean up
docker stop dev-postgres
docker rm dev-postgres
One-liner cleanup
docker rm -f $(docker ps -aq) stops and removes all containers at once. Useful in development — never run this in production!

Cleaning Up Images

# Remove a specific image
docker rmi nginx:1.25-alpine

# Remove all unused images (dangling)
docker image prune

# Remove ALL unused images (not just dangling)
docker image prune -a

# Nuclear option — remove everything unused
docker system prune -a
# ⚠️ WARNING: removes all stopped containers, unused networks, images, and build cache

Summary

CommandWhat it does
docker pull image:tagDownload an image
docker imagesList local images
docker run -d -p host:container --name NAME imageStart a container
docker psList running containers
docker stop NAMEStop a container
docker rm NAMERemove a container
docker exec -it NAME shShell into a container
docker logs -f NAMEStream container logs
docker inspect NAMEFull container metadata

In the next lesson, you’ll write your first Dockerfile to build custom images for your own application!