Introduction to Docker

Docker packages applications and their dependencies into lightweight, portable containers that run consistently across different environments.

Basic Docker Concepts

Dockerfile - Building Images



dockerfile

# Dockerfile for Node.js app
FROM node:18-alpine

# Set working directory
WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy application code
COPY . .

# Expose port
EXPOSE 3000

# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

# Change ownership
RUN chown -R nextjs:nodejs /app
USER nextjs

# Start application
CMD ["npm", "start"]

Basic Docker Commands



bash

# Build image
docker build -t myapp:latest .

# Run container
docker run -d -p 3000:3000 --name myapp-container myapp:latest

# List containers
docker ps
docker ps -a  # Include stopped containers

# View logs
docker logs myapp-container
docker logs -f myapp-container  # Follow logs

# Execute commands in container
docker exec -it myapp-container /bin/sh

# Stop and remove container
docker stop myapp-container
docker rm myapp-container

# Remove image
docker rmi myapp:latest

Multi-Stage Dockerfile



dockerfile

# Multi-stage build for React app
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM nginx:alpine AS production

# Copy built files
COPY --from=builder /app/dist /usr/share/nginx/html

# Copy custom nginx config
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Docker Compose Basics

Docker Compose orchestrates multi-container applications using a YAML file.

Basic docker-compose.yml



yaml

# docker-compose.yml
version: '3.8'

services:
  # Web application
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
    volumes:
      - .:/app
      - /app/node_modules
    depends_on:
      - db
      - redis
    networks:
      - app-network

  # PostgreSQL database
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"
    networks:
      - app-network

  # Redis cache
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    networks:
      - app-network

# Named volumes
volumes:
  postgres_data:
  redis_data:

# Custom network
networks:
  app-network:
    driver: bridge

Docker Compose Commands



bash

# Start all services
docker-compose up
docker-compose up -d  # Detached mode

# Build and start
docker-compose up --build

# Start specific service
docker-compose up web

# Stop services
docker-compose down
docker-compose down -v  # Remove volumes

# View logs
docker-compose logs
docker-compose logs web  # Specific service

# Execute commands
docker-compose exec web npm test
docker-compose exec db psql -U user -d myapp

# Scale services
docker-compose up -d --scale web=3

Development Environment Setup

Full-Stack Development Environment



yaml

# docker-compose.dev.yml
version: '3.8'

services:
  # Frontend (React)
  frontend:
    build:
      context: ./frontend
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./frontend:/app
      - /app/node_modules
    environment:
      - REACT_APP_API_URL=http://localhost:8000
    depends_on:
      - backend

  # Backend (Node.js API)
  backend:
    build:
      context: ./backend
      dockerfile: Dockerfile.dev
    ports:
      - "8000:8000"
    volumes:
      - ./backend:/app
      - /app/node_modules
    environment:
      - DATABASE_URL=postgresql://dev:dev@postgres:5432/devdb
      - REDIS_URL=redis://redis:6379
    depends_on:
      - postgres
      - redis
    command: npm run dev

  # PostgreSQL Database
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: devdb
      POSTGRES_USER: dev
      POSTGRES_PASSWORD: dev
    volumes:
      - postgres_dev_data:/var/lib/postgresql/data
      - ./backend/database/init.sql:/docker-entrypoint-initdb.d/init.sql
    ports:
      - "5432:5432"

  # Redis Cache
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    volumes:
      - redis_dev_data:/data

  # pgAdmin for database management
  pgadmin:
    image: dpage/pgadmin4
    environment:
      PGADMIN_DEFAULT_EMAIL: admin@example.com
      PGADMIN_DEFAULT_PASSWORD: admin
    ports:
      - "8080:80"
    depends_on:
      - postgres

volumes:
  postgres_dev_data:
  redis_dev_data:

Production-Ready Docker Setup



yaml

# docker-compose.prod.yml
version: '3.8'

services:
  # Nginx reverse proxy
  nginx:
    image: nginx:alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
    depends_on:
      - web
    restart: unless-stopped

  # Web application
  web:
    build:
      context: .
      dockerfile: Dockerfile.prod
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://prod_user:${DB_PASSWORD}@db:5432/proddb
    depends_on:
      - db
    restart: unless-stopped
    deploy:
      replicas: 3
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

  # Production database
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: proddb
      POSTGRES_USER: prod_user
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - postgres_prod_data:/var/lib/postgresql/data
    restart: unless-stopped
    deploy:
      resources:
        limits:
          memory: 1G

volumes:
  postgres_prod_data:

Development Dockerfiles

Frontend Development Dockerfile



dockerfile

# frontend/Dockerfile.dev
FROM node:18-alpine

WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm install

# Copy source code
COPY . .

# Expose port
EXPOSE 3000

