Docker Container: Fundamentals, Images, Dockerfile & Docker Compose
Docker revolutionized software development through containerization. It enables consistent environments from development to production and solves the “works on my machine” problem.
Docker Fundamentals
What is Containerization?
Containerization is an operating system-level virtualization technology that runs applications with all their dependencies in isolated environments.
Docker vs Virtual Machines
# Virtual Machine (VM)
# - Complete operating system
# - Hypervisor required
# - High resource consumption
# - Slow startup
# Docker Container
# - Shared operating system kernel
# - No hypervisor required
# - Low resource consumption
# - Fast startup
Docker Architecture
# Docker Components
# 1. Docker Daemon (dockerd)
# - Manages containers, images, networks, volumes
# - Runs in the background
# - API endpoint for clients
# 2. Docker Client (docker)
# - Command-line interface
# - Communicates with Docker Daemon
# - User interaction
# 3. Docker Registry
# - Storage for images (Docker Hub)
# - Public and private registries
# 4. Docker Objects
# - Images: Templates for containers
# - Containers: Running instances
# - Networks: Container communication
# - Volumes: Data storage
Docker Installation and Setup
Installation
# Ubuntu/Debian
sudo apt update
sudo apt install docker.io
sudo systemctl start docker
sudo systemctl enable docker
# CentOS/RHEL
sudo yum install docker
sudo systemctl start docker
sudo systemctl enable docker
# Docker Desktop (Windows/Mac)
# Download from https://www.docker.com/products/docker-desktop
# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker
# Verify installation
docker --version
docker info
Basic Commands
# Docker version and system information
docker version
docker info
docker system df
# Manage images
docker images
docker pull ubuntu:latest
docker search nginx
docker rmi nginx:latest
# Manage containers
docker ps # Running containers
docker ps -a # All containers
docker run nginx # Start container
docker stop container_id # Stop container
docker rm container_id # Remove container
# Logs and inspection
docker logs container_id
docker inspect container_id
docker exec -it container_id bash
Docker Images
What are Docker Images?
Docker images are read-only templates used to create containers. They consist of multiple layers.
Image Structure
# Docker image layer structure
# 1. Base Layer (e.g. Ubuntu)
# 2. Dependencies Layer (e.g. Python)
# 3. Application Layer (e.g. Web app)
# 4. Configuration Layer (e.g. environment variables)
# Display layers
docker history nginx:latest
# Image information
docker inspect nginx:latest
Dockerfile
A Dockerfile is a text file with instructions for creating a Docker image.
# Dockerfile example for Node.js application
# Base image
FROM node:16-alpine
# Metadata
LABEL maintainer="max@example.com"
LABEL version="1.0"
LABEL description="Node.js web application"
# Working directory
WORKDIR /app
# Environment variables
ENV NODE_ENV=production
ENV PORT=3000
# Copy files
COPY package*.json ./
RUN npm install --production
# Copy application code
COPY . .
# Create user (security best practice)
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# Start command
CMD ["node", "server.js"]
Dockerfile Best Practices
# Best practices for Dockerfile
# 1. Minimalist base image
FROM alpine:latest
# 2. Use specific tags (not latest)
FROM node:16.14.2-alpine
# 3. Use .dockerignore
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
# 4. Optimize layer caching
COPY package*.json ./
RUN npm install
COPY . .
# 5. Multi-stage builds
FROM node:16-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM node:16-alpine AS production
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
# 6. Security best practices
USER nonrootuser
RUN rm -rf /var/cache/apk/*
Create and manage images
# Build image
docker build -t myapp:1.0 .
docker build -t myapp:latest -f Dockerfile.prod .
# Image with build arguments
docker build --build-arg NODE_ENV=production -t myapp:prod .
# Multi-platform build
docker buildx build --platform linux/amd64,linux/arm64 -t myapp:multi .
# Tag images
docker tag myapp:1.0 myregistry/myapp:1.0
docker tag myapp:latest myregistry/myapp:latest
# Push images
docker login myregistry.com
docker push myregistry/myapp:1.0
docker push myregistry/myapp:latest
# Clean up images
docker image prune -f
docker image prune -a -f
Docker Containers
Container Lifecycle
# Create and start container
docker run --name mywebserver -d -p 8080:80 nginx
# Container with volumes
docker run --name mydb -v /data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=password mysql:8.0
# Container with network
docker network create mynetwork
docker run --name myapp --network mynetwork -d myapp:latest
# Manage containers
docker start mywebserver
docker stop mywebserver
docker restart mywebserver
docker pause mywebserver
docker unpause mywebserver
# Inspect containers
docker logs mywebserver
docker logs -f mywebserver # Follow logs
docker stats mywebserver # Resource usage
docker exec -it mywebserver bash
Container Configuration
# Resource limits
docker run --memory="512m" --cpus="1.0" myapp:latest
# Environment variables
docker run -e NODE_ENV=production -e PORT=3000 myapp:latest
# Volumes
docker run -v /host/path:/container/path myapp:latest
docker run -v myvolume:/container/path myapp:latest
# Ports
docker run -p 8080:80 -p 8443:443 myapp:latest
# Networks
docker run --network bridge myapp:latest
docker run --network host myapp:latest
docker run --network none myapp:latest
# Restart policies
docker run --restart=always myapp:latest
docker run --restart=on-failure:5 myapp:latest
docker run --restart=unless-stopped myapp:latest
Docker Volumes
# Volume types
# 1. Bind mounts: Host file system
docker run -v /host/data:/container/data myapp:latest
# 2. Named volumes: Docker-managed
docker volume create mydata
docker run -v mydata:/container/data myapp:latest
# 3. Anonymous volumes: Automatically created
docker run -v /container/data myapp:latest
# Volume management
docker volume ls
docker volume inspect mydata
docker volume rm mydata
docker volume prune
# Backup and restore
docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar czf /backup/mydata-backup.tar.gz /data
docker run --rm -v mydata:/data -v $(pwd):/backup alpine tar xzf /backup/mydata-backup.tar.gz -C /
Docker Networks
Network Types
# Bridge Network (Standard)
docker network create mybridge
docker run --network mybridge myapp:latest
# Host Network
docker run --network host myapp:latest
# None Network
docker run --network none myapp:latest
# Overlay Network (Multi-Host)
docker network create --driver overlay myoverlay
Network Configuration
# Create network
docker network create --driver bridge --subnet 192.168.1.0/24 mynetwork
# Container with network
docker run --network mynetwork --ip 192.168.1.10 myapp:latest
# Network connections
docker network connect mynetwork mycontainer
docker network disconnect mynetwork mycontainer
# Network inspection
docker network inspect mynetwork
docker network ls
docker network prune
Docker Compose
Docker Compose Basics
Docker Compose enables the definition and management of multi-container applications.
# docker-compose.yml
version: '3.8'
services:
# Web Service
web:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/myapp
depends_on:
- db
- redis
volumes:
- ./logs:/app/logs
restart: unless-stopped
networks:
- app-network
# Database Service
db:
image: postgres:13
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
restart: unless-stopped
networks:
- app-network
# Redis Cache
redis:
image: redis:6-alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
restart: unless-stopped
networks:
- app-network
# Nginx Reverse Proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- web
restart: unless-stopped
networks:
- app-network
# Volumes
volumes:
postgres_data:
redis_data:
# Networks
networks:
app-network:
driver: bridge
Docker Compose Commands
# Start services
docker-compose up
docker-compose up -d # Detached mode
docker-compose up --build # With rebuild
# Stop services
docker-compose down
docker-compose down -v # With volumes
# View logs
docker-compose logs
docker-compose logs -f web
docker-compose logs --tail=100 web
# Manage services
docker-compose ps
docker-compose restart web
docker-compose stop web
docker-compose start web
# Scaling
docker-compose up -d --scale web=3
# Build images
docker-compose build
docker-compose build --no-cache
docker-compose build web
# Environment variables
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
Environment-Specific Configuration
# docker-compose.override.yml (Development)
version: '3.8'
services:
web:
environment:
- NODE_ENV=development
volumes:
- .:/app
- /app/node_modules
command: npm run dev
db:
ports:
- "5432:5432"
# docker-compose.prod.yml (Production)
version: '3.8'
services:
web:
environment:
- NODE_ENV=production
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
nginx:
ports:
- "80:80"
- "443:443"
Docker Security
Security Best Practices
# 1. Minimal base image
FROM alpine:latest
# 2. Non-root user
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
USER appuser
# 3. Use secrets (not in image)
# docker run --secret=mysecret myapp:latest
# 4. READONLY filesystem
docker run --read-only --tmpfs /tmp myapp:latest
# 5. Resource limits
docker run --memory=512m --cpus=1.0 myapp:latest
Docker Security Scanning
# Scan image with Trivy
trivy image myapp:latest
# Docker Scout (official tool)
docker scout cves myapp:latest
# Security check in Dockerfile
hadolint Dockerfile
Docker Monitoring and Logging
Logging Strategies
# docker-compose.yml with logging configuration
version: '3.8'
services:
web:
image: myapp:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels:
- "logging=promtail"
# ELK Stack for logging
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.14.0
environment:
- discovery.type=single-node
volumes:
- elasticsearch_data:/usr/share/elasticsearch/data
logstash:
image: docker.elastic.co/logstash/logstash:7.14.0
volumes:
- ./logstash.conf:/usr/share/logstash/pipeline/logstash.conf
kibana:
image: docker.elastic.co/kibana/kibana:7.14.0
ports:
- "5601:5601"
depends_on:
- elasticsearch
Monitoring with Prometheus
# docker-compose.monitoring.yml
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
node-exporter:
image: prom/node-exporter:latest
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
volumes:
prometheus_data:
grafana_data:
Docker and Kubernetes
Kubernetes Basics
# kubernetes/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myregistry/myapp:1.0
ports:
- containerPort: 3000
env:
- name: NODE_ENV
value: "production"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
Docker to Kubernetes Migration
# Kompose for conversion
kompose convert -f docker-compose.yml
# Apply Kubernetes manifest
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml
# Manage deployment
kubectl get deployments
kubectl get pods
kubectl logs -f deployment/myapp-deployment
kubectl scale deployment myapp-deployment --replicas=5
Docker Best Practices
Performance Optimization
# Multi-stage build for smaller images
FROM node:16-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build
FROM node:16-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
Production Deployment
# docker-compose.prod.yml
version: '3.8'
services:
web:
image: myregistry/myapp:${VERSION}
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
failure_action: rollback
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Troubleshooting
Common Issues
# 1. Container won't start
docker logs container_id
docker inspect container_id
# 2. Out of disk space
docker system df
docker system prune -a -f
docker volume prune -f
# 3. Network issues
docker network inspect network_name
docker exec -it container_id ping other_container
# 4. Permission issues
sudo chown -R $USER:$USER /var/run/docker.sock
# 5. Image pull issues
docker system prune -f
docker pull --no-cache image_name
Debugging Techniques
# Inspect container
docker exec -it container_id /bin/sh
docker exec -it container_id /bin/bash
# Copy files
docker cp container_id:/path/file.txt .
docker cp file.txt container_id:/path/
# Analyze image layers
docker history image_name
dive image_name
# Performance analysis
docker stats
docker top container_id
Exam-Relevant Concepts
Important Docker Commands
| Command | Description | Usage |
|---|---|---|
docker build | Create image | From Dockerfile |
docker run | Start container | Run application |
docker-compose up | Start multi-container | Development environment |
docker push | Upload image | Registry upload |
docker pull | Download image | Registry download |
Typical Exam Tasks
- Create Dockerfiles for various applications
- Configure Docker Compose for multi-container apps
- Implement security best practices
- Optimize Docker images for production
- Migrate applications to Kubernetes
Summary
Docker is fundamental to modern software development:
- Containerization: Consistent environments everywhere
- Images: Reusable templates for applications
- Dockerfile: Automated build processes
- Docker Compose: Define multi-container applications
- Kubernetes: Orchestration for large deployments
Good Docker management requires understanding of container concepts, security practices, and orchestration techniques.