Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🚫 RESTRICTED — DO NOT COPY 🚫
This document is for personal study purposes only.
Copying, reproducing, sharing, or distributing any content from this material is strictly prohibited.

⚖️ Any unauthorized use of this content will result in immediate legal action.
The author reserves all rights and will pursue copyright infringement claims to the fullest extent of the law.

Docker Study Notes — Complete Reference

Detailed study notes on Docker: what it is, Dockerfiles, container management, image handling, lifecycle, restart policies, volumes, networks, environment variables, and registry operations.


Table of Contents

  1. What is Docker?
  2. Docker Architecture
  3. Dockerfile — Build Your Own Image
  4. docker run — All Important Flags
  5. What Could Go Wrong With Your App?
  6. Docker Container Commands
  7. Docker Container Lifecycle
  8. Docker Container Restart Policies
  9. Docker Image Commands
  10. Image Layers — How Docker Images Work
  11. Environment Variables in Docker
  12. Docker Volumes — Persistent Data
  13. Docker Networks
  14. Dangling Images
  15. Push Image to Docker Hub
  16. Pull Image from Docker Hub
  17. Quick Reference Cheat Sheet

1. What is Docker?

Docker is a platform that lets you package your application and all its dependencies into a single unit called a container, which can run identically on any machine that has Docker installed.

The Problem Docker Solves

Without Docker:
  "It works on my machine!" ← classic problem
  Dev machine has Node 18, production has Node 16 → app breaks

With Docker:
  You package Node 18 + your code + dependencies inside the container
  The container runs the same everywhere: dev, staging, production

Container vs Virtual Machine

Container Virtual Machine
Includes App + dependencies + OS libraries App + dependencies + full OS
Size Megabytes Gigabytes
Startup time Seconds (or milliseconds) Minutes
Resource usage Shares host OS kernel Needs its own kernel
Isolation Process-level Full OS-level

Key insight: Containers share the host OS kernel — they are not full virtual machines. This makes them lightweight and fast.

Core Concepts

Term Meaning
Image A read-only blueprint/template. Like a class in OOP.
Container A running instance of an image. Like an object created from a class.
Dockerfile A script of instructions that tells Docker how to build an image.
Docker Hub A public registry where images are stored and shared (like GitHub for images).
Registry A server that stores Docker images (Docker Hub, AWS ECR, GitHub Container Registry).
Docker Daemon The background service that manages images, containers, volumes, and networks.
Docker CLI The command-line tool (docker) you use to talk to the daemon.

2. Docker Architecture

  You (terminal)
       │
       │  docker build / docker run / docker pull
       ▼
  Docker CLI  ──────────────────►  Docker Daemon (dockerd)
                                          │
                        ┌─────────────────┼─────────────────┐
                        ▼                 ▼                 ▼
                   [ Images ]       [ Containers ]     [ Volumes ]
                        │
                        ▼
                   Docker Hub / Registry
                   (docker pull/push)
  • CLI sends commands to the Daemon via a REST API
  • Daemon does the actual work: pulling images, starting containers, managing networks
  • Images are pulled from registries (Docker Hub by default)
  • Containers are created from images by the daemon

3. Dockerfile — Build Your Own Image

A Dockerfile is a plain text file with step-by-step instructions for building a Docker image. Docker reads it top to bottom and executes each instruction as a layer.

This Project's Dockerfile (Explained Line by Line)

FROM node:20-alpine

WORKDIR /app

ENV NODE_ENV=production

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 5000

CMD ["node", "index.js"]

FROM node:20-alpine

FROM node:20-alpine
  • Every Dockerfile must start with FROM
  • Sets the base image — your image is built on top of this
  • node:20-alpine = Node.js v20 on Alpine Linux (a tiny 5MB Linux distro)
  • Alpine is preferred over the default Debian because it's much smaller
node:20           → ~1.1 GB  (full Debian)
node:20-slim      → ~240 MB  (stripped Debian)
node:20-alpine    → ~130 MB  (Alpine Linux)  ← best for production

WORKDIR /app

WORKDIR /app
  • Sets the working directory inside the container for all following commands
  • If /app doesn't exist, Docker creates it automatically
  • All RUN, COPY, CMD instructions after this work relative to /app
  • Without WORKDIR, files would land in / (root) which is messy

ENV NODE_ENV=production

ENV NODE_ENV=production
  • Sets an environment variable inside the image
  • This variable is available to the app at runtime: process.env.NODE_ENV === 'production'
  • Setting NODE_ENV=production tells Express and many npm packages to use production optimizations (less logging, no dev error pages, etc.)

