Saturday, February 1, 2025

Introduction to Docker

Docker Introduction: Complete Guide to Containerization | RJS Expert

Docker Introduction: Complete Guide to Containerization

✍️ Written by: RJS Expert
A comprehensive introduction to Docker and containerization technology, covering fundamental concepts, key components, comparison with virtual machines, and practical setup guidance.

What is Docker?

🐳 Docker Definition:

Docker is a container technology: A tool for creating and managing containers.

Docker is an open-source containerization platform by which you can pack your application and all its dependencies into a standardized unit called a container.

Understanding Containers in Software Development

📦 What's a Container?

A container is a standardized unit of software - a package of code and dependencies to run that code.

Key Characteristics:
  • Lightweight: Containers are light in weight, making them highly portable
  • Isolated: Isolated from the underlying infrastructure and from each other
  • Consistent: You can run the docker image as a docker container in any machine where docker is installed, regardless of the operating system
  • Predictable: The same container always yields the exact same application and execution behavior - no matter where or by whom it might be executed

Key Components of Docker

Component Description Purpose
Docker Engine Core part of Docker Handles the creation and management of containers
Docker Image Read-only template Used for creating containers, containing the application code and dependencies
Docker Hub Cloud-based repository Used for finding and sharing container images
Dockerfile Script with instructions Contains instructions to build a Docker image
Docker Registry Storage and distribution system Store images in both public and private modes

Why Containers?

🤔 The Central Question:

Why would we want independent, standardized "application packages"?

Problem 1: Different Development and Production Environments

Challenge:

We often have different development and production environments. We want to build and test in the same environment as we later run our app in production.

✅ Container Solution:
"We want to have the exact same environment for development and production → This ensures that it works exactly as tested."

Problem 2: Inconsistent Team Development Environments

Challenge:

Different development environments within a team/company. Every team member should have the exact same environment when working on the same project.

✅ Container Solution:
"It should be easy to share a common development environment/setup with (new) employees and colleagues."

Problem 3: Clashing Tools Between Projects

Challenge:

Clashing tools/versions between different projects. When switching between projects, tools used in project A should not clash with the tools used in project B.

✅ Container Solution:
"We don't want to uninstall and re-install local dependencies and runtime all the time."

Solution Approach 1: Virtual Machines

What Are Virtual Machines?

🖥️ Virtual Machine Concept:

Virtual machines provide virtual operating systems encapsulated in their own shell, independent from our host operating system.

With virtual machines, we have our host operating system (Windows, macOS, or Linux), and then on top of that, we install the virtual machine - essentially a computer inside our computer.

Virtual Machine Architecture

Virtual Machine Architecture: Each VM runs a complete guest OS

Virtual Machines: Pros and Cons

Pros Cons
  • Separated environment
  • Environment-specific configurations are possible
  • Environment configuration can be shared and reproduced reliably
  • Redundant duplication - waste of space
  • Performance can be slow - boot times can be long
  • Reproducing on another computer/server is possible but may still be tricky

The Overhead Problem with Virtual Machines

⚠️ Key Issues:
  • Virtual Operating System Overhead: Every virtual machine is like a standalone computer running on top of our machine
  • Resource Consumption: Each VM requires significant memory, CPU, and hard drive space
  • Duplication Problem: If you have multiple VMs using the same OS (e.g., Linux), it's installed separately in every machine, wasting enormous amounts of space
  • Scalability Issues: The problem compounds with more virtual machines - each adding identical OS overhead
"Virtual machines solve the environment reproducibility problem but not in a perfect way. The overhead and resource duplication make them inefficient for modern cloud-native applications."

Solution Approach 2: Docker and Containers

💡 Important Understanding:
  • Containers are the key concept
  • Docker is the de facto standard tool for creating and managing them

How Docker Containers Work

Docker Container Architecture

Docker Container Architecture: Containers share the host OS kernel

🔧 Docker Architecture Explained:
  1. Host Operating System: Windows, macOS, Linux - whatever your base system is
  2. Built-in Container Support: We utilize built-in container support that our operating system has (or emulated container support that Docker provides)
  3. Docker Engine: One lightweight tool installed on the system
  4. Containers: Spin up containers containing our code and the crucial tools/runtimes the code needs

Container Configuration and Sharing

📋 Configuration Management:

Containers can be configured and described with a configuration file. This file can be shared with others so they can recreate the container.