# Start development server
CMD ["npm", "start"]

Backend Development Dockerfile



dockerfile

# backend/Dockerfile.dev
FROM node:18-alpine

# Install nodemon globally for hot reloading
RUN npm install -g nodemon

WORKDIR /app

# Copy package files
COPY package*.json ./
RUN npm install

# Copy source code
COPY . .

# Expose port
EXPOSE 8000

# Start with nodemon for hot reloading
CMD ["nodemon", "server.js"]

Environment Configuration

.env Files



bash

# .env.development
DATABASE_URL=postgresql://dev:dev@localhost:5432/devdb
REDIS_URL=redis://localhost:6379
JWT_SECRET=dev-secret-key
NODE_ENV=development

# .env.production
DATABASE_URL=postgresql://prod_user:strong_password@db:5432/proddb
REDIS_URL=redis://redis:6379
JWT_SECRET=super-secure-production-key
NODE_ENV=production

Environment-Specific Compose Files



bash

# Development
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up

# Production
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d

# Testing
docker-compose -f docker-compose.yml -f docker-compose.test.yml up --abort-on-container-exit

Docker Best Practices

Optimized Dockerfile



dockerfile

# Use specific versions
FROM node:18.17.0-alpine

# Set working directory
WORKDIR /app

# Copy package files first (for better caching)
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production && npm cache clean --force

# Copy application code
COPY . .

# Create non-root user
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nextjs -u 1001 && \
    chown -R nextjs:nodejs /app

USER nextjs

# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD curl -f http://localhost:3000/health || exit 1

# Expose port
EXPOSE 3000

# Start application
CMD ["npm", "start"]

Docker Networking and Volumes

Custom Networks



yaml

# docker-compose.yml with custom networks
version: '3.8'

services:
  frontend:
    build: ./frontend
    networks:
      - frontend-network

  backend:
    build: ./backend
    networks:
      - frontend-network
      - backend-network

  database:
    image: postgres:15
    networks:
      - backend-network

networks:
  frontend-network:
    driver: bridge
  backend-network:
    driver: bridge
    internal: true  # No external access

Volume Management



yaml

services:
  web:
    image: myapp
    volumes:
      # Named volume
      - app_data:/app/data
      
      # Bind mount (development)
      - ./src:/app/src:ro  # Read-only
      
      # Anonymous volume
      - /app/node_modules

volumes:
  app_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /host/path/data

Complete Example: MERN Stack



yaml

# docker-compose.mern.yml
version: '3.8'

services:
  # React Frontend
  client:
    build:
      context: ./client
      dockerfile: Dockerfile.dev
    ports:
      - "3000:3000"
    volumes:
      - ./client:/app
      - /app/node_modules
    environment:
      - REACT_APP_API_URL=http://localhost:5000
    stdin_open: true
    tty: true

  # Express Backend
  server:
    build:
      context: ./server
      dockerfile: Dockerfile.dev
    ports:
      - "5000:5000"
    volumes:
      - ./server:/app
      - /app/node_modules
    environment:
      - MONGO_URI=mongodb://mongo:27017/mernapp
      - JWT_SECRET=your-jwt-secret
    depends_on:
      - mongo

  # MongoDB Database
  mongo:
    image: mongo:6
    ports:
      - "27017:27017"
    volumes:
      - mongo_data:/data/db
    environment:
      - MONGO_INITDB_ROOT_USERNAME=admin
      - MONGO_INITDB_ROOT_PASSWORD=password

  # MongoDB Admin Interface
  mongo-express:
    image: mongo-express
    ports:
      - "8081:8081"
    environment:
      - ME_CONFIG_MONGODB_SERVER=mongo
      - ME_CONFIG_MONGODB_ADMINUSERNAME=admin
      - ME_CONFIG_MONGODB_ADMINPASSWORD=password
    depends_on:
      - mongo

volumes:
  mongo_data:

Useful Docker Commands



bash

# System management
docker system df          # Check disk usage
docker system prune       # Clean up unused resources
docker system prune -a    # Remove all unused images

# Image management
docker images             # List images
docker image prune        # Remove unused images
docker pull nginx:latest  # Pull specific image

# Container management
docker stats              # Resource usage
docker inspect container  # Detailed container info
docker cp file container:/path  # Copy files

# Compose management
docker-compose config     # Validate compose file
docker-compose ps         # List compose services
docker-compose pull       # Pull latest images

Troubleshooting Tips



bash

# Debug container issues
docker logs -f container-name
docker exec -it container-name /bin/sh
docker inspect container-name

# Network debugging
docker network ls
docker network inspect network-name

# Volume debugging
docker volume ls
docker volume inspect volume-name

# Clean up everything
docker-compose down -v --remove-orphans
docker system prune -a --volumes