COPY package*.json ./

COPY package*.json ./
  • Copies files from your local machine into the image
  • package*.json matches both package.json and package-lock.json
  • ./ means the current directory inside the container (/app because of WORKDIR)
  • Why copy package files before the rest of the code? → Layer caching (explained in Section 10)

RUN npm ci --only=production

RUN npm ci --only=production
  • Executes a command during the image build (not at runtime)
  • npm ci = clean install — uses package-lock.json exactly (more reliable than npm install)
  • --only=production = skip devDependencies (testing tools, linters) → smaller image
  • This creates a layer with all the installed node_modules

npm ci vs npm install:

npm install npm ci
Uses lock file Can modify it Strictly follows it
Deletes node_modules first No Yes
Consistency Less predictable 100% reproducible
Use in Development CI/CD, Docker

COPY . .

COPY . .
  • Copies everything else from your project directory into /app in the image
  • This comes AFTER npm ci on purpose — if you change your code, only this layer rebuilds (not npm ci). See Section 10 for why.

What gets copied? Everything in the build context (.). Use a .dockerignore file to exclude node_modules, .git, .env, etc.


EXPOSE 5000

EXPOSE 5000
  • Documents that the container listens on port 5000
  • This is informational only — it does NOT actually publish the port to your host machine
  • To actually access the port, you still need -p 5000:5000 in docker run
  • Think of it as documentation: "this container serves traffic on 5000"

CMD ["node", "index.js"]

CMD ["node", "index.js"]
  • Specifies the default command to run when the container starts
  • Uses JSON array format (exec form) — preferred because it doesn't spawn a shell
  • Runs node index.js which starts the Express server
  • There can only be one CMD per Dockerfile (last one wins)

CMD vs ENTRYPOINT:

CMD ENTRYPOINT
Purpose Default command — can be overridden Fixed executable — cannot be overridden easily
Override with docker run image other-command docker run --entrypoint
Use for Apps where you might want to swap the command Containers that always run one specific program
# CMD — can override:
CMD ["node", "index.js"]
# docker run my-app node other-script.js  ← overrides CMD

# ENTRYPOINT — always runs:
ENTRYPOINT ["node"]
CMD ["index.js"]           # ← this becomes the default argument to node
# docker run my-app other-script.js  ← runs "node other-script.js"

How to Build and Run This Project

# Build the image from the Dockerfile in the current directory
docker build -t my-express-app .

# Run it, mapping port 5000 on host to 5000 in container
docker run -d -p 5000:5000 my-express-app

# Visit http://localhost:5000 → "Hello World from docker!"

Dockerfile Instruction Summary

Instruction Purpose Runs At
FROM Set base image Build time
WORKDIR Set working directory Build time
ENV Set environment variable Build time + Runtime
COPY Copy files from host to image Build time
ADD Like COPY but supports URLs and tar extraction Build time
RUN Execute a shell command Build time
EXPOSE Document which port the app uses Documentation only
CMD Default command when container starts Runtime
ENTRYPOINT Fixed executable for the container Runtime
ARG Build-time variable (not available at runtime) Build time only
VOLUME Declare a mount point for external volumes Runtime
USER Set the user to run commands as Build time + Runtime

.dockerignore — What to Exclude from the Build

Create a .dockerignore file alongside your Dockerfile:

node_modules
.git
.env
*.log
.DS_Store

Without this, COPY . . would copy node_modules (heavy) and .env (sensitive) into the image — bad for both size and security.


4. docker run — All Important Flags

docker run is the most used command. Here are all the key flags with examples:

docker run [OPTIONS] IMAGE [COMMAND]

Flag Reference

Flag Example What It Does
-d docker run -d nginx Detached mode — run in background
-p docker run -p 8080:80 nginx Map host port to container port
--name docker run --name web nginx Give the container a custom name
-e docker run -e PORT=3000 nginx Set an environment variable
-v docker run -v /host/path:/container/path nginx Mount a volume
--rm docker run --rm nginx Auto-remove container when it stops
--restart docker run --restart always nginx Set restart policy
--network docker run --network my-net nginx Connect to a Docker network
-it docker run -it node sh Interactive terminal (for exploration)
--memory docker run --memory 512m nginx Limit memory to 512 MB
--cpus docker run --cpus 0.5 nginx Limit to half a CPU
--env-file docker run --env-file .env nginx Load env vars from a file