Image Building and Distribution:

You can build the container into an image and share that image with others to ensure everyone can launch the same container on their systems.

Containers vs Virtual Machines: Comprehensive Comparison

Aspect Docker Containers Virtual Machines
OS Impact Low impact on OS Bigger impact on OS
Performance Very fast Slower
Disk Space Minimal disk space usage Higher disk space usage
Sharing & Distribution Easy - sharing, re-building, and distribution Challenging - can be complex
Encapsulation Level Encapsulate apps/environments Encapsulate "whole machines"
Boot Time Seconds Minutes
Resource Efficiency Share host OS kernel - highly efficient Each VM needs complete OS - inefficient

Docker Setup

Docker Setup Architecture

Docker Setup: Complete architecture overview

Understanding What You Install

🔧 Docker Installation Components:

When you install Docker (whether Docker Desktop, Docker Toolbox, or directly on Linux), you're primarily installing the Docker Engine.

Docker Engine Includes:
  • Docker Daemon: A background process that keeps running and ensures Docker works - the "heart of Docker"
  • Command Line Interface (CLI): The tool you'll use throughout to run commands, create images and containers
  • REST API: Interface for programs to interact with the daemon

Note: On macOS and Windows, Docker needs a Linux environment to run. Docker Desktop uses built-in OS features to create this environment efficiently. Older systems may need Docker Toolbox, which uses VirtualBox to create a virtual machine running Linux.

Docker Installation Options

Option 1: Docker Desktop (Recommended)

✅ Docker Desktop - Modern Solution:

Docker Desktop is the recommended way of running Docker on macOS and Windows.

System Requirements:
  • macOS: Mac hardware from 2010 or newer
  • Windows: Windows 10 64-bit (Pro, Enterprise, or Education) with Hyper-V enabled
  • Linux: Native Docker Engine installation
Benefits:
  • Uses built-in OS virtualization features
  • Greater performance
  • Doesn't clutter your system
  • Easy installation and management
  • Includes GUI dashboard

Option 2: Docker Toolbox (Legacy Systems)

⚠️ Docker Toolbox - For Older Systems:

If your system doesn't fulfill Docker Desktop requirements, there's an alternative: Docker Toolbox.

What is Docker Toolbox?

Docker Toolbox is a legacy tool (replaced by Docker Desktop) that was historically the only solution for all platforms. It installs:

  • VirtualBox: Creates a virtual machine on your system
  • Docker Engine: Runs inside the VirtualBox VM
  • Docker CLI: Command-line interface
  • Docker Machine: Tool to manage the VM
  • Docker Compose: Tool for multi-container applications
When to Use Docker Toolbox:
  • Older macOS systems (pre-2010 hardware)
  • Windows 7, Windows 8, or Windows 10 Home
  • Systems that don't support Hyper-V

Important: Make sure your system supports virtualization before installing Docker Toolbox. On Windows 8/7, use tools like Speccy or Hardware-Assisted Virtualization Detection Tool to verify.

Docker Installation: Step-by-Step

Installing Docker Desktop

🚀 Docker Desktop Installation:
  1. Visit Official Site: Go to docs.docker.com
  2. Download and Install: Click on "Download and install" section
  3. Check Requirements: Verify your system meets the requirements listed
  4. Download Installer: Get the installer for your platform
  5. Run Installer: Execute the downloaded installer and follow wizard steps
  6. Start Docker: Launch Docker Desktop after installation
  7. Verify Installation: Open terminal and run:
    docker --version
    docker run hello-world

Installing Docker Toolbox (If Needed)

🔧 Docker Toolbox Installation:
  1. Verify Virtualization Support: Ensure your system can run virtual machines
  2. Visit Toolbox Releases: Search for "Docker Toolbox releases" on GitHub
  3. Download Latest Version:
    • Windows: Download the .exe installer
    • macOS: Download the .pkg package
  4. Run Installer: Execute the downloaded file
  5. Choose Components: Ensure these are selected:
    • VirtualBox (creates the virtual machine)
    • Docker Engine
    • Docker Machine
    • Docker Compose
    • Kitematic (optional GUI)
  6. Configure Options:
    • Check "Add Docker binaries to PATH"
    • Choose installation location
    • Select desktop shortcuts (optional)
  7. Complete Installation: Click Install and wait for setup to finish
  8. Launch Docker: Double-click "Docker Quickstart Terminal" shortcut
  9. Verify Setup: The terminal should show the Docker whale logo and you can run:
    docker --version

