0% found this document useful (0 votes)
5 views27 pages

Docker Complete Guide

The document is a comprehensive guide on Docker, explaining its purpose, core concepts, and practical applications for developers. It covers the installation process, creation of Docker images and containers, and how to share projects using Docker Hub or archive files. The guide also includes essential Docker commands and a step-by-step tutorial for building a sample Node.js application with Docker.

Uploaded by

mandadhikalyan6
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views27 pages

Docker Complete Guide

The document is a comprehensive guide on Docker, explaining its purpose, core concepts, and practical applications for developers. It covers the installation process, creation of Docker images and containers, and how to share projects using Docker Hub or archive files. The guide also includes essential Docker commands and a step-by-step tutorial for building a sample Node.js application with Docker.

Uploaded by

mandadhikalyan6
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

The Complete Docker Guide

Beginner to Advanced — For Students & Developers


Run Any Project on Any Machine — Without Installing Dependencies

By Abhishek Rathor [Ig :code.abhii07] | SYNTAX ERROR

1 Introduction to Docker

What is Docker?
Docker is an open-source platform that lets you package your application and all its
dependencies into a single unit called a Container. Think of it like a lunchbox — you put your
food (code), plate (runtime), and utensils (dependencies) all inside one box. Wherever you carry
that box, you can eat your lunch exactly the same way.

Analogy: Imagine you cooked a perfect biryani at home. But when you try to cook it at a
friend's house, the gas pressure is different, some spices are missing, and the result is totally
different. Docker is like bringing your entire kitchen along — so the biryani always tastes the
same!

Why is Docker Used?


Docker solves some of the most frustrating problems in software development:
• Ship applications faster with consistent environments
• Eliminate environment-related bugs
• Scale applications easily using containers
• Simplify collaboration between team members
• Works identically on development, testing, and production servers

The Real-World Problem Docker Solves


Every developer has heard this phrase at least once in their career:

"It works on my machine!"


Here is a common scenario without Docker:
1. You build a [Link] app using Node v18 on your laptop
2. Your friend tries to run it, but has Node v14 — app crashes
3. Your production server has Ubuntu, but you developed on macOS — different behavior
4. You need MongoDB v6, but the server has v4 installed — data issues

✅ With Docker, you define EVERYTHING your app needs inside a Dockerfile. When anyone
runs your Docker container, they get the exact same environment — same OS, same Node
version, same MongoDB version, same everything.

Common Problems Without Docker

Problem What Happens


Dependency version mismatch App crashes or behaves differently on another machine
Missing environment variables Features silently fail or throw cryptic errors
OS differences (Mac vs Linux) File paths, permissions, and commands differ
Manual setup for every developer Hours wasted just to get the project running
"Works on my machine" bug Impossible to reproduce — defeats the purpose of
testing

2 Core Concepts

Docker vs Virtual Machine (VM)


Both Docker and VMs allow you to run isolated environments, but they work very differently:

Feature Docker Container


Technology Uses your host OS kernel directly
Startup time Seconds (very fast)
Size MBs — very lightweight
Performance Near-native performance
Isolation Process-level isolation
Portability Extremely portable
Best for Microservices, apps, CI/CD pipelines

Feature Virtual Machine


Technology Runs its own full OS on a hypervisor
Startup time Minutes (slow)
Size GBs — very heavy
Performance Slower due to overhead
Isolation Full OS-level isolation
Portability Less portable, large disk images
Best for Running different OS, legacy systems

Simple Analogy: VM is like renting a full house. Docker container is like renting just a room in
a shared flat. You get your own private space, but share the building infrastructure.

Docker Image
A Docker Image is a read-only blueprint or template used to create containers. Think of it like a
recipe or a class in programming — you define it once, and you can create multiple instances
from it.

• Read-only: Images never change once built


• Layered: Built in layers for caching efficiency
• Shareable: Can be pushed to Docker Hub for others to use
• Versioned: Multiple versions (tags) can exist side by side

Analogy: Docker Image = A recipe card. You read the recipe (image), then cook the dish (run
the container). Multiple people can cook from the same recipe card!

Docker Container
A Docker Container is a running instance of a Docker Image. When you run an image, a
container is created. You can run multiple containers from the same image, and each one is
isolated from the others.

• Ephemeral: Containers can be started, stopped, deleted anytime