Practical Example with Multiple Flags

docker run \
  -d \
  -p 5000:5000 \
  --name my-express-app \
  -e NODE_ENV=production \
  -e PORT=5000 \
  --restart unless-stopped \
  --memory 256m \
  --cpus 0.5 \
  my-express-app

--rm Flag — Cleanup Automatically

docker run --rm node:20-alpine node -e "console.log('hello')"

The container is deleted the moment it exits. Perfect for one-off tasks where you don't need the container to stick around.


5. What Could Go Wrong With Your App?

What could go wrong with your app

This is the core reason Docker has restart policies and container lifecycle management. A production app can go down for many unexpected reasons:

# Failure What Happens
1 Resource Spike Sudden surge in CPU or memory causes the process to crash or the OS to kill it (OOM killer)
2 Dependency Unavailable A database, external API, or another microservice goes down — your app can't connect and exits
3 Application Bug An unhandled exception, null reference, or uncaught error crashes the process
4 Manual Stop Someone accidentally or intentionally runs docker stop or shuts the server down
5 System Reboot The host machine restarts (OS update, power cut) — all running containers are killed

Without restart policies, every one of these events means manual intervention to bring the app back. With the right policy, Docker handles recovery automatically.


6. Docker Container Commands

Docker Container Commands

The image above shows the 13 essential container commands. Here is the full reference with notes:

Full Command Table (from the image)

Command Example What It Does
docker run docker run nginx Create & start a container in one step
docker run -d docker run -d nginx Run container in the background (detached)
docker run -p docker run -p 8080:80 nginx Map a host port to a container port
docker ps docker ps List running containers
docker ps -a docker ps -a List all containers (running + stopped)
docker stop docker stop container_id Stop a running container
docker start docker start container_id Start a stopped container
docker restart docker restart container_id Restart a container
docker rm docker rm container_id Remove a container
docker logs docker logs container_id View container logs
docker exec -it docker exec -it container_id sh Access container terminal
docker container prune docker container prune Remove stopped containers
docker system prune docker system prune Remove all unused data

Notes on Each Command Group

docker run — Create & Start

docker run nginx               # Create + start (foreground, blocks terminal)
docker run -d nginx            # Detached mode — runs in background, prints container ID
docker run -p 8080:80 nginx    # Port mapping: host:container

Port mapping breakdown:

docker run -p 8080:80 nginx
              ↑    ↑
         host port  container port

→ You access http://localhost:8080
→ Docker forwards it to port 80 inside the container

docker ps / docker ps -a — List Containers

docker ps       # only RUNNING containers
docker ps -a    # ALL containers (including stopped/exited ones)

Output columns explained:

CONTAINER ID   IMAGE   COMMAND   CREATED   STATUS         PORTS                  NAMES
a1b2c3d4e5f6   nginx   ...       1 min     Up 1 minute    0.0.0.0:8080->80/tcp   my-nginx
f6e5d4c3b2a1   nginx   ...       5 min     Exited (0)                            old-nginx
  • STATUS: Up = running
  • STATUS: Exited (0) = stopped cleanly
  • STATUS: Exited (1) = stopped with an error

docker stop / docker start / docker restart

docker stop container_id      # Sends SIGTERM → waits 10 sec → sends SIGKILL (graceful)
docker start container_id     # Starts a stopped container (keeps previous config)
docker restart container_id   # Equivalent to docker stop + docker start

docker stop vs docker kill:

  • stop = graceful shutdown (app can clean up, close connections)
  • kill = immediate force kill (SIGKILL, no cleanup time)

docker rm / docker container prune / docker system prune

docker rm container_id         # Remove one stopped container
docker container prune         # Remove ALL stopped containers
docker system prune            # Remove stopped containers + dangling images + unused networks + build cache

You cannot docker rm a running container. Stop it first, or use docker rm -f to force-remove.


docker logs — View Output

docker logs container_id             # Print all logs since container started
docker logs -f container_id          # Follow logs in real time (like tail -f)
docker logs --tail 100 container_id  # Show last 100 lines only
docker logs --since 1h container_id  # Show logs from the last 1 hour

docker exec -it — Enter the Container

docker exec -it container_id sh     # Open shell (sh is available in most images)
docker exec -it container_id bash   # Bash (available in Debian/Ubuntu-based images)
  • -i = interactive (keeps stdin open)
  • -t = allocate a terminal (TTY)
  • You can also run single commands: docker exec container_id ls /app

7. Docker Container Lifecycle

