Introduction to Docker Containerization
Docker has revolutionized application deployment by providing lightweight, portable containers that ensure consistency across different environments. This comprehensive guide will teach you everything you need to know about containerizing and deploying applications using Docker.
Why Use Docker?
Docker offers numerous advantages for application deployment:
- Consistency: Applications run the same way across development, testing, and production
- Isolation: Each container runs independently without affecting others
- Portability: Containers can run on any system that supports Docker
- Scalability: Easy to scale applications horizontally
- Resource Efficiency: Containers share the host OS kernel, using fewer resources than VMs
Docker Installation
Ubuntu/Debian Installation
# Update package index
sudo apt update
# Install prerequisites
sudo apt install -y apt-transport-https ca-certificates curl gnupg lsb-release
# Add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io
# Add user to docker group
sudo usermod -aG docker $USER
# Start Docker service
sudo systemctl start docker
sudo systemctl enable docker
CentOS/RHEL Installation
# Install yum-utils
sudo yum install -y yum-utils
# Add Docker repository
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# Install Docker
sudo yum install -y docker-ce docker-ce-cli containerd.io
# Start Docker
sudo systemctl start docker
sudo systemctl enable docker
Docker Basics
Essential Docker Commands
# Check Docker version
docker --version
# Run a container
docker run hello-world
# List running containers
docker ps
# List all containers
docker ps -a
# List images
docker images
# Stop a container
docker stop container_name
# Remove a container
docker rm container_name
# Remove an image
docker rmi image_name
Creating Your First Dockerfile
Node.js Application Example
# Dockerfile for Node.js application
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 . .
# Create non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001
# Change ownership of the app directory
RUN chown -R nextjs:nodejs /app
USER nextjs
# 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 application
CMD ["npm", "start"]
Python Application Example
# Dockerfile for Python application
FROM python:3.11-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Set working directory
WORKDIR /app
# Install system dependencies
RUN apt-get update \
&& apt-get install -y --no-install-recommends gcc \
&& rm -rf /var/lib/apt/lists/*
# Copy requirements and install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application code
COPY . .
# Create non-root user
RUN adduser --disabled-password --gecos '' appuser
RUN chown -R appuser:appuser /app
USER appuser
# Expose port
EXPOSE 8000
# Start application
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "app:app"]
Multi-Stage Builds
Multi-stage builds help reduce image size by separating build dependencies from runtime dependencies:
# Multi-stage Dockerfile for Node.js
# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Production stage
FROM node:18-alpine AS production
WORKDIR /app
# Copy only production dependencies and built app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
# Create non-root user
RUN addgroup -g 1001 -S nodejs && adduser -S nextjs -u 1001
RUN chown -R nextjs:nodejs /app
USER nextjs
EXPOSE 3000
CMD ["npm", "start"]
Docker Compose
Docker Compose allows you to define and run multi-container applications:
Installation
# Download Docker Compose
sudo curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# Make executable
sudo chmod +x /usr/local/bin/docker-compose
# Verify installation
docker-compose --version
Docker Compose Example
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/myapp
depends_on:
- db
- redis
restart: unless-stopped
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=myapp
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7-alpine
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./ssl:/etc/nginx/ssl
depends_on:
- app
restart: unless-stopped
volumes:
postgres_data:
Docker Compose Commands
# Start services
docker-compose up -d
# View logs
docker-compose logs -f
# Stop services
docker-compose down
# Rebuild and start
docker-compose up --build -d
# Scale services
docker-compose up --scale app=3 -d
Production Deployment Strategies
Docker Swarm
# Initialize swarm
docker swarm init
# Deploy stack
docker stack deploy -c docker-compose.yml myapp
# List services
docker service ls
# Scale service
docker service scale myapp_app=3
# Update service
docker service update --image myapp:v2 myapp_app
Environment Variables and Secrets
# .env file
NODE_ENV=production
DATABASE_URL=postgresql://user:password@db:5432/myapp
JWT_SECRET=your-secret-key
# Using secrets in Docker Swarm
echo "my-secret-password" | docker secret create db_password -
# docker-compose.yml with secrets
version: '3.8'
services:
app:
image: myapp:latest
secrets:
- db_password
environment:
- DATABASE_PASSWORD_FILE=/run/secrets/db_password
secrets:
db_password:
external: true
Best Practices
Security Best Practices
- Use official base images from trusted sources
- Keep images updated with security patches
- Run containers as non-root users
- Use multi-stage builds to reduce attack surface
- Scan images for vulnerabilities
- Use secrets management for sensitive data
Performance Optimization
- Use .dockerignore to exclude unnecessary files
- Minimize the number of layers
- Use specific tags instead of 'latest'
- Leverage build cache effectively
- Use Alpine Linux for smaller images
Sample .dockerignore
node_modules
npm-debug.log
.git
.gitignore
README.md
.env
.nyc_output
coverage
.cache
.DS_Store
Monitoring and Logging
Container Monitoring
# View container stats
docker stats
# View container logs
docker logs -f container_name
# Execute commands in running container
docker exec -it container_name bash
# Copy files from container
docker cp container_name:/app/file.txt ./file.txt
Health Checks
# Dockerfile health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
# Docker Compose health check
services:
app:
build: .
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
CI/CD Integration
GitHub Actions Example
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: myapp:latest,myapp:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
Troubleshooting Common Issues
Container Won't Start
- Check logs:
docker logs container_name
- Verify port bindings
- Check environment variables
- Ensure dependencies are available
Performance Issues
- Monitor resource usage:
docker stats
- Optimize Dockerfile for layer caching
- Use appropriate base images
- Configure resource limits
Conclusion
Docker containerization provides a robust foundation for modern application deployment. By following these best practices and examples, you can create efficient, secure, and scalable containerized applications. Remember to keep security, performance, and maintainability in mind throughout your containerization journey.
Ready to deploy your containerized applications? Get started with RexZ Cloud VPS hosting with Docker pre-installed and optimized for container workloads.