• Isolated: Each container has its own filesystem, network, and processes
• Lightweight: Shares the host OS kernel — very efficient
Analogy: Docker Image = Class definition in code. Docker Container = An object (instance)
created from that class. You can create many objects from one class!

Dockerfile
A Dockerfile is a text file containing a set of instructions to build a Docker Image. It tells Docker
exactly how to set up the environment for your application — what OS to use, what to install,
how to start the app.

# Example Dockerfile structure


FROM node:18-alpine # Base image
WORKDIR /app # Set working directory
COPY package*.json ./ # Copy package files
RUN npm install # Install dependencies
COPY . . # Copy all source code
EXPOSE 3000 # Document the port
CMD ["node", "[Link]"] # Start command

Docker Hub
Docker Hub is the official public registry (like GitHub, but for Docker Images). You can:
• Pull official images like node, python, mysql, nginx, redis
• Push your own images so others can use them
• Use private registries for company/team images
• Explore thousands of community-maintained images

Docker Hub URL: [Link] — Browse official images for Node, Python, Go,
MySQL, PostgreSQL, Redis, Nginx and more!

3 Step-by-Step Practical Guide

Step 1: Install Docker

Windows Installation
5. Go to [Link]
6. Download Docker Desktop for Windows
7. Run the installer and follow the wizard
8. Enable WSL 2 (Windows Subsystem for Linux) when prompted
9. Restart your computer
10. Open terminal and verify: docker --version

macOS Installation
11. Go to [Link]
12. Download Docker Desktop for Mac (choose Intel or Apple Silicon chip)
13. Open the .dmg file and drag Docker to Applications
14. Open Docker from Applications and follow setup
15. Open terminal and verify: docker --version

Linux (Ubuntu) Installation

# Update package list


sudo apt-get update

# Install required packages


sudo apt-get install ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key


sudo mkdir -p /etc/apt/keyrings
curl -fsSL [Link] | sudo gpg \
--dearmor -o /etc/apt/keyrings/[Link]

# Set up the repository


echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/[Link]] \
[Link] \
$(lsb_release -cs) stable" | sudo tee /etc/apt/[Link].d/[Link] >
/dev/null

# Install Docker Engine


sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli [Link] docker-compose-plugin

# Start Docker and enable auto-start


sudo systemctl start docker
sudo systemctl enable docker

# Run without sudo (optional but recommended)


sudo usermod -aG docker $USER
newgrp docker

# Verify installation
docker --version
docker run hello-world
Step 2: Create a Sample [Link] Project
We will build a simple [Link] web server that displays a message. Create a new project
folder:

# Create and enter project directory


mkdir my-docker-app
cd my-docker-app

Create [Link]

# Create [Link]
cat > [Link] << 'EOF'
{
"name": "my-docker-app",
"version": "1.0.0",
"description": "A simple [Link] app for Docker demo",
"main": "[Link]",
"scripts": {
"start": "node [Link]"
},
"dependencies": {
"express": "^4.18.2"
}
}
EOF

Create [Link] (Main App File)

// [Link]
const express = require('express');
const app = express();
const PORT = [Link] || 3000;

[Link]('/', (req, res) => {


[Link](`
<html>
<body style='font-family:Arial; text-align:center; margin-top:100px;'>
<h1> Hello from Docker!</h1>
<p>This app is running inside a Docker Container</p>
<p>Server Time: ${new Date().toISOString()}</p>
</body>
</html>
`);
});

[Link](PORT, () => {
[Link](`Server running on port ${PORT}`);
});
Step 3: Write a Dockerfile
Create a file named exactly 'Dockerfile' (no extension) in your project root:

# Dockerfile

# Step 1: Choose the base image


# alpine = lightweight Linux, node:18 = [Link] version 18
FROM node:18-alpine

# Step 2: Set the working directory inside the container


# All future commands will run from this path
WORKDIR /app

# Step 3: Copy package files FIRST (for Docker layer caching)


# This way, npm install only re-runs when [Link] changes
COPY package*.json ./

# Step 4: Install [Link] dependencies


RUN npm install --production

# Step 5: Copy the rest of your application code


COPY . .

# Step 6: Tell Docker which port the app listens on


# This is documentation — it doesn't actually open the port
EXPOSE 3000

# Step 7: Define the command to run when container starts


CMD ["node", "[Link]"]

Dockerfile Commands Explained

Command What It Does


