Day 35: Docker Installation - Setting Up Container Environment 🐳

Welcome back! 👋 Day 35 of the 100 Days Cloud DevOps Challenge, and today we're installing Docker - the containerization platform! This is where our journey into containers begins. Let's dockerize! 🎯
🎯 The Mission - Install Docker on App Server 3
It's Thursday morning, and the team is ready to start containerization:
📋 TASK TICKET #DEV-7125 - Docker Installation & Setup
Priority: HIGH
Type: Container Platform Installation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PROJECT: Application Containerization Initiative
Team: Nautilus DevOps Team
Issue: Need Docker environment for testing
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
BACKGROUND:
└─ Meeting: DevOps + Development teams
└─ Decision: Containerize applications
└─ Phase 1: Install Docker on test server
└─ Phase 2: Begin container testing
REQUIREMENTS:
1. Target Server:
└─ Server: App Server 3
└─ User: banner (password: BigGr33n)
└─ OS: CentOS/RHEL-based
└─ Action: Install Docker
2. Install Docker CE:
└─ Package: docker-ce (Community Edition)
└─ Method: Official repository
└─ Version: Latest stable
└─ Include dependencies
3. Install Docker Compose:
└─ Package: docker-compose-plugin
└─ Method: Official repository
└─ Version: Latest stable
└─ For multi-container apps
4. Start Docker Service:
└─ Service: docker.service
└─ Action: Start immediately
└─ Enable: Start on boot
└─ Verify: Service running
5. Verification:
└─ Check Docker version
└─ Check Compose version
└─ Verify service status
└─ Test Docker functionality
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STATUS: CRITICAL - Blocking containerization project
DEADLINE: Today
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
This is the foundation of containerization! Docker enables modern application deployment! 🚀
🤔 Why Docker Matters - The Container Revolution
The Problem Before Containers
Traditional Deployment Challenges:
Scenario: Deploying applications
Server 1: Python 2.7, Node 10
└─ App A needs Python 2.7 ✓
└─ App B needs Python 3.8 ✗ CONFLICT!
Server 2: Ubuntu 18.04
└─ App C needs Ubuntu 20.04 libs ✗
└─ Dependency hell!
Problems:
❌ Dependency conflicts
❌ "Works on my machine"
❌ Environment inconsistencies
❌ Slow deployments
❌ Resource waste (one app per VM)
❌ Difficult scaling
With Docker (Containerization):
Same Server:
├─ Container 1: Python 2.7 + App A ✓
├─ Container 2: Python 3.8 + App B ✓
├─ Container 3: Node 14 + App C ✓
└─ Container 4: Java 11 + App D ✓
Benefits:
✅ Isolated environments
✅ Consistent everywhere
✅ Package app + dependencies
✅ Fast deployment (seconds!)
✅ Efficient resources
✅ Easy scaling
Real stat: Docker reduces deployment time by 90% and infrastructure costs by 60%! 📊
Understanding Docker
What is Docker?
Docker is a platform for developing, shipping, and running applications in containers:
Docker Architecture:
┌─────────────────────────────────┐
│ Your Application Code │
├─────────────────────────────────┤
│ Application Dependencies │
│ (Python, Node, Libraries, etc.) │
├─────────────────────────────────┤
│ Docker Container │
│ (Isolated Environment) │
├─────────────────────────────────┤
│ Docker Engine │
│ (Container Runtime) │
├─────────────────────────────────┤
│ Host Operating System │
│ (Linux/Windows) │
└─────────────────────────────────┘
Key concepts:
Container: Lightweight, isolated environment
Image: Template for creating containers
Docker Engine: Runs and manages containers
Docker Compose: Tool for multi-container apps
Registry: Storage for Docker images (Docker Hub)
Container vs Virtual Machine
Virtual Machines:
┌──────────────────┐ ┌──────────────────┐
│ App A │ │ App B │
│ Dependencies │ │ Dependencies │
├──────────────────┤ ├──────────────────┤
│ Guest OS (GB!) │ │ Guest OS (GB!) │
├──────────────────┴─┴──────────────────┤
│ Hypervisor │
├────────────────────────────────────────┤
│ Host OS │
├────────────────────────────────────────┤
│ Hardware │
└────────────────────────────────────────┘
Heavy: GB per VM
Slow: Minutes to start
Isolated: Full OS isolation
Containers:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ App A │ │ App B │ │ App C │
│ Deps │ │ Deps │ │ Deps │
├──────────┴─┴──────────┴─┴──────────┤
│ Docker Engine │
├─────────────────────────────────────┤
│ Host OS (Shared!) │
├─────────────────────────────────────┤
│ Hardware │
└─────────────────────────────────────┘
Light: MB per container
Fast: Seconds to start
Efficient: Share host OS
Real-World Use Cases
Use Case 1: Development Consistency
Problem: "Works on my laptop, not on server"
Solution: Package in Docker
Result: Same container everywhere!
Use Case 2: Microservices
Application:
├─ Frontend (React) → Container 1
├─ Backend API (Node) → Container 2
├─ Database (PostgreSQL) → Container 3
└─ Cache (Redis) → Container 4
Each service isolated, independently scalable!
Use Case 3: CI/CD Pipelines
Build → Test → Deploy
Each step in container:
- Consistent environment
- Fast execution
- Easy cleanup
🏗️ Understanding the Setup
Target Environment:
Stratos Datacenter
App Server 3:
├─ Hostname: stapp03
├─ User: banner (password: BigGr33n)
├─ OS: CentOS/RHEL-based
├─ Current State: No Docker installed
└─ Required: Docker CE + Docker Compose
Installation Plan:
1. Add Docker repository
2. Install docker-ce package
3. Install docker-compose-plugin
4. Start docker.service
5. Enable on boot
6. Verify installation
Before Installation:
App Server 3:
├─ No Docker
├─ No containers
├─ Standard Linux packages
└─ Ready for containerization
Commands don't exist:
$ docker --version
bash: docker: command not found
$ docker compose version
bash: docker: command not found
After Installation:
App Server 3:
├─ Docker CE installed ✅
├─ Docker Compose installed ✅
├─ Docker service running ✅
├─ Enabled on boot ✅
└─ Ready for containers!
Commands work:
$ docker --version
Docker version 24.0.7, build...
$ docker compose version
Docker Compose version v2.23.0
$ systemctl status docker
● docker.service - Docker Application Container Engine
Active: active (running)
🛠️ Complete Step-by-Step Implementation
Phase 1: Access App Server 3
Step 1.1: SSH to App Server 3
# Connect to App Server 3
ssh banner@stapp03
# Password: BigGr33n
Logged in as banner! ✅
Step 1.2: Switch to Root
# Switch to root for installation
sudo su -
Root access obtained! ✅
Step 1.3: Check Current State
# Verify Docker not installed
docker --version
Expected output:
bash: docker: command not found
Confirms Docker needs installation! ✅
Step 1.4: Check OS Version
# Check OS information
cat /etc/os-release
Expected output:
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
OS identified! ✅
Phase 2: Prepare for Docker Installation
Step 2.1: Update System Packages
# Update package database
yum update -y
System updated! ✅
Step 2.2: Install Required Dependencies
# Install prerequisites
yum install -y yum-utils device-mapper-persistent-data lvm2
Expected output:
Installed:
yum-utils.noarch 0:1.1.31-...
device-mapper-persistent-data.x86_64 0:0.7.3-...
lvm2.x86_64 7:2.02.187-...
Complete!
Dependencies installed! ✅
What these packages do:
yum-utils: Provides yum-config-managerdevice-mapper-persistent-data: Storage driverlvm2: Logical volume management
Step 2.3: Remove Old Docker Versions (If Any)
# Remove old Docker versions
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
Old versions removed (if existed)! ✅
Phase 3: Add Docker Repository
Step 3.1: Add Docker CE Repository
# Add Docker's official repository
yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
Expected output:
Adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
Repository added! ✅
Step 3.2: Verify Repository Added
# List enabled repositories
yum repolist | grep docker
Expected output:
docker-ce-stable/7/x86_64 Docker CE Stable - x86_64
Docker repository enabled! ✅
Phase 4: Install Docker CE
Step 4.1: Install Docker CE
# Install Docker CE (Community Edition)
yum install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Expected output:
Installed:
docker-ce.x86_64 3:24.0.7-1.el7
docker-ce-cli.x86_64 1:24.0.7-1.el7
containerd.io.x86_64 1.6.26-3.1.el7
docker-compose-plugin.x86_64 2.23.0-1.el7
Complete!
Docker installed! 🎉
Packages installed:
docker-ce: Docker Enginedocker-ce-cli: Docker command-line interfacecontainerd.io: Container runtimedocker-compose-plugin: Docker Compose V2
Step 4.2: Verify Installation
# Check Docker version
docker --version
Expected output:
Docker version 24.0.7, build afdd53b
Docker CE installed successfully! ✅
Step 4.3: Check Docker Compose
# Check Compose version
docker compose version
Expected output:
Docker Compose version v2.23.0
Docker Compose installed! ✅
Phase 5: Start and Enable Docker Service
Step 5.1: Start Docker Service
# Start Docker daemon
systemctl start docker
No output = success! ✅
Step 5.2: Enable Docker on Boot
# Enable Docker to start on system boot
systemctl enable docker
Expected output:
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
Docker enabled at boot! ✅
Step 5.3: Check Service Status
# Verify Docker service running
systemctl status docker
Expected output:
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2025-12-09 10:00:00 UTC; 30s ago
Docs: https://docs.docker.com
Main PID: 12345 (dockerd)
Tasks: 8
Memory: 45.2M
CGroup: /system.slice/docker.service
└─12345 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
Dec 09 10:00:00 stapp03 systemd[1]: Starting Docker Application Container Engine...
Dec 09 10:00:00 stapp03 dockerd[12345]: time="2025-12-09T10:00:00Z" level=info msg="Starting up"
Dec 09 10:00:00 stapp03 systemd[1]: Started Docker Application Container Engine.
Service active and running! ✅
Phase 6: Verify Docker Installation
Step 6.1: Test Docker Functionality
# Run hello-world container
docker run hello-world
Expected output:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:4bd78111b6914a99dbc560e6a20eab57ff6655aea4a80c50b0c5491968cbc2e6
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/get-started/
Docker working perfectly! 🎊
Step 6.2: Check Docker Images
# List downloaded images
docker images
Expected output:
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 7 months ago 13.3kB
Image downloaded successfully! ✅
Step 6.3: Check Docker Info
# Display system-wide information
docker info
Expected output (abbreviated):
Client:
Version: 24.0.7
Context: default
Server:
Containers: 1
Running: 0
Paused: 0
Stopped: 1
Images: 1
Server Version: 24.0.7
Storage Driver: overlay2
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Kernel Version: 3.10.0-1160.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 3.7GiB
Docker Root Dir: /var/lib/docker
Docker system information displayed! ✅
Step 6.4: Verify Docker Compose
# Test Docker Compose
docker compose version
Expected output:
Docker Compose version v2.23.0
Compose working! ✅
Step 6.5: Check Running Containers
# List running containers
docker ps
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
No containers running (expected)! ✅
Step 6.6: Check All Containers
# List all containers (including stopped)
docker ps -a
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123def456 hello-world "/hello" 2 minutes ago Exited (0) 2 minutes ago mystifying_galileo
Hello-world container executed and exited! ✅
Phase 7: Final Verification
Step 7.1: Check Docker Service Enabled
# Verify enabled on boot
systemctl is-enabled docker
Expected output:
enabled
Docker will start on boot! ✅
Step 7.2: Verify Docker Socket
# Check Docker socket
ls -la /var/run/docker.sock
Expected output:
srw-rw----. 1 root docker 0 Dec 9 10:00 /var/run/docker.sock
Docker socket exists! ✅
Step 7.3: Check Docker Group
# Verify docker group exists
getent group docker
Expected output:
docker:x:992:
Docker group created! ✅
Step 7.4: Add User to Docker Group (Optional)
# Add banner user to docker group
usermod -aG docker banner
User added to docker group! ✅
Note: User needs to log out and back in for group change to take effect.
Step 7.5: Comprehensive Status Check
# Complete verification
echo "=== Docker Version ==="
docker --version
echo "=== Docker Compose Version ==="
docker compose version
echo "=== Docker Service Status ==="
systemctl status docker --no-pager
echo "=== Docker Images ==="
docker images
echo "=== Docker Info ==="
docker info | head -20
All checks pass! ✅
TASK COMPLETE! 🎉🎊🎈🎊🎉
🔍 Understanding What We Accomplished
Installation Components
What We Installed:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Docker CE (Community Edition)
└─ Docker Engine (dockerd)
└─ Container runtime
└─ Image management
└─ Network management
2. Docker CLI
└─ docker command
└─ Client interface
└─ Talks to Docker Engine
3. containerd
└─ Container runtime
└─ Manages container lifecycle
└─ Used by Docker Engine
4. Docker Compose Plugin
└─ docker compose command
└─ Multi-container orchestration
└─ YAML configuration files
5. Docker Service
└─ systemd service
└─ Starts on boot
└─ Manages Docker daemon
Docker Architecture
Components Installed:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌─────────────────────────────────┐
│ Docker CLI (docker) │
│ (User runs: docker run nginx) │
└────────────┬────────────────────┘
│ REST API
↓
┌─────────────────────────────────┐
│ Docker Engine (dockerd) │
│ - Manages images │
│ - Creates containers │
│ - Handles networking │
└────────────┬────────────────────┘
│
↓
┌─────────────────────────────────┐
│ containerd │
│ - Container runtime │
│ - Starts/stops containers │
└────────────┬────────────────────┘
│
↓
┌─────────────────────────────────┐
│ runc │
│ - Low-level container runtime │
│ - Interacts with Linux kernel │
└─────────────────────────────────┘
Directory Structure Created
Docker Installation Created:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
/var/lib/docker/
├─ containers/ # Container data
├─ images/ # Image layers
├─ volumes/ # Persistent volumes
├─ networks/ # Network configs
└─ overlay2/ # Storage driver data
/etc/docker/
└─ daemon.json # Docker config (if created)
/var/run/
└─ docker.sock # Docker API socket
/usr/bin/
├─ docker # Docker CLI
└─ dockerd # Docker daemon
/usr/lib/systemd/system/
└─ docker.service # Systemd service file
💡 Key Takeaways
✨ Docker CE is Community Edition (free and open-source)
✨ Docker Compose manages multi-container applications
✨ Repository setup required before installation
✨ systemd manages Docker as a service
✨ docker.sock is the API endpoint
✨ Hello-world image tests installation
✨ Enable service ensures startup on boot
✨ Docker group allows non-root Docker access
✨ containerd is the container runtime
✨ Images vs Containers - template vs running instance
✨ Installation verified through multiple tests
🎓 Interview Questions
Q1: Explain the difference between Docker CE and Docker EE. When would you use each?
Answer: Docker comes in two main editions with different features and support: Docker CE (Community Edition): What it is: Free, open-source Docker platform, community-supported, frequent updates (monthly stable releases). Features: Core Docker Engine, basic container management, Docker Compose, suitable for development/testing, open-source components. Licensing: Apache 2.0 license, completely free, no support contract. Use when: Development environments, personal projects, small teams, testing/learning, open-source projects, cost is primary concern. Docker EE (Enterprise Edition): What it is: Paid enterprise platform, commercial support included, certified and tested, longer support cycles. Features: Everything in CE plus: certified images, image scanning (security), advanced RBAC, enterprise registry, enterprise support, certified plugins, compliance features, longer support lifecycle. Licensing: Subscription-based, per-node pricing, includes support SLA. Use when: Production environments, enterprise requirements, compliance needs (HIPAA, PCI-DSS), security scanning required, need vendor support, mission-critical applications, large teams/organizations. Detailed comparison: | Feature | Docker CE | Docker EE | |---------|-----------|----------| | Cost | Free | Paid subscription | | Support | Community | Commercial 24/7 | | Updates | Monthly | Quarterly (stable) | | Certification | No | Yes (images, infrastructure) | | Security Scanning | No | Yes (built-in) | | RBAC | Basic | Advanced | | Best for | Dev/Test | Production | Our task: Installed Docker CE because: perfect for testing phase, no cost for evaluation, community support sufficient, full features for containerization, can upgrade to EE if needed. Migration path: Start with CE for development, evaluate in staging, upgrade to EE for production, seamless transition (compatible). Real-world decision: Startups/SMBs: Often use CE even in production, larger enterprises: EE for compliance and support, hybrid: CE for dev, EE for production!
Q2: Walk through what happens when you run 'docker run hello-world'. Explain each step.
Answer: The docker run command triggers a complex series of operations: Command breakdown: bash docker run hello-world # │ │ │ # │ │ └─ Image name # │ └─ Run command # └─ Docker CLI Step-by-step process: Step 1: CLI parses command - Docker CLI receives: docker run hello-world, parses arguments: image=hello-world, sends REST API request to Docker daemon. Step 2: Check local images - Docker daemon checks: /var/lib/docker/images/, searches for: hello-world:latest (default tag), if found: skip to Step 4, if NOT found: proceed to Step 3. Step 3: Pull image from registry - Output: "Unable to find image 'hello-world:latest' locally", connects to: Docker Hub (default registry), authenticates: anonymous pull (public image), downloads: image manifest lists layers, pulls layers: download each layer, stores in: /var/lib/docker/overlay2/, output: "Pull complete". Step 4: Create container - Docker daemon: reads image configuration, creates container configuration, generates container ID (random), allocates container resources, prepares filesystem: merge image layers (union filesystem), creates container directory: /var/lib/docker/containers/<ID>/. Step 5: Start container - Daemon calls containerd: "start container <ID>", containerd calls runc: creates Linux namespaces (PID, network, mount), sets up cgroups (resource limits), creates isolated environment, executes container command: /hello (hello-world binary), container starts and runs. Step 6: Execute application - hello-world binary runs, outputs message to stdout, daemon captures output, streams to Docker CLI, CLI displays on terminal. Step 7: Container exits - hello-world completes execution, returns exit code: 0 (success), container stops automatically, status changes: running → exited, container persists: can see with docker ps -a. Behind the scenes - detailed: bash # Internal operations 1. Docker CLI: Parses: docker run hello-world Sends: POST /containers/create API: Docker daemon @ /var/run/docker.sock 2. Docker Daemon: Checks: /var/lib/docker/image/overlay2/repositories.json Result: hello-world not found Action: Pull from registry 3. Registry Communication: URL: https://registry-1.docker.io API: GET /v2/library/hello-world/manifests/latest Response: Image manifest (layers, config) 4. Layer Download: Manifest: { "layers": [ {"digest": "sha256:c1ec..."} ] } Download: Each layer (compressed) Store: /var/lib/docker/overlay2/<layer-id> 5. Container Creation: Generate ID: abc123def456... Config from image: { "Cmd": ["/hello"], "WorkingDir": "/", "Env": [...] } Create: /var/lib/docker/containers/abc123def456/ 6. Container Start: Create namespaces: PID: isolated process tree NET: isolated network stack MNT: isolated filesystem IPC: isolated IPC Set cgroups: CPU, memory limits Mount filesystem: Union of image layers Execute: /hello binary 7. Output Handling: Binary writes: stdout stream Docker captures: container output Streams to: Docker CLI CLI displays: "Hello from Docker!" 8. Container Stop: Process exits: exit code 0 Daemon detects: container stopped Updates state: running → exited Cleanup: (filesystem persists) Verify each step: bash # Check images docker images # REPOSITORY TAG IMAGE ID # hello-world latest d2c94e258dcb # Check containers docker ps -a # CONTAINER ID STATUS # abc123def456 Exited (0) 2 minutes ago # Check container details docker inspect abc123def456 | head -20 Why hello-world is perfect test: Small image (13.3 KB), quick download, simple operation, no dependencies, predictable output, tests entire Docker stack. What we learned: Image pulling works, container creation works, container execution works, output streaming works, Docker fully functional!
Q3: Explain Docker storage drivers. What is overlay2 and why is it the default?
Answer: Storage drivers manage how Docker stores and retrieves container/image data: What are storage drivers?: Docker images: composed of layers (read-only), containers: writable layer on top (copy-on-write), storage driver: manages these layers, handles union filesystem. Common storage drivers: 1. overlay2 (modern, default): Technology: OverlayFS (Linux kernel feature), layers: up to 128 layers supported, performance: excellent (native), space efficiency: high (shared layers), inode usage: moderate, kernel requirement: Linux 4.0+. 2. overlay (older): Predecessor of overlay2, deprecated: use overlay2 instead, similar but: less efficient, max 2 layers only. 3. devicemapper: Technology: Device Mapper (LVM), layers: managed as block devices, performance: good but slower than overlay2, space: thin provisioning, use case: older kernels. 4. btrfs: Technology: Btrfs filesystem, layers: Btrfs subvolumes, performance: good, features: snapshots, built-in, requirement: Btrfs filesystem. 5. zfs: Technology: ZFS filesystem, layers: ZFS datasets, performance: excellent, features: snapshots, compression, requirement: ZFS on Linux. Why overlay2 is default: Performance advantages: Native kernel support (no overhead), efficient read/write operations, minimal CPU impact, fast container start times. Space efficiency: Shares layers between containers, deduplication at layer level, thin provisioning, efficient disk usage. Simplicity: Easy to understand, minimal configuration, works out-of-box, stable and mature. Kernel support: Standard in modern Linux (4.0+), widely tested, good community support.
Q4: What is the difference between 'docker' and 'docker compose'? When would you use Compose?
Answer: Docker and Docker Compose serve different purposes in container management: docker (single containers): Purpose: Run individual containers, one container at a time, manual linking required. Commands: bash docker run nginx docker run postgres docker run redis # Each separate! Use case: Simple applications, single-service containers, testing individual images, learning Docker. Limitations: Manual container linking, no dependency management, complex multi-container setups, difficult to reproduce. docker compose (multi-container apps): Purpose: Define multi-container applications, declarative configuration (YAML), orchestrate multiple services. Commands: bash docker compose up # Start all docker compose down # Stop all docker compose logs # View logs # One command! Use case: Multi-tier applications, development environments, microservices, complex dependencies. Detailed comparison: | Aspect | docker | docker compose | |--------|--------|----------------| | Containers | One at a time | Multiple together | | Configuration | Command-line | YAML file | | Networking | Manual | Auto-configured | | Dependencies | Manual | Defined in YAML | | Reproducible | Difficult | Easy (one file) | | Best for | Single containers | Applications | Docker Compose example: yaml # docker-compose.yml version: '3.8' services: web: image: nginx ports: - "80:80" depends_on: - api api: image: node:16 environment: DB_HOST: database depends_on: - database database: image: postgres:14 environment: POSTGRES_PASSWORD: secret volumes: - db-data:/var/lib/postgresql/data volumes: db-data: Single command: bash docker compose up # Starts: postgres, then node, then nginx # Creates: network for communication # Sets up: all configurations Without Compose (manual): bash # Create network docker network create app-network # Start database docker run -d \ --name database \ --network app-network \ -e POSTGRES_PASSWORD=secret \ -v db-data:/var/lib/postgresql/data \ postgres:14 # Start API docker run -d \ --name api \ --network app-network \ -e DB_HOST=database \ node:16 # Start web docker run -d \ --name web \ --network app-network \ -p 80:80 \ nginx # Complex! Error-prone! Compose features: Dependency management: yaml depends_on: - database # API waits for database Environment configuration: yaml environment: NODE_ENV: production API_KEY: ${API_KEY} # From .env file Volume management: yaml volumes: - ./app:/usr/src/app # Bind mount - node_modules:/usr/src/app/node_modules Network isolation: yaml networks: frontend: backend: Scaling services: bash docker compose up --scale api=3 # Run 3 API instances Real-world workflow: bash # Development docker compose up -d # Start all docker compose logs -f # View logs docker compose exec api bash # Access container docker compose down # Stop all # Production docker compose -f docker-compose.prod.yml up -d Our task: Installed Docker Compose plugin, ready for multi-container apps, use Docker for: single containers, testing images, use Compose for: full applications, development stacks, microservices! Common Compose use cases: Development: Full stack locally (DB + backend + frontend), testing: Isolated test environments, CI/CD: Consistent pipelines, learning: Easy setup for tutorials!
Q5: Explain Docker networking modes. What is the default bridge network?
Answer: Docker provides multiple networking modes for different use cases: Network drivers available: 1. bridge (default): How it works: Virtual bridge (docker0) on host, containers get private IPs, NAT to access external network, containers can communicate via bridge. Default behavior: Automatic for containers, default network: docker0, IP range: 172.17.0.0/16 (typically). 2. host: How it works: Container uses host network directly, no network isolation, shares host's IP and ports. Use case: High performance needed, network tools, monitoring containers. 3. none: How it works: No networking configured, completely isolated, only loopback interface. Use case: Maximum isolation, custom network setup, security requirements. 4. overlay: How it works: Multi-host networking, spans multiple Docker hosts, used in Swarm mode. Use case: Distributed applications, Docker Swarm, Kubernetes. 5. macvlan: How it works: Assigns MAC address to container, appears as physical device on network. Use case: Legacy apps, direct network access. Default bridge network explained: bash Created automatically: Name: bridge Network: 172.17.0.0/16 (default) Gateway: 172.17.0.1 Docker host interface: docker0 How bridge networking works: bash Host Machine: ├─ Physical NIC (eth0): 192.168.1.100 └─ Docker Bridge (docker0): 172.17.0.1 ├─ Container 1: 172.17.0.2 ├─ Container 2: 172.17.0.3 └─ Container 3: 172.17.0.4 Internet ← NAT ← docker0 ← containers Containers communicate: bash # Container 1 can ping Container 2 docker exec container1 ping 172.17.0.3 # Works! Same bridge network Port mapping: bash # Container port → Host port docker run -p 8080:80 nginx # Host:8080 → Container:80 # External access enabled Network inspection: bash # List networks docker network ls # Output: NETWORK ID NAME DRIVER SCOPE abc123def456 bridge bridge local 789def456abc host host local 456abc123def none null local # Inspect bridge docker network inspect bridge # Shows: containers, IP addresses, subnet Custom bridge networks: bash # Create custom network docker network create my-network # Run container on custom network docker run --network my-network nginx # Benefits of custom: - DNS resolution (by container name) - Better isolation - Custom subnet Container connectivity: Default bridge: bash # Start containers docker run -d --name web nginx docker run -d --name db postgres # Communicate by IP only docker exec web ping 172.17.0.3 # Must know IP Custom bridge: bash # Create network docker network create app-net # Start containers docker run -d --name web --network app-net nginx docker run -d --name db --network app-net postgres # Communicate by name docker exec web ping db # DNS works! Network isolation: bash # Create separate networks docker network create frontend docker network create backend # Frontend containers docker run -d --name web --network frontend nginx # Backend containers docker run -d --name db --network backend postgres # web cannot access db (different networks) Host networking example: bash # Use host network docker run --network host nginx # Container uses host's IP directly # No port mapping needed # No isolation Security considerations: Default bridge: Less secure (all containers connected), custom bridges: Better isolation (explicit connections), host mode: No network isolation!, firewall rules: Apply to host, affect containers. Troubleshooting networking: bash # Check container IP docker inspect container-name | grep IPAddress # Check network connectivity docker exec container-name ping google.com # Test container-to-container docker exec web ping db # View network config docker network inspect bridge Our installation: Default bridge network created, ready for container networking, can create custom networks as needed, supports all network modes!
Q6: How do you secure a Docker installation? What are the security best practices?
Answer: Docker security involves multiple layers requiring careful configuration: 1. Docker daemon security: Run as non-root (user namespaces): bash # Enable user namespaces in daemon.json { "userns-remap": "default" } # Restart Docker sudo systemctl restart docker # Containers run as non-root in host Secure Docker socket: bash # Default: /var/run/docker.sock # Permissions: srw-rw---- root:docker # Risk: Socket access = root access! # Protect: Only trusted users in docker group # Remove user from docker group sudo gpasswd -d username docker TLS for remote access: bash # Generate certificates # Configure daemon.json { "tls": true, "tlscacert": "/path/to/ca.pem", "tlscert": "/path/to/server-cert.pem", "tlskey": "/path/to/server-key.pem", "tlsverify": true } # Clients must present valid certificate 2. Image security: Use official images: bash # Good docker pull nginx # Official # Bad docker pull random-user/nginx # Unknown source Scan images for vulnerabilities: bash # Using Trivy trivy image nginx # Using Clair clair-scanner nginx # Using Snyk snyk container test nginx Pin image versions: bash # Bad (floating tag) docker pull nginx:latest # Can change! # Good (specific version) docker pull nginx:1.24.0 # Immutable # Better (digest) docker pull nginx@sha256:abc123... Minimal base images: bash # Instead of ubuntu FROM alpine:3.18 # Or distroless FROM gcr.io/distroless/base # Smaller = fewer vulnerabilities 3. Container runtime security: Run as non-root user: dockerfile # In Dockerfile RUN adduser -D appuser USER appuser # Container process runs as appuser Read-only filesystem: bash # Make filesystem read-only docker run --read-only nginx # Add writable volume if needed docker run --read-only -v /tmp nginx Drop capabilities: bash # Remove unnecessary capabilities docker run --cap-drop ALL nginx # Add only needed ones docker run --cap-drop ALL --cap-add NET_BIND_SERVICE nginx Resource limits: bash # Limit CPU/memory docker run --cpus=".5" --memory="512m" nginx # Prevents DoS via resource exhaustion Security options: bash # Enable AppArmor/SELinux docker run --security-opt apparmor=docker-default nginx # No new privileges docker run --security-opt no-new-privileges nginx 4. Network security: Custom networks: bash # Isolate containers docker network create frontend docker network create backend # Only connect what's needed Firewall rules: bash # Restrict Docker iptables rules # Use UFW or firewalld sudo ufw allow from 192.168.1.0/24 to any port 2376 Disable inter-container communication: bash # In daemon.json { "icc": false } # Containers can't talk unless explicitly linked 5. Secrets management: Don't hardcode secrets: bash # Bad docker run -e DB_PASSWORD=secret123 app # Good (use secrets) echo "secret123" | docker secret create db_password - docker service create --secret db_password app Use secret management tools: bash # HashiCorp Vault docker run -e VAULT_TOKEN=$(vault token) app # AWS Secrets Manager docker run -e AWS_SECRET=$(aws secretsmanager) app 6. Logging and monitoring: Enable logging: bash # Configure logging driver { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } Monitor Docker events: bash # Watch for suspicious activity docker events # Log to SIEM for analysis Audit Docker daemon: bash # Enable audit logging auditctl -w /usr/bin/docker -k docker auditctl -w /var/lib/docker -k docker 7. Keep Docker updated: bash # Regular updates sudo yum update docker-ce # Security patches applied 8. Use Docker Bench Security: bash # Automated security audit docker run -it --net host --pid host --userns host --cap-add audit_control \ -v /var/lib:/var/lib -v /var/run/docker.sock:/var/run/docker.sock \ -v /etc:/etc --label docker_bench_security \ docker/docker-bench-security # Checks 100+ security items Security checklist: ☐ Enable user namespaces ☐ Protect Docker socket ☐ Use official/trusted images ☐ Scan images regularly ☐ Pin image versions ☐ Run containers as non-root ☐ Use read-only filesystems ☐ Drop unnecessary capabilities ☐ Set resource limits ☐ Use custom networks ☐ Never hardcode secrets ☐ Enable logging ☐ Keep Docker updated ☐ Regular security audits Our installation: Basic installation complete, security hardening: next phase, follow best practices: as we deploy apps, regular updates: essential for security!
🌟 Advanced Docker Topics
Docker System Management
Disk space management:
bash
# Check disk usage
docker system df
# Output:
# TYPE TOTAL ACTIVE SIZE
# Images 5 2 1.2GB
# Containers 10 2 45MB
# Local Volumes 3 2 200MB
# Clean up
docker system prune -a # Remove all unused
docker image prune # Remove unused images
docker container prune # Remove stopped containers
docker volume prune # Remove unused volumes
Docker Resource Limits
Prevent resource exhaustion:
bash
# CPU limits
docker run --cpus=".5" nginx # 50% of one CPU
docker run --cpu-shares=512 nginx # Relative weight
# Memory limits
docker run --memory="512m" nginx # Max 512MB
docker run --memory-reservation="256m" # Soft limit
# Disk I/O
docker run --device-write-bps /dev/sda:1mb nginx
# PIDs limit
docker run --pids-limit=100 nginx
Docker Registry
Private registry setup:
bash
# Run registry container
docker run -d -p 5000:5000 --name registry registry:2
# Tag image for private registry
docker tag nginx localhost:5000/nginx
# Push to private registry
docker push localhost:5000/nginx
# Pull from private registry
docker pull localhost:5000/nginx
Docker Multi-Stage Builds
Optimize image size:
dockerfile
# Build stage
FROM node:16 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Production stage
FROM node:16-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/server.js"]
# Result: Much smaller final image!
🔧 Troubleshooting Docker
Issue 1: Docker Service Won't Start
bash
# Check service status
systemctl status docker
# Check logs
journalctl -u docker -n 50
# Common causes:
# - Conflicting ports
# - Corrupted data directory
# - Disk space full
# Solution:
# Check disk space
df -h /var/lib/docker
# Reset Docker (if needed)
sudo systemctl stop docker
sudo rm -rf /var/lib/docker
sudo systemctl start docker
Issue 2: Permission Denied
bash
# Error: permission denied while trying to connect
# Solution 1: Add user to docker group
sudo usermod -aG docker $USER
newgrp docker # Or logout/login
# Solution 2: Use sudo
sudo docker ps
# Verify
docker run hello-world
Issue 3: Cannot Pull Images
bash
# Error: Cannot connect to Docker daemon
# Check Docker running
systemctl status docker
# Check Docker socket
ls -la /var/run/docker.sock
# Restart Docker
sudo systemctl restart docker
Issue 4: Container Immediately Exits
bash
# Check container logs
docker logs container-name
# Check exit code
docker ps -a
# Common causes:
# - Missing command
# - Application crashes
# - Configuration errors
# Debug interactively
docker run -it image-name /bin/sh
🎉 Final Thoughts
You've successfully installed Docker - the foundation of modern containerization! This is the beginning of your container journey:
What you accomplished:
✅ Installed Docker CE on App Server 3
✅ Installed Docker Compose plugin
✅ Started Docker service
✅ Enabled Docker at boot
✅ Verified installation with hello-world
✅ Confirmed Docker functionality
✅ Ready for containerization!
Real-world applications:
Application deployment: Package apps with dependencies
Development environments: Consistent dev/prod parity
Microservices: Isolated service deployment
CI/CD pipelines: Containerized build/test
Resource efficiency: Multiple apps, one server
Scalability: Easy horizontal scaling
This is modern DevOps! Docker revolutionizes how we build, ship, and run applications! 💪
Key principles to remember:
Docker CE - free Community Edition for all
Containers - lightweight, isolated environments
Images - templates for containers
Docker Compose - multi-container orchestration
Networking - bridge mode is default
Storage - overlay2 driver for layers
Security - many layers to consider
Testing - hello-world verifies installation
🚀 What's Next?
Day 35 complete! 🎉 You've installed Docker and entered the container world!
Skills Mastered Today:
✅ Docker CE installation
✅ Docker Compose setup
✅ Service management
✅ Installation verification
✅ Docker fundamentals
✅ Container concepts
35 days complete! 🎊 More than one-third through! Now with containers! 💪
Next steps:
Create custom Docker images
Run real applications in containers
Use Docker Compose for multi-container apps
Learn Docker networking
Explore container orchestration
Deploy production containers
Day: 35/100
Challenge: KodeKloud Cloud DevOps
Date: December 10, 2025
Topic: Docker Installation - Setting Up Container Environment
What was your first Docker experience? Share your containerization journey and lessons learned! 🐳