Installing Docker on Linux

🐧 Linux Installation (Ubuntu Example):
# Update package index
sudo apt-get update

# Install prerequisites
sudo apt-get install ca-certificates curl gnupg lsb-release

# Add Docker's official GPG key
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Set up repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.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-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Verify installation
sudo docker run hello-world

Post-Installation Setup

🔧 Recommended Post-Installation Steps:
  1. Start Docker Daemon: Ensure Docker Desktop is running (or Docker service on Linux)
  2. Test Installation:
    docker run hello-world

    This pulls a test image and runs it in a container. If successful, you'll see a welcome message.

  3. Linux: Manage Docker as Non-Root User (Optional):
    sudo groupadd docker
    sudo usermod -aG docker $USER
    newgrp docker

Recommended Development Environment

💻 Setting Up Your Code Editor:

While you'll primarily run Docker commands in the command line, you'll also work with configuration files (Dockerfiles) and application code. A good code editor is essential.

Recommended Editor: Visual Studio Code
  • Why VS Code?
    • Free and open-source
    • Available for macOS, Windows, and Linux
    • Integrated terminal
    • Excellent Docker support
  • Download: Visit code.visualstudio.com
  • Install: Run the installer and follow setup wizard

VS Code Configuration for Docker Development

🎨 Recommended VS Code Setup:
  1. Theme (Optional):
    • Go to: File → Preferences → Color Theme
    • Select: "Dark+ (default dark)" for better visibility
  2. View Settings:
    • Menu: View → Appearance
    • Show/hide: Side bar, Status bar, Activity bar as needed
  3. Essential Extensions:
    • Docker Extension:
      • Click Extensions icon (or Ctrl+Shift+X)
      • Search: "Docker"
      • Install: Docker by Microsoft
      • Benefits: Syntax highlighting, IntelliSense for Dockerfiles, container management
    • Prettier Extension (Optional):
      • Search: "Prettier - Code formatter"
      • Install for automatic code formatting
      • Helps keep configuration files clean
  4. Integrated Terminal:
    • Access: View → Terminal (or Ctrl+`)
    • Benefit: Run Docker commands directly in VS Code
    • Auto-opens in your project directory
  5. Opening Projects:
    • File → Open Folder
    • Select folder containing your project
    • VS Code opens with file explorer on left

Basic Docker Commands

# Check Docker version
docker --version

# Pull an image from Docker Hub
docker pull ubuntu:latest

# List all images
docker images

# Run a container
docker run -it ubuntu:latest /bin/bash

# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# Stop a container
docker stop <container_id>

# Remove a container
docker rm <container_id>

# Remove an image
docker rmi <image_id>

Creating Your First Docker Container

🎯 Practical Example:

Let's create a real Docker container to validate your installation and understand the basic workflow. This example uses a simple Node.js application, but remember: you don't need to know Node.js. The concepts apply to any programming language.

Example Application Overview

📦 Sample Node.js Web Server:

This example is a basic Node.js application that:

  • Starts a web server on port 3000
  • Listens for GET requests
  • Returns simple HTML response: "Hi there!"
  • Includes dummy database connection code (simulates async operations)
  • Requires Node.js version 14.3 or higher (uses top-level await)

Project Structure:

project/
├── app.mjs # Application code
├── package.json # Dependencies list
└── Dockerfile # Docker configuration

Running Without Docker (Traditional Way)

🔄 Traditional Approach - What You'd Normally Do:
  1. Visit nodejs.org and download Node.js
  2. Install Node.js on your system
  3. Open terminal in project folder
  4. Run: npm install (installs dependencies from package.json)
  5. Run: node app.mjs (starts the server)

Problems with This Approach:

  • Requires Node.js installation on every machine
  • Version conflicts between projects
  • "Works on my machine" syndrome
  • Team members need exact same setup

Running With Docker (The Better Way)

✅ Docker Approach - Containerized:

Instead of installing Node.js locally, we create a container that includes everything needed.

Key Concept:

Containers are based on Images. First, we create an image (blueprint), then run containers from that image.

Step 1: Create a Dockerfile

📝 The Dockerfile:

Create a file named Dockerfile (no extension) in your project root:

# Use Node.js as base image
FROM node:14

# Set working directory in container
WORKDIR /app

# Copy package.json to working directory
COPY package.json .

# Install dependencies inside container
RUN npm install

# Copy application code
COPY . .

# Expose port 3000 to outside world
EXPOSE 3000

# Command to run when container starts
CMD ["node", "app.mjs"]
What Each Instruction Does:
  • FROM node:14 - Start with Node.js 14 environment (downloaded from Docker Hub)
  • WORKDIR /app - Create and use /app directory in container filesystem
  • COPY package.json . - Copy dependency list into container
  • RUN npm install - Install dependencies inside container
  • COPY . . - Copy rest of application code
  • EXPOSE 3000 - Document that app uses port 3000
  • CMD ["node", "app.mjs"] - Run the application when container starts

Step 2: Build the Docker Image

🔨 Building Your First Image:

Open terminal in your project directory and run:

docker build .
What Happens:
  1. Docker finds the Dockerfile in current directory
  2. Downloads Node.js base image from Docker Hub
  3. Executes each instruction in the Dockerfile
  4. Creates a new image with all setup complete
  5. Outputs: "Successfully built [IMAGE_ID]"

💡 Tip: On Windows, you might see the image ID displayed differently. Look for it in the output.

⚠️ Troubleshooting: If you get an error, ensure Docker Desktop is running in the background.

Step 3: Run the Container

🚀 Starting Your Container:

Run the container with port mapping:

docker run -p 3000:3000 [IMAGE_ID]
Breaking Down the Command:
  • docker run - Start a new container
  • -p 3000:3000 - Port mapping (host:container)
  • [IMAGE_ID] - The ID from the build step (or use image name)
Port Mapping Explained:

By default, containers are isolated. The -p flag "publishes" a container port to your host machine:

  • First 3000: Port on your local machine (localhost)
  • Second 3000: Port inside the container
  • Result: localhost:3000 on your machine → port 3000 in container

After Running: Your terminal will appear "stuck" - this is normal! The container is running and the web server is active.

Step 4: Test Your Containerized Application

🎉 Access Your App:
  1. Open a web browser
  2. Visit: http://localhost:3000
  3. You should see: "Hi there!"
What Just Happened:
  • ✅ Application is running in a container
  • ✅ No Node.js installed on your system
  • ✅ No npm install run in your project folder
  • ✅ Everything runs isolated in the container
  • ✅ Same container works on any machine with Docker

Step 5: Stop the Container

🛑 Stopping Your Container:

Option 1: From Terminal (Quick):

# Press Ctrl+C in the terminal where container is running

Option 2: From Another Terminal (Proper Way):

  1. Open a new terminal window or tab
  2. List running containers:
    docker ps
  3. Copy the container name (auto-generated, like "festive_maxwell")
  4. Stop the container:
    docker stop [CONTAINER_NAME]

Verify: Try accessing localhost:3000 again - it should not be reachable. The container has stopped.

What You Accomplished

🎓 Congratulations! You've:
  • ✅ Verified Docker installation works correctly
  • ✅ Created your first Dockerfile
  • ✅ Built a Docker image
  • ✅ Ran a containerized application
  • ✅ Understood port mapping
  • ✅ Managed container lifecycle (start/stop)
  • ✅ Experienced the power of containerization
Key Achievement:

You ran a Node.js application without installing Node.js on your system. Everything ran in an isolated, portable container that works identically on any machine with Docker!

Key Docker Workflow

📋 Typical Docker Development Workflow:
  1. Create a Dockerfile: Define your application environment
    FROM node:14
    WORKDIR /app
    COPY package*.json ./
    RUN npm install
    COPY . .
    EXPOSE 3000
    CMD ["npm", "start"]
  2. Build the Image: Create a container image from the Dockerfile
    docker build -t my-app:1.0 .
  3. Run the Container: Start your application
    docker run -d -p 3000:3000 --name my-app-container my-app:1.0
  4. Push to Registry: Share your image
    docker tag my-app:1.0 username/my-app:1.0
    docker push username/my-app:1.0
  5. Deploy Anywhere: Pull and run on any system
    docker pull username/my-app:1.0
    docker run -d -p 3000:3000 username/my-app:1.0

When to Use Docker vs Virtual Machines

Use Case Use Docker Containers Use Virtual Machines
Microservices ✅ Ideal - lightweight, fast ❌ Too heavy
CI/CD Pipelines ✅ Fast build and deploy ❌ Slow boot times
Development Environments ✅ Easy sharing, consistency ⚠️ Possible but heavy
Testing Different OS ❌ Shares host kernel ✅ Full OS isolation
Legacy Monolithic Apps ⚠️ May need modification ✅ Run as-is
High-Density Deployment ✅ Hundreds of containers ❌ Limited by resources

Docker Use Cases

💼 Real-World Docker Applications:
  • Microservices Architecture: Package each service independently
  • Continuous Integration/Deployment: Consistent build and test environments
  • Development Environments: Onboard developers quickly with pre-configured environments
  • Application Isolation: Run multiple versions of dependencies without conflicts
  • Cloud Migration: "Lift and shift" applications to cloud platforms
  • Scaling Applications: Quickly spin up multiple instances
  • Testing: Create isolated test environments

Docker Best Practices

✅ Docker Development Best Practices:
  1. Use Official Base Images: Start with trusted images from Docker Hub
  2. Keep Images Small: Use multi-stage builds and minimal base images (Alpine)
  3. One Process Per Container: Follow the single responsibility principle
  4. Use .dockerignore: Exclude unnecessary files from build context
  5. Don't Run as Root: Create and use non-root users for security
  6. Leverage Build Cache: Order Dockerfile instructions to maximize caching
  7. Tag Images Properly: Use semantic versioning (e.g., app:1.0.0)
  8. Health Checks: Implement container health checks
  9. Use Environment Variables: Configure containers through environment variables
  10. Scan for Vulnerabilities: Regularly scan images for security issues

Key Takeaways

🎓 Summary:
  • Docker = Containerization Platform: Tool for creating and managing containers
  • Containers = Standardized Software Units: Package code and dependencies together
  • Key Advantage: Same container works identically everywhere
  • Lightweight vs VMs: Share host OS kernel instead of running full OS
  • Performance: Fast startup (seconds vs minutes), minimal resource overhead
  • Portability: Easy to share, rebuild, and distribute
  • Consistency: Exact same environment for development, testing, and production
  • Isolation: No conflicts between different project dependencies
  • Components: Docker Engine, Images, Containers, Dockerfile, Registries
  • Workflow: Write Dockerfile → Build Image → Run Container → Push to Registry → Deploy Anywhere

Docker Ecosystem: Additional Tools

Docker Hub

☁️ Docker Hub - The Image Registry:

Docker Hub is a cloud-based repository for hosting and sharing Docker images.

What is Docker Hub?
  • Central place to store and distribute container images
  • Access thousands of official images (Node.js, Python, Nginx, etc.)
  • Share your own images publicly or privately
  • Automate image builds from GitHub/Bitbucket
  • Free for public repositories
Common Docker Hub Operations:
# Login to Docker Hub
docker login

# Tag your image for Docker Hub
docker tag my-app:1.0 username/my-app:1.0

# Push image to Docker Hub
docker push username/my-app:1.0

# Pull image from Docker Hub
docker pull username/my-app:1.0

# Search for images
docker search nginx

Note: You don't need Docker Hub account to pull public images, but you need one to push your own images.

Docker Compose

🎼 Docker Compose - Multi-Container Management:

Docker Compose is a tool that simplifies managing multi-container applications.

Why Docker Compose?
  • Define entire multi-container setup in one YAML file
  • Start all containers with single command
  • Manage complex applications easily
  • Ideal for microservices architectures
  • Perfect for development environments
Example docker-compose.yml:
version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
  database:
    image: postgres:13
    environment:
      POSTGRES_PASSWORD: example
  redis:
    image: redis:alpine
Common Docker Compose Commands:
# Start all services
docker-compose up

# Start in background
docker-compose up -d

# Stop all services
docker-compose down

# View logs
docker-compose logs

# List running services
docker-compose ps

Note: Docker Compose is included with Docker Desktop. On Linux, you may need to install it separately.

Kubernetes

☸️ Kubernetes - Container Orchestration:

Kubernetes is a powerful platform for automating deployment, scaling, and management of containerized applications in production.

When You Need Kubernetes:
  • Deploying containerized applications at scale
  • Managing hundreds or thousands of containers
  • Need automatic scaling and load balancing
  • Self-healing capabilities (restart failed containers)
  • Rolling updates and rollbacks
  • Production-grade container orchestration

Learning Path: Master Docker basics first, then Docker Compose, then move to Kubernetes for production deployments.