FROM Specifies the base image to start from (like choosing
your OS + runtime)
WORKDIR Sets the working directory inside the container for all
commands
COPY Copies files from your local machine into the container
filesystem
RUN Executes a command during the image BUILD phase
(e.g., npm install)
EXPOSE Documents which port the container listens on
(informational)
CMD Specifies the default command to run when the
container STARTS
ENV Sets environment variables inside the container
ARG Defines build-time variables (only during build, not at
runtime)
VOLUME Creates a mount point for persistent data
ENTRYPOINT Sets the main executable (CMD provides default
arguments)

Create .dockerignore
Similar to .gitignore — tells Docker which files to EXCLUDE from the image:

# .dockerignore
node_modules
[Link]
.git
.gitignore
[Link]
.env
*.log
dist
.DS_Store

Why .dockerignore? Without it, COPY . . would copy node_modules (thousands of files) into
the image, making it huge. Always exclude node_modules and .git!

Step 4: Build the Docker Image


# Build the image
# -t = tag (name:version), . = use current directory as build context
docker build -t my-docker-app:1.0 .

# You will see output like:


# [1/5] FROM node:18-alpine
# [2/5] WORKDIR /app
# [3/5] COPY package*.json ./
# [4/5] RUN npm install
# [5/5] COPY . .
# Successfully built abc123def456
# Successfully tagged my-docker-app:1.0

# Verify the image was created


docker images

Step 5: Run the Docker Container


# Run the container
# -d = run in background (detached mode)
# -p 8080:3000 = map host port 8080 to container port 3000
# --name = give the container a friendly name
docker run -d -p 8080:3000 --name myapp my-docker-app:1.0

# Verify container is running


docker ps

# Expected output:
# CONTAINER ID IMAGE COMMAND STATUS PORTS
# a1b2c3d4e5f6 my-docker-app:1.0 'node [Link]' Up 30 seconds [Link]:8080-
>3000/tcp

Step 6: Port Mapping Explained


Port mapping is one of the most important Docker concepts. It connects your computer's port to
the container's port:

-p HOST_PORT:CONTAINER_PORT → -p 8080:3000 Host Port (8080) = The port on


YOUR machine (your laptop/server) Container Port (3000) = The port the app listens on INSIDE
the container Result: Opening localhost:8080 in your browser talks to the container's port 3000

Port mapping examples:

# Map same port numbers


docker run -p 3000:3000 my-app

# Map different port numbers


docker run -p 8080:3000 my-app

# Run multiple instances on different host ports


docker run -p 8080:3000 --name app1 my-app
docker run -p 8081:3000 --name app2 my-app
docker run -p 8082:3000 --name app3 my-app

Step 7: Access the Project in Browser


Open your web browser and navigate to:

[Link]

You should see: " Hello from Docker!" — your app is running inside a container!

# Useful commands while your container is running:


# View container logs (live)
docker logs -f myapp

# Execute a command inside the container


docker exec -it myapp sh

# Stop the container


docker stop myapp

# Start it again
docker start myapp

# Remove the container


docker rm myapp

4 Real-World Use Case

How to Share Your Project With a Friend


Now for the magic! There are two main ways to share your Docker project:

Option A: Share via Docker Hub (Recommended)

# Step 1: Create a free account at [Link]

# Step 2: Login to Docker Hub from terminal


docker login
# Enter your Docker Hub username and password

# Step 3: Tag your image with your Docker Hub username


# Format: docker tag LOCAL_IMAGE USERNAME/REPO_NAME:TAG
docker tag my-docker-app:1.0 yourUsername/my-docker-app:1.0

# Step 4: Push the image to Docker Hub


docker push yourUsername/my-docker-app:1.0

# Your image is now publicly available!


# Share this with your friend: yourUsername/my-docker-app:1.0

Option B: Share via Docker Archive File

# Save the image as a .tar file


docker save -o [Link] my-docker-app:1.0
# Send the .tar file to your friend (via USB, Google Drive, etc.)

# Your friend loads it on their machine:


docker load -i [Link]

# Then runs it:


docker run -d -p 8080:3000 my-docker-app:1.0

How Your Friend Runs It (Without Installing ANYTHING)


Your friend only needs to have Docker installed. That's it. Here is their complete setup:

# Your friend does ONLY these steps:

# Step 1: Pull your image from Docker Hub


