πŸš€Docker deep dive

🚒 What is Docker?

Docker is an open-source platform that helps you build, ship, and run applications in containers. It allows developers and system administrators to package an application with all its dependencies into a single unit (called a container) that can run on any system.


βœ… In Simple Terms:

Docker helps you run your app anywhere, the same way, without worrying about the system setup.


🧱 Key Concepts:

TermDescription
ImageA read-only template used to create containers (like a recipe).
ContainerA running instance of an image (like a dish made from the recipe).
DockerfileA text file that defines how to build a Docker image.
Docker HubA public repository to share and download Docker images.
Docker EngineThe runtime that builds and runs containers.

πŸ“¦ Docker vs Virtual Machine

FeatureDocker (Container)Virtual Machine
Startup TimeSecondsMinutes
SizeMBsGBs
Isolation LevelOS-levelFull OS
Resource UsageLowHigh

πŸ’‘ Why Use Docker?

  • βœ… Portability: "It works on my machine" problem goes away.

  • βœ… Consistency: Same environment from development to production.

  • βœ… Isolation: Each app runs in its own container.

  • βœ… Speed: Lightweight and faster than traditional virtual machines.

  • βœ… Efficiency: Uses fewer resources than VMs.


Kubernetes stopped supporting Docker as a runtime directly in version 1.24 and now relies on containerd or CRI-O.

πŸ“Š Summary Table

Developed byUsed in Kubernetes?Rootless SupportSpecial Features
DockerDocker Inc.❌ (deprecated in v1.24+)πŸ”Ά Partial (via rootless Docker)Easy CLI
containerdCNCF / Dockerβœ… (default in most distros)βœ…Fast, standard
CRI-ORed Hatβœ…βœ…Kubernetes-native
runcOCI / Dockerβœ… (used internally)πŸ”Ά (rootless mode available)Low-level
PodmanRed Hat❌ (can be used outside K8s)βœ…Docker CLI compatible

πŸ”§ Basic Example:

1. Create a simple web app using Python Flask:

mkdir simple-web-app-using-Python-Flask
cd simple-web-app-using-Python-Flask
touch app.py Dockerfile
# app.py
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello():
    return "Hello from Docker!"

2. Dockerfile:

# Use Python image
FROM python:3.9

# Set working directory
WORKDIR /app

# Copy app files
COPY . .

# Install dependencies
RUN pip install flask

# Run the app
CMD ["python", "app.py"]

3. Build and Run:

docker build -t flask-app .
docker run -p 5000:5000 flask-app

Then visit: http://localhost:5000


🐳 What is a Dockerfile?

A Dockerfile is a text file that contains a list of instructions Docker uses to build a container image.


🧱 Common Dockerfile Instructions

InstructionDescription
FROMSets the base image
LABELAdds metadata to the image
RUNExecutes a command during image build
COPYCopies files from host to container
ADDSimilar to COPY, but can unpack archives/URLs
WORKDIRSets the working directory inside the container
ENVSets environment variables
EXPOSEInforms Docker the container listens on a port (does not publish)
CMDSets default command to run when container starts
ENTRYPOINTSimilar to CMD, but meant to always run
VOLUMECreates a mount point for external volumes
USERSpecifies which user to use

πŸ“ Example Project Structure

my-node-app/
β”œβ”€β”€ Dockerfile
β”œβ”€β”€ index.js
β”œβ”€β”€ package.json

βœ… index.js


// index.js
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;

// Basic GET endpoint
app.get('/', (req, res) => {
  res.send('Hello from Dockerized Node.js App!');
});

// Start server
app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});

βœ… Dockerfile

# 1. Use an official base image
FROM node:18

# 2. Add metadata
LABEL maintainer="yourname@example.com"

# 3. Set working directory inside container
WORKDIR /app

# 4. Copy package.json and install dependencies
COPY package*.json ./
RUN npm install

# 5. Copy the rest of the app
COPY . .

# 6. Set environment variable
ENV PORT=3000

# 7. Expose the port the app runs on
EXPOSE 3000

# 8. Default command to run the app
CMD ["node", "index.js"]

βœ… package.json

jsonCopyEdit{
  "name": "my-node-app",
  "version": "1.0.0",
  "description": "A simple Node.js app for Docker demo",
  "main": "index.js",
  "scripts": {
    "start": "node index.js"
  },
  "author": "Your Name",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.2"
  }
}

πŸƒ How to Build and Run

πŸ”¨ Build the image:

docker build -t my-node-app .

▢️ Run the container:

docker run -p 3000:3000 my-node-app

🟦 RUN vs CMD vs ENTRYPOINT

InstructionWhen it runsPurpose
RUNDuring image buildInstalls dependencies, setup tasks
CMDAt container startSets default arguments for entrypoint
ENTRYPOINTAt container startAlways runs and can take CMD as args

πŸ”¨ 1. Dockerfile with RUN

# Dockerfile.run
FROM alpine

# Install bash
RUN apk add --no-cache bash

# RUN executes at build time
RUN echo "This runs at build time"

CMD ["echo", "This runs at container start"]

πŸ‘‰ Usage:

docker build -f Dockerfile.run -t run-demo .
docker run run-demo

πŸ“Œ Output:

This runs at container start
docker run run-demo echo "welcome"

πŸ“Œ Output:

welcome

πŸ› οΈ CMD can be overridden by runtime arguments.

πŸ› οΈ RUN is only for build-time actions, not for container startup behavior.

πŸ”¨ 2. Create script.sh file add bellow code

#!/bin/bash
echo "Arguments passed: $@"

πŸ”¨ 3. Dockerfile with ENTRYPOINT

# Dockerfile.entrypoint
FROM alpine
RUN apk add --no-cache bash

COPY script.sh /script.sh

ENTRYPOINT ["/script.sh"]

πŸ‘‰ Usage:

docker build -f Dockerfile.entrypoint -t entrypoint-demo .
docker run entrypoint-demo arg1 arg2

πŸ“Œ Output:

Arguments passed: arg1 arg2

πŸ› οΈ ENTRYPOINT is not overridden, unless --entrypoint is explicitly set.


πŸ”₯ Combining ENTRYPOINT + CMD

# Dockerfile.entrypoint-cmd
FROM alpine
RUN apk add --no-cache bash

COPY script.sh /script.sh

ENTRYPOINT ["/script.sh"]
CMD ["default1", "default2"]

πŸ‘‰ Usage:

docker build -f Dockerfile.entrypoint-cmd -t entrypoint-cmd-demo .
docker run entrypoint-cmd-demo

πŸ“Œ Output:

Arguments passed: default1 default2

Override CMD:

docker run entrypoint-cmd-demo new1 new2

πŸ“Œ Output:

Arguments passed: new1 new2

Override ENTRYPOINT:

docker run --entrypoint echo entrypoint-cmd-demo hello

πŸ“Œ Output:

hello

βœ… Summary Table

FeatureRUNCMDENTRYPOINT
Runs duringBuild TimeContainer StartContainer Start
PurposeSetup / InstallationDefault command argsMain command to run
Overridable❌ Noβœ… Yes (via CLI)❌ No (unless --entrypoint used)
Used with CMD❌ Not relatedβœ… Alone or with ENTRYPOINTβœ… Can use CMD for default arguments

Create a Docker container that serves a custom HTML page using Nginx on Alpine Linux.


πŸ“ Project Structure

alpine-nginx-demo/
β”œβ”€β”€ Dockerfile
└── index.html

πŸ”Ή index.html

<!DOCTYPE html>
<html>
<head>
  <title>Alpine Nginx Demo</title>
</head>
<body>
  <h1>Hello from Alpine + Nginx!</h1>
</body>
</html>

πŸ“ Dockerfile

# Use alpine base with nginx
FROM nginx:alpine