Docker Container Lifecycle

The diagram shows 4 states a container moves through and the commands that trigger each transition.

The 4 States

State Color in Diagram Description
Created Purple Container created (filesystem allocated, config set) but process NOT yet started
Running Teal The container's main process is actively running
Stopped Yellow/Orange Process has exited. Container still exists with its data, can be restarted
Deleted Red Container permanently removed. Data is gone (unless in a volume)

State Transitions (as shown in the diagram)

                  ┌─────────────── Run ───────────────────┐
                  │                                        ▼
   Create ──► [ Created ] ──── Start ────────────► [ Running ]
                  │                                        │
                  │ rm                                   Stop
                  │                                        │
                  ▼                                        ▼
             [ Deleted ] ◄──────── rm ──────────── [ Stopped ]
                                                          │
                                                        Start
                                                          │
                                                          └──────────────► [ Running ]

Transition Table

Trigger From To Notes
docker create Created Prepares container, does not start it
docker run Running Skips Created — creates AND starts in one command
docker start Created / Stopped Running Starts existing container
docker stop Running Stopped Graceful shutdown
docker restart Running Running Internally: stop → start
docker rm Created / Stopped Deleted Can't remove while running
docker rm -f Running Deleted Force removes (skips stop)

Key insight from the diagram: docker run goes directly to Running — it never enters the Created state. Only docker create produces a Created container.


8. Docker Container Restart Policies

Docker Container Restart Policies

The diagram shows 3 restart policies branching from the top. These are set when creating a container:

docker run --restart <policy> image_name

8.1 --restart always

Restart Always

docker run --restart always nginx

What the flowchart shows:

Container Start ──────────────────────► Container Exit
      ▲                                       │
      │                                       ▼
      └──────────── Restart Container ◄───────┘
                          ▲
                          │
                  Docker Daemon Restart

Behavior summary:

  • Restarts on clean exit (exit code 0) ✅
  • Restarts on crash (exit code != 0) ✅
  • Restarts after Docker daemon restart / system reboot ✅
  • This is a permanent loop — the container will always come back

Use case: Web servers, databases, APIs — anything that must never be offline.

docker run -d --restart always -p 80:80 nginx

8.2 --restart unless-stopped

Restart Unless Stopped

docker run --restart unless-stopped nginx

What the flowchart shows:

Container Start ──────────────────────────────► Container Exit
      ▲                                               │
      │                                               ▼
      │                                       Manually Stopped?
      │                                        Yes │      │ No
      │                                            ▼      ▼
      │                                      Don't    Restart
      │                                      Restart  Container ──┐
      │                                                           │
      └───────────────────────────────────────────────────────────┘

  Docker Daemon Restart
          │
          ▼
   Was Running Before?
    Yes │        │ No
        ▼        ▼
   Restart   Don't
   Container  Restart

Behavior summary:

  • Restarts on crash ✅
  • Restarts on clean exit ✅
  • Respects docker stop — will NOT come back after a manual stop ✅
  • After daemon restart — only if it wasn't manually stopped ⚠️

Key difference from always: always ignores your manual stop. unless-stopped remembers it and stays stopped after daemon restarts too.

Use case: Production services where you occasionally need to take them offline for maintenance.

docker run -d --restart unless-stopped -p 3000:3000 my-app

8.3 --restart on-failure

Restart on Failure

docker run --restart on-failure nginx

# With a max retry limit:
docker run --restart on-failure:5 nginx

What the flowchart shows:

Container Start ──────────────────────────────► Container Exit
      ▲                                               │
      │                                               ▼
      │                                       Exit Code != 0 ?
      │                                        Yes │      │ No
      │                                            ▼      ▼
      │                                       Restart   Don't
      │                                       Container  Restart
      └───────────────────────────────────────────┘

  Docker Daemon Restart
          │
          ▼
     Restart Container
          │
          └──────────────────────────────► Container Start

Behavior summary:

  • Restarts on crash (exit code != 0) ✅
  • Does NOT restart on clean exit (exit code 0) ❌ — intentionally won't restart a finished job
  • Restarts after Docker daemon restart ✅
  • :N limits max retries — e.g., on-failure:5 = give up after 5 consecutive crashes

Use case: One-time scripts, batch jobs, or worker processes that should finish and stop cleanly, but automatically retry if they crash.

# Data import job — retry up to 3 times if it crashes, stop when done
docker run --restart on-failure:3 my-data-importer

8.4 Policy Comparison Table

Restart Policy Description