docker pull yourUsername/my-docker-app:1.0

# Step 2: Run it
docker run -d -p 8080:3000 yourUsername/my-docker-app:1.0

# Step 3: Open browser


# [Link]

# That's it! No [Link] installation.


# No npm install. No dependency conflicts.
# It just works — same as on your machine!

This is the power of Docker! Your friend did NOT need to install [Link], npm, express, or
any other dependency. Everything is baked into the Docker image.

5 Important Docker Commands

Essential Commands Reference

docker build — Build an Image


Reads the Dockerfile and creates a new Docker Image:

# Basic build (uses Dockerfile in current directory)


docker build -t my-app .
# Build with specific tag/version
docker build -t my-app:2.0 .

# Build from a different directory


docker build -t my-app -f /path/to/Dockerfile .

# Build without cache (fresh build)


docker build --no-cache -t my-app .

# Build and see detailed output


docker build --progress=plain -t my-app .

docker run — Run a Container


Creates and starts a container from an image:

# Basic run
docker run my-app

# Run in background (detached)


docker run -d my-app

# Run with port mapping


docker run -d -p 8080:3000 my-app

# Run with a custom name


docker run -d --name mycontainer my-app

# Run with environment variables


docker run -d -e NODE_ENV=production -e PORT=5000 my-app

# Run with a volume (persistent storage)


docker run -d -v /host/path:/container/path my-app

# Run interactively (great for debugging)


docker run -it my-app sh

# Automatically remove container when it stops


docker run --rm my-app

docker ps — List Running Containers

# Show running containers only


docker ps

# Show ALL containers (including stopped)


docker ps -a

# Show only container IDs


docker ps -q

# Show containers with specific format


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

docker stop / start / restart — Control Containers

# Stop a container gracefully


docker stop mycontainer

# Stop multiple containers


docker stop container1 container2 container3

# Start a stopped container


docker start mycontainer

# Restart a container
docker restart mycontainer

# Force kill a container immediately


docker kill mycontainer

# Remove a stopped container


docker rm mycontainer

# Remove a running container (force)


docker rm -f mycontainer

# Remove ALL stopped containers


docker container prune

docker images — Manage Images

# List all local images


docker images

# Pull an image from Docker Hub


docker pull node:18-alpine

# Push image to Docker Hub


docker push yourUsername/my-app:1.0

# Remove an image
docker rmi my-app:1.0

# Remove ALL unused images


docker image prune -a

# Inspect image details


docker inspect my-app

# View image build history/layers


docker history my-app
Other Useful Commands

# View real-time logs


docker logs -f mycontainer

# Execute command in running container


docker exec -it mycontainer sh

# Copy files between container and host


docker cp mycontainer:/app/[Link] ./[Link]
docker cp ./[Link] mycontainer:/app/[Link]

# View resource usage (CPU, memory)


docker stats

# View all Docker system info


docker info

# Clean up everything unused


docker system prune -a

# View Docker networks


docker network ls

6 Advanced Concepts (Beginner Friendly)

Volumes — Persistent Data Storage


By default, data inside a container is lost when the container stops. Volumes solve this by
mapping a folder inside the container to a folder on your host machine.

Analogy: Think of the container as a hotel room and the volume as your personal locker. Even
when you check out (container stops), your belongings (data) remain in the locker.

# Mount a volume: -v HOST_PATH:CONTAINER_PATH


docker run -d \
-p 8080:3000 \
-v $(pwd)/data:/app/data \
--name myapp \
my-docker-app

# Named volumes (Docker manages the location)


docker volume create mydata
docker run -d -v mydata:/app/data my-docker-app

# List all volumes


docker volume ls
# Inspect a volume
docker volume inspect mydata

# Remove unused volumes


docker volume prune

Common Volume Use Cases


• Database data (MongoDB, MySQL, PostgreSQL) — so data persists after container
restart
• Application logs — access log files from your host machine
• Development hot-reload — mount source code so code changes reflect instantly
• Config files — inject configuration without rebuilding the image

Environment Variables
Environment variables let you configure your app without changing the code. This is essential
for secrets, API keys, database URLs, and configuration that differs between environments.

# Pass env variables with -e flag


docker run -d \
-e NODE_ENV=production \
-e DB_HOST=localhost \
-e DB_PASSWORD=secret123 \
-e API_KEY=your-api-key \
-p 3000:3000 \
my-app

