Skip to main content

Command Palette

Search for a command to run...

Day 35: Docker Installation - Setting Up Container Environment 🐳

Published
26 min read
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-manager

  • device-mapper-persistent-data: Storage driver

  • lvm2: 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 Engine

  • docker-ce-cli: Docker command-line interface

  • containerd.io: Container runtime

  • docker-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:

  1. Docker CE - free Community Edition for all

  2. Containers - lightweight, isolated environments

  3. Images - templates for containers

  4. Docker Compose - multi-container orchestration

  5. Networking - bridge mode is default

  6. Storage - overlay2 driver for layers

  7. Security - many layers to consider

  8. 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! 🐳

More from this blog

🚀 DevOps Challenge- KodeKloud Solutions

73 posts