Taken directly from the image:

Policy Description
always Restart the container no matter what, even if it exits cleanly (exit code 0)
unless-stopped Same as always, except it won't restart if the container was manually stopped
on-failure Restart only when the container exits with a non-zero exit code (i.e., it failed)

Extended comparison:

Policy Exit 0 Exit !=0 Daemon Restart Manual Stop Respected
no (default)
always
unless-stopped ✅ (if was running)
on-failure

9. Docker Image Commands

Docker Image Commands

Images are the templates/blueprints that containers are created from. An image is read-only — when you run it, Docker adds a writable layer on top to create a container.

Full Command Table (from the image)

Command Example What It Does
docker pull docker pull nginx Download image from Docker Hub
docker images docker images List all local images
docker build docker build -t my-app . Build image from Dockerfile
docker rmi docker rmi nginx Remove an image
docker tag docker tag my-app my-app:v1 Add tag/version to image
docker push docker push username/my-app Push image to registry
docker image prune docker image prune Remove unused images
docker inspect docker inspect nginx View image details

Notes on Each Command

docker build — Build from Dockerfile

docker build -t my-app .              # Build and tag as "my-app:latest"
docker build -t my-app:v2 .           # Build with specific version tag
docker build -f Dockerfile.prod -t my-app:prod .  # Use a different Dockerfile
docker build --no-cache -t my-app .   # Force rebuild all layers (ignore cache)

The . at the end is the build context — the directory Docker reads files from.


docker rmi — Remove an Image

docker rmi nginx           # remove by name
docker rmi a6bd71f48f68    # remove by image ID
docker rmi nginx:1.25      # remove specific tag

Cannot remove an image that is being used by an existing container (even stopped). Remove the container first.


docker tag — Tag an Image

docker tag my-app my-app:v1                      # add a version tag
docker tag my-app username/my-app:latest         # tag for Docker Hub push

Tagging does NOT copy the image — it just adds a new label pointing to the same image data.


docker inspect — View Image Details

docker inspect nginx

Returns a JSON object with: Image ID, creation date, environment variables, exposed ports, entrypoint, CMD, layer info, volume mounts.


10. Image Layers — How Docker Images Work

Every instruction in a Dockerfile that modifies the filesystem creates a new layer. Layers are stacked on top of each other to form the final image.

Visual Representation

┌──────────────────────────────┐
│  Layer 5: COPY . .           │  ← your app source code
├──────────────────────────────┤
│  Layer 4: RUN npm ci         │  ← node_modules
├──────────────────────────────┤
│  Layer 3: COPY package*.json │  ← package files
├──────────────────────────────┤
│  Layer 2: ENV NODE_ENV=...   │  ← env config
├──────────────────────────────┤
│  Layer 1: FROM node:20-alpine│  ← base OS + Node
└──────────────────────────────┘

Why Layer Order Matters (Caching)

Docker caches each layer. When you rebuild, Docker only re-runs layers that changed and everything after them.