# Use a .env file (recommended!)


docker run -d --env-file .env -p 3000:3000 my-app

# Sample .env file:


# NODE_ENV=production
# DB_HOST=localhost
# DB_PASSWORD=secret123

# Access in your [Link] code:


# const dbHost = [Link].DB_HOST;
# const port = [Link] || 3000;

Security Tip: Never hardcode secrets in your Dockerfile or image! Always pass them as
environment variables at runtime. Add .env to your .dockerignore and .gitignore files.

Docker Compose — Managing Multiple Containers


Real applications usually have multiple services — a web server, a database, a cache, maybe a
message queue. Docker Compose lets you define and run all of them with a single YAML file.

Example: [Link] App + MongoDB + Redis

# [Link]

version: '3.8'

services:
# Your [Link] application
app:
build: .
ports:
- '8080:3000'
environment:
- NODE_ENV=production
- MONGO_URI=mongodb://mongodb:27017/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- mongodb
- redis
volumes:
- ./logs:/app/logs

# MongoDB database
mongodb:
image: mongo:6
ports:
- '27017:27017'
volumes:
- mongo_data:/data/db
environment:
- MONGO_INITDB_DATABASE=mydb

# Redis cache
redis:
image: redis:7-alpine
ports:
- '6379:6379'

# Named volumes for persistence


volumes:
mongo_data:

Docker Compose Commands

# Start all services (build images if needed)


docker compose up -d

# Stop all services


docker compose down

# Stop and remove volumes (WARNING: deletes data!)


docker compose down -v

# Rebuild images and restart


docker compose up -d --build

# View logs for all services


docker compose logs -f

# View logs for a specific service


docker compose logs -f app

# Scale a service (run 3 instances of app)


docker compose up -d --scale app=3

# Run a one-off command


docker compose exec app sh

Docker Compose is the #1 tool for local development! Define your entire stack (app +
database + cache) in one file. Share it with your team — everyone gets the same environment
with one command: docker compose up

7 Common Mistakes

Mistakes Every Docker Beginner Makes

Common Mistake How to Fix It


Using latest tag everywhere Always use specific versions: node:18-alpine not
node:latest
Copying node_modules into image Add node_modules to .dockerignore file
Port conflict error Check if port is in use: lsof -i :8080 — use a different
host port
Running as root user Add USER node in Dockerfile to run as non-root for
security
Not using .dockerignore Create .dockerignore to exclude .git,
node_modules, .env files
Putting RUN commands last Put rarely-changing commands early for better layer
caching
Forgetting -d flag Without -d the container runs in foreground, blocking
your terminal
Image vs Container confusion Image = recipe (static). Container = cooked dish
(running instance)
Storing secrets in Dockerfile Use environment variables or Docker secrets, never
hardcode in Dockerfile
Large image sizes Use alpine base images and multi-stage builds to reduce
size

Port Conflict Error — How to Debug


# Error: Bind for [Link]:8080 failed: port is already allocated

# Find what's using the port (Linux/Mac)


lsof -i :8080
sudo netstat -tulpn | grep :8080

# Find what's using the port (Windows)


netstat -ano | findstr :8080

# Solution 1: Use a different host port


docker run -p 9090:3000 my-app

# Solution 2: Stop the container using the port


docker stop container_using_8080

8 Best Practices

1. Use Lightweight Base Images


# ❌ Heavy — full OS with many unused packages
FROM node:18

# ✅ Lightweight — Alpine Linux, much smaller


FROM node:18-alpine

# Image size comparison:


# node:18 = ~1 GB
# node:18-alpine = ~180 MB
# Much faster to download and push!

2. Use Multi-Stage Builds (Advanced)


Multi-stage builds let you use multiple FROM statements to create smaller final images. Perfect
for compiled languages or when you need build tools that aren't needed at runtime.
# Multi-stage Dockerfile example

# Stage 1: Build stage (has all dev dependencies)


FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci # Clean install
COPY . .
RUN npm run build # Build the app

# Stage 2: Production stage (only what's needed to run)


FROM node:18-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY [Link] .
CMD ["node", "dist/[Link]"]

# Result: Final image has no dev tools, much smaller!

3. Optimize Layer Caching


Docker caches each Dockerfile step as a layer. If a layer changes, all layers after it are rebuilt.
Structure your Dockerfile to maximize caching:

