π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:
Term | Description |
Image | A read-only template used to create containers (like a recipe). |
Container | A running instance of an image (like a dish made from the recipe). |
Dockerfile | A text file that defines how to build a Docker image. |
Docker Hub | A public repository to share and download Docker images. |
Docker Engine | The runtime that builds and runs containers. |
π¦ Docker vs Virtual Machine
Feature | Docker (Container) | Virtual Machine |
Startup Time | Seconds | Minutes |
Size | MBs | GBs |
Isolation Level | OS-level | Full OS |
Resource Usage | Low | High |
π‘ 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 by | Used in Kubernetes? | Rootless Support | Special Features | |
Docker | Docker Inc. | β (deprecated in v1.24+) | πΆ Partial (via rootless Docker) | Easy CLI |
containerd | CNCF / Docker | β (default in most distros) | β | Fast, standard |
CRI-O | Red Hat | β | β | Kubernetes-native |
runc | OCI / Docker | β (used internally) | πΆ (rootless mode available) | Low-level |
Podman | Red 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
Instruction | Description |
FROM | Sets the base image |
LABEL | Adds metadata to the image |
RUN | Executes a command during image build |
COPY | Copies files from host to container |
ADD | Similar to COPY, but can unpack archives/URLs |
WORKDIR | Sets the working directory inside the container |
ENV | Sets environment variables |
EXPOSE | Informs Docker the container listens on a port (does not publish) |
CMD | Sets default command to run when container starts |
ENTRYPOINT | Similar to CMD, but meant to always run |
VOLUME | Creates a mount point for external volumes |
USER | Specifies 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
Instruction | When it runs | Purpose |
RUN | During image build | Installs dependencies, setup tasks |
CMD | At container start | Sets default arguments for entrypoint |
ENTRYPOINT | At container start | Always 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
Feature | RUN | CMD | ENTRYPOINT |
Runs during | Build Time | Container Start | Container Start |
Purpose | Setup / Installation | Default command args | Main 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?
Benefit | Description |
Persistence | Data stays even if the container is deleted. |
Sharing | Share data between multiple containers. |
Isolation | Avoids cluttering the container's writable layer. |
Backups and Migration | Easy to back up, restore, and migrate data. |
π¦ Types of Docker Storage
Type | Description |
Volumes | Managed by Docker and stored under /var/lib/docker/volumes/ (Recommended). |
Bind Mounts | Link to any path on the host system. |
tmpfs | Temporary 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
Type | Command |
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
Feature | Volume Mount | Bind Mount |
Managed by Docker | β Yes | β No |
Data Location | /var/lib/docker/volumes/... | Any path on host |
Best for | Persistent container data | Local development & live changes |
Security | More secure | Less 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
Subscribe to my newsletter
Read articles from SRINIVAS TIRUNAHARI directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