Smart order (this project's Dockerfile):

COPY package*.json ./      # Layer A — only changes when dependencies change
RUN npm ci                 # Layer B — only re-runs if Layer A changed
COPY . .                   # Layer C — changes every time you edit code
You change a .js file:
  Layer A (package.json) → cache HIT  ← not re-run
  Layer B (npm ci)       → cache HIT  ← not re-run  ← saves minutes
  Layer C (COPY . .)     → cache MISS ← re-run (your file changed)

Naive order (bad):

COPY . .           # Changes every time → cache busted
RUN npm ci         # Always re-runs → slow!

Rule: Put rarely changing instructions first, frequently changing ones last. This maximizes cache hits and makes builds fast.


11. Environment Variables in Docker

Environment variables let you configure your app without changing the code or rebuilding the image. There are two ways to set them in Docker.

Method 1 — ENV in Dockerfile (baked into image)

ENV NODE_ENV=production
ENV PORT=5000
  • The variable is built into the image — every container from this image gets it
  • Available at both build time and runtime
  • Good for variables that are always the same (e.g., NODE_ENV=production)

Method 2 — -e flag in docker run (set at runtime)

docker run -e PORT=3000 my-app
docker run -e NODE_ENV=development my-app
docker run -e DB_URL=mongodb://localhost:27017/mydb my-app
  • Overrides or adds variables when starting the container
  • Does NOT change the image — different containers can have different values
  • Good for secrets, database URLs, API keys — things that differ per environment

Method 3 — --env-file (load from a file)

# .env file:
NODE_ENV=production
PORT=5000
DB_PASSWORD=supersecret

docker run --env-file .env my-app
  • Loads all variables from a file — cleaner than many -e flags
  • Never bake .env files into your image — use --env-file or a secrets manager

Priority (who wins when there's a conflict)

--env-file < -e flag < ENV in Dockerfile
                ↑
         -e flag overrides --env-file

Actually: -e flag always overrides --env-file values, so runtime flags take precedence.

Accessing Env Vars in Node.js

// index.js
const port = process.env.PORT || 5000;
const env  = process.env.NODE_ENV;

console.log(`Running in ${env} mode on port ${port}`);

12. Docker Volumes — Persistent Data

By default, a container's filesystem is temporary. When the container is deleted, all data written inside it is gone. Volumes solve this.

The Problem Without Volumes

Container (no volume):
  You write data to /app/data inside the container
  docker rm container
  → All data is permanently lost

Types of Storage in Docker

Type Syntax Use Case
Named Volume -v my-volume:/app/data Persistent data (databases, uploads) managed by Docker
Bind Mount -v /host/path:/container/path Share host files with container (local dev)
tmpfs --tmpfs /tmp In-memory only, fast, non-persistent

Named Volumes — Docker Managed

# Create a named volume
docker volume create my-data

# Use it when running a container
docker run -v my-data:/app/data my-app

# List all volumes
docker volume ls

# Inspect a volume (see where Docker stores it)
docker volume inspect my-data

# Remove a volume
docker volume rm my-data

# Remove all unused volumes
docker volume prune
  • Docker stores the volume data on the host (usually under /var/lib/docker/volumes/)
  • The volume persists even after the container is removed
  • Multiple containers can share the same volume

Bind Mounts — Share Host Directory

# Mount current directory into /app in the container
docker run -v $(pwd):/app my-app

# Windows (PowerShell):
docker run -v ${PWD}:/app my-app

# Mount a specific host path
docker run -v /Users/zihad/myproject:/app my-app

Use case for local development:

# Your code changes on host are instantly reflected in the container
docker run -d -p 5000:5000 -v $(pwd):/app my-express-app

Bind mounts are great for dev (see live code changes), but named volumes are better for production (Docker manages the location and lifecycle).


Volume vs No Volume

Without volume:                   With named volume:
  Container deleted                 Container deleted
  → data gone ❌                    → volume persists ✅

  New container                     New container
  → starts empty ❌                 → mounts same volume, data intact ✅

13. Docker Networks

By default, containers are isolated — they can't talk to each other. Networks allow containers to communicate.

Default Networks

Docker creates three networks automatically:

Network Driver Description
bridge bridge Default network for containers. Containers can talk to each other via IP.
host host Container shares the host's network stack. No port mapping needed.
none null No networking at all. Complete isolation.
docker network ls
# NETWORK ID   NAME      DRIVER    SCOPE
# abc123       bridge    bridge    local
# def456       host      host      local
# ghi789       none      null      local

Why Custom Networks?

On the default bridge network, containers cannot reach each other by name — only by IP. A custom bridge network enables DNS-based discovery (container name = hostname).

# Create a custom network
docker network create my-network

# Run containers on that network
docker run -d --name app --network my-network my-express-app
docker run -d --name db  --network my-network mongo

# Now "app" can connect to "db" just by using the hostname "db"
# e.g., mongodb://db:27017/mydb

Network Commands

# List networks
docker network ls

# Create a network
docker network create my-network

# Inspect a network (see which containers are connected)
docker network inspect my-network

# Connect a running container to a network
docker network connect my-network container_id

# Disconnect a container from a network
docker network disconnect my-network container_id

# Remove a network
docker network rm my-network

# Remove unused networks
docker network prune

How Containers Communicate

Without custom network:              With custom network:
  container A → cannot find "db"      container A → "db" resolves to db container IP
  must use IP: 172.17.0.2             can use: mongodb://db:27017

Real example — Express app + MongoDB:

docker network create app-net

docker run -d \
  --name mongo \
  --network app-net \
  mongo

docker run -d \
  --name express-app \
  --network app-net \
  -p 5000:5000 \
  -e DB_URL=mongodb://mongo:27017/mydb \
  my-express-app

The Express app connects to MongoDB using mongodb://mongo:27017mongo resolves to the MongoDB container's IP automatically.


14. Dangling Images

A dangling image is an image with no name and no tag — it appears as <none>:<none> in docker images. It exists on disk but no container or tag references it.

How They Are Created

The most common cause is rebuilding an image with the same tag:

# Build 1 — image created, tagged as "my-app:latest"
docker build -t my-app .

# ... you edit your code ...

# Build 2 — a NEW image gets the "my-app:latest" tag
# The OLD image LOSES its tag → becomes <none>:<none> (dangling)
docker build -t my-app .

Every rebuild leaves the old image orphaned. Over many rebuilds, these pile up and eat disk space silently.

What They Look Like

docker images

# REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
# my-app       latest    abc123def456   30 seconds ago   320MB
# <none>       <none>    d1e017099d17   5 minutes ago    310MB   ← dangling
# <none>       <none>    a2f9b3c44e21   1 hour ago       308MB   ← dangling

Viewing Only Dangling Images

docker images -f dangling=true

Why They Are a Problem

  • Waste disk space — each build can leave behind hundreds of MBs
  • Accumulate invisibly — don't show up clearly in plain docker images
  • Serve no purpose — no container runs from them, no tag points to them

How to Remove Dangling Images

# Remove only dangling images
docker image prune

# Remove ALL images not currently used by a container
docker image prune -a

# Skip confirmation prompt
docker image prune -f

# Remove everything unused (containers, images, networks, cache)
docker system prune

15. Push Image to Docker Hub

Docker Hub is the default public registry. Once an image is pushed, anyone can docker pull it from anywhere in the world.

How Pushing Works

Your Machine                   Docker Hub
─────────────                  ──────────────────────────────
[local image]  ─── push ──►   [username/repository:tag]

Step-by-Step Workflow

Step 1 — Log in to Docker Hub

docker login
# Prompts for username and password

Step 2 — Build Your Image

docker build -t my-app .

Step 3 — Tag with Your Docker Hub Username

Docker Hub requires the format: username/repository:tag

# Format:
docker tag <local-image-name> <dockerhub-username>/<repository>:<tag>

# Example:
docker tag my-app zihadrahman/my-app:v1
docker tag my-app zihadrahman/my-app:latest

Step 4 — Push

docker push zihadrahman/my-app:v1
docker push zihadrahman/my-app:latest

Docker pushes each layer separately. Layers already on Docker Hub are skipped (Layer already exists), so subsequent pushes are very fast.

Step 5 — Verify

Your image is now at: hub.docker.com/r/zihadrahman/my-app

Anyone can pull it with:

docker pull zihadrahman/my-app:v1

Full Example (all steps)

docker login

docker build -t my-express-app .

docker tag my-express-app zihadrahman/my-express-app:v1
docker tag my-express-app zihadrahman/my-express-app:latest

docker push zihadrahman/my-express-app:v1
docker push zihadrahman/my-express-app:latest

Why Tag as Both v1 and latest?

  • :latest — always points to the most recent build (default pulled by others)
  • :v1 — a permanent snapshot. Even after you push v2, v1 remains pullable.

16. Pull Image from Docker Hub

Pulling downloads a Docker image from a registry to your local machine so you can run containers from it.

Basic Pull

docker pull nginx           # pulls nginx:latest
docker pull nginx:1.25      # pulls a specific version
docker pull node:20-alpine  # the exact base image this project uses

How Pulling Works (Layers)

Docker images are made of layers. Docker downloads each layer separately and caches them:

docker pull node:20-alpine

18-alpine: Pulling from library/node
31e352740f53: Pull complete      ← base OS layer
b2b5bfcb75ab: Pull complete      ← node runtime layer
Digest: sha256:abc123...
Status: Downloaded newer image for node:20-alpine

If you pull another image that shares a layer, that layer is not re-downloaded — reused from cache.

Pull Types

# Official image (maintained by Docker/vendor)
docker pull nginx
docker pull postgres

# User/community image (username/repository)
docker pull zihadrahman/my-express-app:v1

# Specific version tag
docker pull nginx:1.25.3

# Immutable digest reference (exact version, never changes)
docker pull nginx@sha256:abc123...

docker pull vs docker run

docker pull docker run
Downloads image ✅ (if not cached locally)
Creates container
Starts container

Use docker pull when you want to pre-download an image without running it (useful for warming CI/CD cache).


17. Quick Reference Cheat Sheet

Build

Real Command Example Command Usage
docker build docker build -t my-app . Build image from Dockerfile in current directory
docker build docker build -t my-app:v1 . Build image with a specific version tag
docker build docker build --no-cache -t my-app . Force rebuild all layers, ignore layer cache
docker build docker build -f Dockerfile.prod -t my-app . Build using a specific Dockerfile file

Container — Run

Real Command Example Command Usage
docker run docker run nginx Create and start a container (foreground, blocks terminal)
docker run -d docker run -d nginx Run container in background (detached mode)
docker run -p docker run -p 5000:5000 nginx Map host port 5000 to container port 5000
docker run --name docker run --name web nginx Give the container a custom name
docker run -e docker run -e NODE_ENV=production my-app Set an environment variable inside the container
docker run --env-file docker run --env-file .env my-app Load environment variables from a file
docker run -v docker run -v my-vol:/app/data my-app Mount a named volume for persistent data
docker run -v docker run -v ${PWD}:/app my-app Bind mount current directory into container (dev)
docker run --rm docker run --rm node sh Auto-remove container when it stops
docker run --memory docker run --memory 256m my-app Limit container memory to 256 MB
docker run --cpus docker run --cpus 0.5 my-app Limit container to half a CPU core
docker run --network docker run --network my-net my-app Connect container to a custom network
docker run --restart docker run --restart always my-app Set restart policy when starting the container

Container — Manage

Real Command Example Command Usage
docker ps docker ps List only currently running containers
docker ps -a docker ps -a List all containers (running + stopped)
docker stop docker stop container_id Gracefully stop a running container (SIGTERM)
docker start docker start container_id Start a previously stopped container
docker restart docker restart container_id Stop and start a container in one command
docker rm docker rm container_id Remove a stopped container
docker rm -f docker rm -f container_id Force remove a running container
docker logs docker logs container_id View all stdout/stderr output from a container
docker logs -f docker logs -f container_id Follow/stream container logs in real time
docker logs --tail docker logs --tail 100 container_id Show only the last 100 lines of logs
docker exec -it docker exec -it container_id sh Open an interactive shell inside the container
docker container prune docker container prune Remove all stopped containers at once
docker system prune docker system prune Remove all unused containers, images, networks, cache

Restart Policies

Real Command Example Command Usage
docker run --restart always docker run --restart always nginx Always restart — on any exit or after system reboot
docker run --restart unless-stopped docker run --restart unless-stopped nginx Restart on any exit, but not if manually stopped
docker run --restart on-failure docker run --restart on-failure nginx Restart only when exit code is non-zero (crash)
docker run --restart on-failure:N docker run --restart on-failure:5 nginx Restart on crash, but give up after N retries

Images

Real Command Example Command Usage
docker images docker images List all images stored locally
docker pull docker pull nginx Download the latest version of an image from Docker Hub
docker pull docker pull nginx:1.25 Download a specific version/tag of an image
docker tag docker tag my-app username/my-app:v1 Add a registry tag to an image before pushing
docker push docker push username/my-app:v1 Upload a tagged image to Docker Hub
docker rmi docker rmi nginx Remove a local image by name
docker rmi docker rmi a6bd71f48f68 Remove a local image by ID
docker inspect docker inspect nginx View detailed metadata of an image (JSON output)

Dangling Image Cleanup

Real Command Example Command Usage
docker images -f docker images -f dangling=true Show only dangling (<none>:<none>) images
docker image prune docker image prune Remove all dangling images
docker image prune -a docker image prune -a Remove all images not used by any container
docker image prune -f docker image prune -f Remove dangling images without confirmation prompt
docker system prune docker system prune Remove all unused Docker data (nuclear cleanup)

Volumes

Real Command Example Command Usage
docker volume create docker volume create my-vol Create a named volume managed by Docker
docker volume ls docker volume ls List all volumes
docker volume inspect docker volume inspect my-vol View volume details and host storage path
docker volume rm docker volume rm my-vol Remove a specific volume
docker volume prune docker volume prune Remove all volumes not used by any container

Networks

Real Command Example Command Usage
docker network ls docker network ls List all Docker networks
docker network create docker network create my-net Create a custom bridge network
docker network inspect docker network inspect my-net View network details and connected containers
docker network connect docker network connect my-net container_id Connect a running container to a network
docker network disconnect docker network disconnect my-net container_id Disconnect a container from a network
docker network rm docker network rm my-net Remove a network
docker network prune docker network prune Remove all networks not used by any container

Auth

Real Command Example Command Usage
docker login docker login Log in to Docker Hub (prompts for username + password)
docker logout docker logout Log out of Docker Hub

Habibur Rahman Zihad

Full-Stack Developer

© 2026 All Rights Reserved