# ❌ Bad — code changes invalidate npm install cache


FROM node:18-alpine
WORKDIR /app
COPY . . # Copies everything — cache busted on ANY change!
RUN npm install
CMD ["node", "[Link]"]

# ✅ Good — npm install is cached unless [Link] changes


FROM node:18-alpine
WORKDIR /app
COPY package*.json ./ # Only copy package files first
RUN npm install # This layer is cached!
COPY . . # Source changes don't bust npm cache
CMD ["node", "[Link]"]

4. Security Best Practices


# Run as non-root user
FROM node:18-alpine
WORKDIR /app
COPY --chown=node:node package*.json ./
RUN npm ci --production
COPY --chown=node:node . .
USER node # Switch to non-root user
CMD ["node", "[Link]"]

# Never store secrets in images


# ❌ Bad
ENV API_KEY=mysecretkey123

# ✅ Good — pass at runtime


docker run -e API_KEY=mysecretkey123 my-app

# Use Docker secrets for production


docker secret create api_key [Link]

5. Tag Images Properly


# ❌ Avoid using 'latest' in production
docker pull my-app:latest

# ✅ Always use specific versions


docker pull my-app:1.2.3
docker pull my-app:2024-01-15

# Good tagging strategy:


docker build -t myapp:1.0.0 .
docker build -t myapp:1.0 .
docker build -t myapp:latest .

# Using git commit hash for traceability:


GIT_HASH=$(git rev-parse --short HEAD)
docker build -t myapp:${GIT_HASH} .

Complete Real Project — [Link] REST API

Project: A Simple REST API with Docker


Let's build a complete, production-ready [Link] REST API with Docker. This project is suitable
for portfolios and real-world use.

Project Structure

my-api/
├── Dockerfile
├── [Link]
├── .dockerignore
├── .[Link]
├── [Link]
├── [Link]
└── src/
├── [Link]
├── routes/
│ └── [Link]
└── data/
└── [Link]

[Link]

{
"name": "my-api",
"version": "1.0.0",
"description": "REST API with Docker",
"main": "src/[Link]",
"scripts": {
"start": "node src/[Link]",
"dev": "nodemon src/[Link]"
},
"dependencies": {
"express": "^4.18.2",
"cors": "^2.8.5"
},
"devDependencies": {
"nodemon": "^3.0.2"
}
}

src/[Link]

const express = require('express');


const cors = require('cors');
const usersRouter = require('./routes/users');

const app = express();


const PORT = [Link] || 3000;

[Link](cors());
[Link]([Link]());

// Health check endpoint


[Link]('/health', (req, res) => {
[Link]({
status: 'healthy',
environment: [Link].NODE_ENV || 'development',
uptime: [Link](),
timestamp: new Date().toISOString()
});
});

// Routes
[Link]('/api/users', usersRouter);

// Root endpoint
[Link]('/', (req, res) => {
[Link]({
message: ' Welcome to Dockerized REST API!',
endpoints: {
health: 'GET /health',
users: 'GET /api/users',
user: 'GET /api/users/:id',
create: 'POST /api/users',
}
});
});

[Link](PORT, '[Link]', () => {


[Link](` Server running on port ${PORT}`);
[Link](` Environment: ${[Link].NODE_ENV || 'development'}`);
});

src/routes/[Link]

const express = require('express');


const router = [Link]();

// In-memory data (use a database in production!)


let users = [
{ id: 1, name: 'Alice Johnson', email: 'alice@[Link]', role: 'admin' },
{ id: 2, name: 'Bob Smith', email: 'bob@[Link]', role: 'user' },
{ id: 3, name: 'Charlie Dev', email: 'charlie@[Link]', role: 'user' },
];

// GET all users


[Link]('/', (req, res) => {
[Link]({ success: true, count: [Link], data: users });
});

// GET single user