# Remove default index page (optional)
RUN rm -rf /usr/share/nginx/html/*

# Copy your custom index.html to nginx html dir
COPY index.html /usr/share/nginx/html/index.html

# Expose default nginx port
EXPOSE 80

# Nginx already has ENTRYPOINT + CMD defined in base image

▢️ Build and Run

πŸ”¨ Build image

docker build -t alpine-nginx-demo .

▢️ Run container

docker run -d -p 8080:80 alpine-nginx-demo

Now visit: http://localhost:8080
You should see: "Hello from Alpine + Nginx!"


βœ… Why Use nginx:alpine?

  • Tiny size (~5MB) ⬇️

  • Faster download/build

  • Secure, minimal attack surface


πŸ—‚οΈ Docker Volumes – A Complete Guide

πŸ”§ What is a Docker Volume?

A Docker volume is a persistent storage mechanism managed by Docker to store and share data between containers or between a container and the host.

βœ… Why Use Volumes?

BenefitDescription
PersistenceData stays even if the container is deleted.
SharingShare data between multiple containers.
IsolationAvoids cluttering the container's writable layer.
Backups and MigrationEasy to back up, restore, and migrate data.

πŸ“¦ Types of Docker Storage

TypeDescription
VolumesManaged by Docker and stored under /var/lib/docker/volumes/ (Recommended).
Bind MountsLink to any path on the host system.
tmpfsTemporary in-memory storage. Data is lost when container stops.

πŸ”¨ Common Volume Commands

# Create a volume
docker volume create myvolume

# List volumes
docker volume ls

# Inspect a volume
docker volume inspect myvolume

# Remove a volume
docker volume rm myvolume

# Prune (delete all unused volumes)
docker volume prune

πŸ§ͺ Example: Using a Volume in a Container

1. Create and Run with a Named Volume

docker run -d \
  --name mycontainer \
  -v myvolume:/app/data \
  alpine \
  sh -c "echo 'hello' > /app/data/hello.txt && sleep 3600"

βœ… This stores hello.txt in the Docker-managed volume myvolume.

docker run -it --name mycontainer2 -v myvolume:/app/data alpine sh

πŸ“ Bind Mount vs Volume Example

TypeCommand
Bind Mount (host-controlled path):
docker run -v /home/user/data:/data alpine

| Volume (Docker-managed):

docker run -v myvolume:/data alpine

πŸ“‚ Inspect Volume Mount on Host

To check where the volume is stored:

docker volume inspect myvolume

Sample output:

[
    {
        "Name": "myvolume",
        "Mountpoint": "/var/lib/docker/volumes/myvolume/_data",
        ...
    }
]

πŸ› οΈ Docker Compose Volume Example

version: '3.9'
services:
  db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: example
    volumes:
      - dbdata:/var/lib/mysql

volumes:
  dbdata:

Run with:

docker compose up -d

βœ… This keeps database data persistent across container restarts.


🧼 Clean Up

# Stop and remove all containers
docker rm -f $(docker ps -aq)

# Remove all volumes
docker volume prune

πŸš€ Difference between volume mount and bind mount

Understand the difference between:

  • Volume Mounts (managed by Docker)

  • Bind Mounts (map host directory to container directory)


πŸ“ Sample App Structure

docker-mount-demo/
β”œβ”€β”€ index.html

index.html:

<h1>Hello from Docker Mount Demo!</h1>

🐳 1. VOLUME MOUNT

Docker volumes are managed by Docker and live in /var/lib/docker/volumes.

πŸ”Ή Step 1: Create a volume

docker volume create myvol

πŸ”Ή Step 2: Run container using volume

docker run -d \
  --name volume-demo \
  -p 8080:80 \
  -v myvol:/usr/share/nginx/html \
  nginx:alpine

Now Nginx serves content from the empty volume β€” default page won't appear.

πŸ”Ή Step 3: Copy a file into the volume

docker cp index.html volume-demo:/usr/share/nginx/html/index.html

Now visit: http://localhost:8080


πŸ“‚ 2. BIND MOUNT

Bind mounts link a host folder directly to the container.

πŸ”Ή Step 1: Run container using bind mount

docker run -d \
  --name bind-demo \
  -p 8081:80 \
  -v $(pwd):/usr/share/nginx/html \
  nginx:alpine

On Windows (PowerShell), use:

docker run -d --name bind-demo -p 8081:80 -v ${PWD}:/usr/share/nginx/html nginx:alpine

Now Nginx serves the index.html directly from your local directory!

You can edit index.html live and see changes on http://localhost:8081 without rebuilding.


πŸ” Summary: Volume vs Bind Mount

FeatureVolume MountBind Mount
Managed by Dockerβœ… Yes❌ No
Data Location/var/lib/docker/volumes/...Any path on host
Best forPersistent container dataLocal development & live changes
SecurityMore secureLess secure (host path access)

Bonus tips

Print docker contaners list in tabular format

docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"

To remove all Docker volumes

docker volume prune -f
  • -f (or --force) skips the confirmation prompt.

  • This deletes all unused volumes (not used by any container).

⚠️ To remove all volumes, even those in use (dangerous):

docker volume rm $(docker volume ls -q)
  • This forcefully deletes every volume, including ones currently used by running/stopped containers.

  • Can cause data loss if containers rely on those volumes.


βœ… To check volumes before deleting:

docker volume ls
1
Subscribe to my newsletter

Read articles from SRINIVAS TIRUNAHARI directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

SRINIVAS TIRUNAHARI
SRINIVAS TIRUNAHARI