Containerization
Docker Containerization Complete Guide
Master Docker containerization from fundamentals to production deployment with multi-stage builds, container orchestration, security best practices, monitoring, and CI/CD integration on Ubuntu 24.04 LTS.
What you'll learn
- Install and configure Docker CE on Ubuntu 24.04 LTS
- Write optimized Dockerfiles with multi-stage builds
- Orchestrate multi-container apps with Docker Compose
- Implement container security best practices
- Set up monitoring and observability for containers
- Integrate Docker into CI/CD pipelines
- Deploy containers to production environments
Installation & Setup
Install Docker CE on Ubuntu 24.04 LTS using the official Docker repository for the latest stable release with full production support.
1# Remove old Docker installations
2sudo apt remove -y docker docker-engine docker.io containerd runc
3
4# Install prerequisites
5sudo apt update && sudo apt install -y ca-certificates curl gnupg
6
7# Add Docker's official GPG key
8sudo install -m 0755 -d /etc/apt/keyrings
9curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
10 sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
11sudo chmod a+r /etc/apt/keyrings/docker.gpg
12
13# Add the Docker repository
14echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
15 https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
16 sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
17
18# Install Docker Engine
19sudo apt update
20sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
21
22# Add current user to the docker group
23sudo usermod -aG docker $USER
24newgrp docker
25
26# Verify installation
27docker --version
28docker compose versionDocker Fundamentals
Understand the core concepts: images, containers, volumes, and networks.
1# Pull and run a container
2docker pull nginx:alpine
3docker run -d -p 8080:80 --name my-nginx nginx:alpine
4
5# List running containers
6docker ps
7
8# View logs
9docker logs my-nginx
10
11# Execute a command inside a container
12docker exec -it my-nginx sh
13
14# Stop and remove
15docker stop my-nginx && docker rm my-nginx
16
17# Manage volumes
18docker volume create my-data
19docker run -v my-data:/data alpine sh
20
21# Inspect networks
22docker network ls
23docker network inspect bridgeDockerfile Optimization
Write efficient Dockerfiles that produce small, secure, cache-friendly images.
1# Optimized Node.js Dockerfile
2FROM node:20-alpine AS base
3WORKDIR /app
4
5# Install dependencies separately for better cache
6FROM base AS deps
7COPY package*.json ./
8RUN npm ci --only=production
9
10FROM base AS build
11COPY package*.json ./
12RUN npm ci
13COPY . .
14RUN npm run build
15
16# Production image — minimal footprint
17FROM base AS runner
18ENV NODE_ENV=production
19RUN addgroup -S appgroup && adduser -S appuser -G appgroup
20COPY /app/node_modules ./node_modules
21COPY /app/dist ./dist
22USER appuser
23EXPOSE 3000
24CMD ["node", "dist/main.js"]Multi-Stage Builds
Multi-stage builds eliminate build-time dependencies from production images, dramatically reducing image size and attack surface.
Best practice: Always use a minimal base image (alpine, distroless) for your final production stage. A typical Node.js app shrinks from ~1 GB to under 100 MB.
Docker Compose
Define and run multi-container applications with a single compose.yml file.
1# compose.yml
2services:
3 api:
4 build: ./api
5 ports:
6 - "3000:3000"
7 environment:
8 DATABASE_URL: postgres://user:pass@db:5432/mydb
9 depends_on:
10 db:
11 condition: service_healthy
12
13 db:
14 image: postgres:16-alpine
15 volumes:
16 - pg-data:/var/lib/postgresql/data
17 environment:
18 POSTGRES_USER: user
19 POSTGRES_PASSWORD: pass
20 POSTGRES_DB: mydb
21 healthcheck:
22 test: ["CMD-SHELL", "pg_isready -U user"]
23 interval: 10s
24 timeout: 5s
25 retries: 5
26
27 redis:
28 image: valkey/valkey:8-alpine
29 volumes:
30 - redis-data:/data
31
32volumes:
33 pg-data:
34 redis-data:Container Security
- Run containers as a non-root user (
USER appuser) - Use read-only root filesystems (
--read-only) - Drop all Linux capabilities and add only what is needed
- Scan images with
docker scout cves - Pin base image digests, not just tags
- Never bake secrets into images — use Docker secrets or environment variables at runtime
Monitoring & Observability
Export container metrics to Prometheus and visualize in Grafana.
1# Add cadvisor to your compose stack
2cadvisor:
3 image: gcr.io/cadvisor/cadvisor:latest
4 volumes:
5 - /:/rootfs:ro
6 - /var/run:/var/run:ro
7 - /sys:/sys:ro
8 - /var/lib/docker/:/var/lib/docker:ro
9 ports:
10 - "8080:8080"
11 restart: unless-stoppedCI/CD Integration
Build, test, scan, and push Docker images automatically with GitHub Actions.
1# .github/workflows/docker.yml
2- name: Build and push
3 uses: docker/build-push-action@v5
4 with:
5 context: .
6 platforms: linux/amd64,linux/arm64
7 push: true
8 tags: ghcr.io/org/app:latest
9 cache-from: type=gha
10 cache-to: type=gha,mode=maxProduction Deployment
- Use restart policies:
restart: unless-stopped - Set CPU and memory limits on every service
- Use Docker Swarm or Kubernetes for multi-node deployments
- Store persistent data in named volumes, not bind mounts
- Enable Docker daemon TLS for remote access