[Link]('/:id', (req, res) => {
const user = [Link](u => [Link] === parseInt([Link]));
if (!user) return [Link](404).json({ success: false, message: 'User not
found' });
[Link]({ success: true, data: user });
});

// POST create user


[Link]('/', (req, res) => {
const { name, email, role = 'user' } = [Link];
if (!name || !email) {
return [Link](400).json({ success: false, message: 'Name and email
required' });
}
const newUser = { id: [Link] + 1, name, email, role };
[Link](newUser);
[Link](201).json({ success: true, data: newUser });
});

[Link] = router;
Dockerfile (Production-Ready)

# Production-ready Dockerfile
FROM node:18-alpine

# Install dumb-init for proper signal handling


RUN apk add --no-cache dumb-init

# Set environment
ENV NODE_ENV=production

# Set working directory


WORKDIR /app

# Copy and install dependencies


COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

# Copy source code


COPY --chown=node:node . .

# Switch to non-root user


USER node

# Expose port
EXPOSE 3000

# Use dumb-init to handle signals properly


ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["node", "src/[Link]"]

[Link]

version: '3.8'

services:
api:
build:
context: .
dockerfile: Dockerfile
ports:
- '8080:3000'
environment:
- NODE_ENV=production
- PORT=3000
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--quiet', '--tries=1', '--spider',
'[Link]
interval: 30s
timeout: 10s
retries: 3
volumes:
- ./logs:/app/logs

# Uncomment to add MongoDB:


# mongodb:
# image: mongo:6-jammy
# ports:
# - '27017:27017'
# volumes:
# - mongo_data:/data/db

# volumes:
# mongo_data:

.dockerignore

node_modules
[Link]
.git
.gitignore
[Link]
.env
*.env
logs
*.log
.DS_Store
coverage
.nyc_output
dist
*.md

Build and Run Commands

# === Using Docker directly ===

# Build the image


docker build -t my-api:1.0 .

# Run the container


docker run -d \
-p 8080:3000 \
-e NODE_ENV=production \
--name my-api \
my-api:1.0

# Test the API


curl [Link]
curl [Link]
curl [Link]
curl [Link]

# Create a new user


curl -X POST [Link] \
-H 'Content-Type: application/json' \
-d '{"name":"Dave","email":"dave@[Link]"}'
# === Using Docker Compose ===

# Start all services


docker compose up -d

# View logs
docker compose logs -f api

# Stop everything
docker compose down

Expected API Responses

# GET /
{
"message": " Welcome to Dockerized REST API!",
"endpoints": { ... }
}

# GET /health
{
"status": "healthy",
"environment": "production",
"uptime": 42.5
}

# GET /api/users
{
"success": true,
"count": 3,
"data": [
{ "id": 1, "name": "Alice Johnson", "email": "alice@[Link]" },
...
]
}

9 Summary & Interview Guide

Step-by-Step Recap
Step What You Did
1. Install Docker Set up Docker Desktop on Windows/Mac or Docker
Engine on Linux
2. Create project Built a [Link] Express app with a proper project
structure
3. Write Dockerfile Defined the environment: base image, working dir,
dependencies, start command
4. Create .dockerignore Excluded unnecessary files from the image
(node_modules, .git, .env)
5. Build image docker build -t my-app . — created a portable Docker
image
6. Run container docker run -d -p 8080:3000 my-app — started the
containerized app
7. Access in browser Opened localhost:8080 — saw the app running from
inside Docker
8. Push to Docker Hub docker push username/my-app — shared the image with
the world
9. Friend pulls & runs docker pull + docker run — friend runs with zero setup!
10. Docker Compose docker compose up — orchestrated multi-service
applications

Interview-Ready Explanation
If an interviewer asks 'Explain Docker in simple terms', here is a perfect answer:

"Docker is a containerization platform that packages an application and all its dependencies
— runtime, libraries, configuration — into a single, self-contained unit called a container. Unlike
virtual machines, containers share the host OS kernel, making them lightweight and fast. A
Dockerfile defines the recipe to build an image, and containers are running instances of those
images. Docker solves the classic 'works on my machine' problem by ensuring consistent
environments across development, testing, and production."

Key Terms Cheat Sheet


Term One-Line Definition
Docker Platform to build, ship, and run containers
Container A running isolated instance of a Docker image
Image A read-only blueprint/template to create containers
Dockerfile Script of instructions to build a Docker image
Docker Hub Public registry to store and share Docker images
Volume Persistent storage that survives container restarts
Port Mapping Connecting host port to container port (-p host:container)
Docker Compose Tool to define and run multi-container applications
Registry Storage location for Docker images (Hub, ECR, GCR,
etc.)
Layer Each Dockerfile instruction creates a cached layer in the
image

Happy Dockerizing!
You now have everything you need to containerize any project

By Abhishek Rathor [Ig :code.abhii07] | SYNTAX ERROR.

You might also like