0% found this document useful (0 votes)
52 views105 pages

DOCKER - SWARM - ECS Notes

Docker is an open-source platform that enables developers to build, package, and distribute applications using containerization, ensuring consistency across environments. It revolutionizes software deployment by allowing lightweight, fast, and efficient resource utilization compared to traditional virtual machines. Docker's architecture includes components like the Docker Engine, Daemon, Client, Images, and Registries, facilitating the management and running of containers effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
52 views105 pages

DOCKER - SWARM - ECS Notes

Docker is an open-source platform that enables developers to build, package, and distribute applications using containerization, ensuring consistency across environments. It revolutionizes software deployment by allowing lightweight, fast, and efficient resource utilization compared to traditional virtual machines. Docker's architecture includes components like the Docker Engine, Daemon, Client, Images, and Registries, facilitating the management and running of containers effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 105

DOCKER

1. Introduction to Docker
1.1 What is Docker?
Docker is an open-source platform that enables developers to build, package, and distribute
applications using containerization. A Docker container is a lightweight, portable, and isolated
environment that encapsulates an application along with its dependencies, ensuring consistency
across different computing environments.
Docker allows developers to:
 Package applications and their dependencies together.
 Run applications consistently across multiple environments (development, testing, and
production).
 Reduce conflicts between different software versions.
 Improve resource efficiency by sharing the underlying OS kernel.
Example:
Suppose you have a Python application that requires Python 3.10 and specific libraries. Without
Docker, a developer might install dependencies manually, leading to inconsistencies between
environments.
With Docker, you create a Docker image containing the necessary Python version and dependencies,
ensuring that the application runs the same way everywhere.
Simple Dockerfile for a Python Application:

# Use an official Python runtime as the base image


FROM python:3.10

# Set the working directory


WORKDIR /app

# Copy application files


COPY . /app

# Install dependencies
RUN pip install -r requirements.txt

# Run the application


CMD ["python", "app.py"]
With this setup, the application runs identically on any machine with Docker installed.

1.1.a History of Containers & Docker


Early Days of Virtualization
Before Docker, developers used virtual machines (VMs) to run multiple applications on a single
physical machine. However, VMs had high overhead because they required a full operating system
for each instance.
Evolution of Containers
 2000s: Linux Containers (LXC) – Provided process isolation using cgroups and namespaces.
 2013: Docker – Built on LXC but introduced simplified container management with:
o Docker Engine
o Docker Hub (container registry)
o Docker CLI
Docker revolutionized software deployment by making containers easier to use and manage.

1.1.b Difference Between Containers & Virtual Machines (VMs)


Feature Virtual Machines (VMs) Containers
Isolation Fully isolated OS instances Process-level isolation using the host OS
Startup Time Minutes (due to OS boot) Seconds (lightweight)
Resource Usage High (each VM has its own OS) Low (shared OS kernel)
Storage Size Large (several GBs) Small (MBs)
Portability Limited (depends on hypervisor) High (runs anywhere with Docker)

Example:
Imagine running 3 applications with different environments:
 Using VMs: You need three separate VMs, each with its own OS, consuming a lot of memory.
 Using Docker: You need three containers, each sharing the same OS kernel, making it
lightweight and efficient.
Diagram:
VM Approach: Docker Approach:
---------------------- ----------------------
| Host OS | | Host OS |
| Hypervisor | | Docker Engine |
| ---------------- | | ------------------ |
| VM1 | VM2 | VM3 | | Container1 | Container2 | Container3 |
---------------------- ----------------------

1.1.c Why Use Docker?


1️ Consistency Across Environments
Docker ensures that an application behaves identically in development, testing, and
production.
2️ Lightweight & Fast
 No need for a full OS per application.
 Containers start in milliseconds compared to minutes for VMs.
3️ Efficient Resource Utilization
Since containers share the same OS kernel, they use less CPU & memory than VMs.
4️ Portability
A containerized application runs anywhere: on local machines, cloud, or on-premise servers.
Example:
A Python application packaged as a Docker container runs identically on:
 MacBook (local development)
 AWS EC2 instance (cloud)
 Google Cloud Kubernetes (production)
5️ Scalability & Microservices
 Docker makes it easy to scale applications horizontally.
 Ideal for microservices architecture, where different services run in separate containers.
6️ Faster CI/CD & Deployment
 Containers eliminate “It works on my machine” issues.
 Docker integrates with CI/CD tools (Jenkins, GitHub Actions, GitLab CI/CD) for automated
deployments.
Example CI/CD Workflow with Docker:
name: Docker CI/CD
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Build Docker Image


run: docker build -t myapp:latest .

- name: Push to Docker Hub


run: docker push myapp:latest

- name: Deploy to Server


run: docker run -d -p 80:80 myapp:latest
7️Security
 Docker isolates applications to prevent dependency conflicts.
 Features like Docker Content Trust (DCT) help verify image authenticity.

1.1.d Use Cases for Docker


1. Development & Testing
 Developers use Docker to test applications in isolated environments.
 Easily switch between different versions of a database or programming language.
 Example:
 docker run -d --name mydb -e POSTGRES_PASSWORD=mysecret -p 5432:5432 postgres:15
🚀 2. Microservices Architecture
 Each service (API, frontend, database) runs in a separate container.
 Containers can be scaled independently.
 Example stack:
o Frontend: React.js in an Nginx container
o Backend: Django REST API in a Python container
o Database: PostgreSQL in a database container
🌍 3. Cloud Deployments
 Docker is widely used in AWS, Azure, Google Cloud.
 Services like AWS ECS, Google Cloud Run run containerized apps.
🔁 4. Continuous Integration/Continuous Deployment (CI/CD)
 Developers package their apps into containers and deploy them via CI/CD pipelines.
 Example: GitHub Actions automating Docker image builds.
💾 5. Data Science & AI/ML Workloads
 Machine learning engineers use Docker to package Jupyter Notebooks, TensorFlow, and
PyTorch environments.
 Example:
 docker run -it tensorflow/tensorflow:latest-gpu bash
6. Running Legacy Applications
 Run older software on modern systems without compatibility issues.

1.2 Docker Architecture


Docker follows a client-server architecture, where different components work together to manage
and run containers efficiently. These components include:
1. Docker Engine
2. Docker Daemon (dockerd) – Runs in the background and manages Docker objects like
images, volume, network, & containers.
3. Docker Client (docker CLI) – Command-line interface to interact with Docker.
4. Docker Images – Blueprint for creating containers.
5. Docker Containers – Running instances of Docker images.
6. Docker Registries – Store and distribute Docker images.
Let’s dive into each component in detail with practical examples.

1.2.1 Docker Engine


Docker Engine is the core component of Docker that runs and manages containers. It is responsible
for building, running, and distributing containerized applications.
Components of Docker Engine:
 Docker Daemon (dockerd) – The background service that runs on the host machine,
managing containers, images, networks, and volumes.
 REST API – The interface through which clients communicate with the daemon.
 Docker CLI (Command Line Interface) – A tool to interact with the Docker Daemon using
commands.
Example:
When you run:
docker run hello-world
 The Docker CLI sends a request to the Docker Daemon.
 The Daemon checks for the "hello-world" image locally; if not found, it pulls it from
Docker Hub.
 A new container is created from the image and executed.
1.2.2 Docker Daemon (dockerd)
What is the Docker Daemon?
The Docker Daemon (dockerd) is a background service that:
 Manages Docker objects (containers, images, networks, volumes).
 Handles API requests from the Docker Client (docker CLI).
 Builds, runs, and monitors containers.
How It Works
 The Docker Daemon listens for commands from the Docker CLI.
 It processes these commands and performs actions like creating, running, or stopping
containers.
 It communicates with Docker Registries to pull/push images.
Example: Checking if the Docker Daemon is Running
Run the following command to check if the Docker Daemon is active:
sudo systemctl status docker
If Docker is running, you should see output like:
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2025-03-26 10:15:00 UTC; 2h ago
Starting & Stopping the Docker Daemon
To start the Docker Daemon:
sudo systemctl start docker
To stop the Docker Daemon:
sudo systemctl stop docker
Docker Daemon Logs
To troubleshoot Docker issues, check the logs:
sudo journalctl -u docker --no-pager

1.2.3 Docker Client (docker CLI)


What is the Docker Client?
The Docker Client (docker CLI) is the primary way users interact with Docker. It:
 Sends commands to the Docker Daemon via the REST API.
 Supports multiple commands like docker run, docker build, docker ps, docker stop, etc.
Basic Commands
Command Description
docker version Check installed Docker version
docker info Display system-wide information
docker images List locally available images
docker ps List running containers
docker ps -a List all containers (including stopped ones)
docker stop <container_id> Stop a running container
docker rm <container_id> Remove a stopped container
Example: Running a Container Using Docker CLI
docker run -d --name my_nginx -p 8080:80 nginx
 docker run → Runs a container.
 -d → Runs in detached mode (background).
 --name my_nginx → Assigns a custom name to the container.
 -p 8080:80 → Maps host port 8080 to container port 80.
 nginx → Uses the official nginx image.
To verify the container is running:
docker ps

1.2.4 Docker Client and Daemon


The Docker Client and Docker Daemon communicate using a REST API. The client sends commands,
and the daemon executes them.
How It Works?
1. The user runs a Docker command using the CLI.
2. The Docker Client sends the request to the Docker Daemon.
3. The Daemon processes the request, such as pulling an image, creating a container, or
stopping a service.
Example:
 Running docker ps:
docker ps
o The client requests a list of running containers.
o The daemon responds with details about the active containers.

 Creating and running a container:


docker run -d -p 8080:80 nginx
o The client asks the daemon to:
 Download the Nginx image if it's not available.
 Create a container from the image.
 Run the container in detached mode (-d).
 Expose port 80 from the container to port 8080 on the host.

1.2.5 Docker Images


What is a Docker Image?
A Docker Image is a read-only template containing:
 Application code.
 Required dependencies (libraries, runtimes, configurations).
 An OS layer (minimal base system like Ubuntu, Alpine).
How Docker Images Work
 Docker Images are built from a Dockerfile.
 Each layer in the image is cached, allowing efficient builds.
 Images are immutable (cannot be changed once built).
Example: Creating a Custom Docker Image
1️ Create a Dockerfile for a Python app:
# Base image
FROM python:3.10

# Set working directory


WORKDIR /app

# Copy app files


COPY . /app

# Install dependencies
RUN pip install -r requirements.txt

# Run the application


CMD ["python", "app.py"]
2️ Build the Docker Image:
docker build -t my-python-app .
3️ Verify the Image:
docker images
4️ Run a Container from the Image:
docker run -d --name python_app my-python-app

1.2.6 Docker Containers


What is a Docker Container?
A Docker Container is a running instance of a Docker image. It:
 Isolated from the host system.
 Shares the host OS kernel but has its own process namespace.
 Can be started, stopped, restarted, and removed.
Key Container Commands
Command Description
docker ps List running containers
docker stop <container_id> Stop a running container
docker start <container_id> Start a stopped container
docker restart <container_id> Restart a container
docker rm <container_id> Remove a stopped container
Example: Running a Container
docker run -d --name webserver -p 8080:80 nginx
 Runs an nginx container with port 8080 mapped to port 80.

To access the running container’s shell:


docker exec -it webserver bash
To remove a container:
docker stop webserver
docker rm webserver

1.2.7 Docker Registries


What is a Docker Registry?
A Docker Registry is a repository that stores and distributes Docker images.

Types of Registries
1. Public Registry – Docker Hub (default)
2. Private Registry – Self-hosted or cloud-based (AWS ECR, Azure ACR, Google GCR)

Working with Docker Hub


Pull an Image from Docker Hub
docker pull nginx
Tag an Image
docker tag my-python-app myusername/my-python-app:v1
Push an Image to Docker Hub
docker login
docker push myusername/my-python-app:v1
Setting Up a Private Registry
To host a private Docker registry:
docker run -d -p 5000:5000 --name registry registry:2
Now, push images to the local registry:
docker tag my-python-app localhost:5000/my-python-app
docker push localhost:5000/my-python-app

1.3 Installation & Setup


1. Installing Docker on Windows, macOS, and Linux
A. Installing Docker on Windows (WSL2)
1. Download Docker Desktop from the official site: 👉 Docker Desktop for Windows
2. Run the installer and follow the setup instructions.
3. Enable WSL 2 (Windows Subsystem for Linux 2) for better performance:
o Open PowerShell as Administrator and run:
o wsl --set-default-version 2
o Ensure you have installed a Linux distribution (e.g., Ubuntu) from the Microsoft
Store.
Post-Installation Verification:
docker --version
docker info
docker run hello-world

B. Installing Docker on macOS


1. Download Docker Desktop for Mac: 👉 Docker Desktop for macOS
2. Install and launch Docker by following the installer.
3. Ensure Virtualization & Apple Silicon (if using M1/M2 chip) compatibility.
Post-Installation Verification:
docker --version
docker run hello-world

C. Installing Docker on Linux (Ubuntu/Debian-based Distributions)


1. Update package list and install dependencies:
sudo apt update
sudo apt install -y ca-certificates curl gnupg
2. Add Docker’s GPG key & repository:
sudo install -m 0755 -d /etc/apt/keyrings (Creates a secure directory for key storage:)

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee


/etc/apt/keyrings/docker.asc > /dev/null null (Downloads the official Docker GPG key and saves
it:)

sudo chmod a+r /etc/apt/keyrings/docker.asc (Grant read permission to all user on machine)

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc]


https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee
/etc/apt/sources.list.d/docker.list > /dev/null (Adds the Docker repository URL to APT’s sources
list)

sudo apt update (Updates APT package index so it recognizes the new repository)

3. Install Docker Engine and related packages:


sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-
plugin
4. Enable and start Docker service:
sudo systemctl enable docker
sudo systemctl start docker

Running Docker as a Non-Root User (sudo-less Docker Usage)


To allow running Docker without sudo, add your user to the Docker group:
sudo usermod -aG docker $USER
newgrp docker # Apply changes without logging out
Post-Installation Verification:
docker --version
docker run hello-world

2. Configuring Docker Daemon (/etc/docker/daemon.json)


Docker can be configured using a JSON-based configuration file at /etc/docker/daemon.json. This file
is useful for customizing settings like logging drivers, storage backends, and network configurations.
Example Configuration:
{
"log-driver": "json-file",
"log-level": "warn",
"storage-driver": "overlay2"
}
Restart Docker Daemon after changes:
sudo systemctl restart docker

3. Docker Desktop vs. Docker Engine


Feature Docker Desktop Docker Engine
Platform Windows & macOS Linux
Installation GUI-based Command-line
Virtualization Uses Hyper-V / WSL2 (Windows) or HyperKit (macOS) Uses native Linux features
Includes GUI Yes No
Use Case Developer-friendly, local testing Production-ready on servers
Key Takeaways:
 Use Docker Desktop for development on Windows/macOS with an easy-to-use GUI.
 Use Docker Engine for Linux servers in production environments.

4. Verifying Docker Installation


After installation, verify Docker is running with these commands:
docker --version # Check Docker version
docker info # Detailed system info
docker run hello-world # Verify container execution
If Docker is installed correctly, running docker run hello-world should output a success message.

5. Installing Docker Using Ansible


What is Ansible?
Ansible is an automation tool used to manage infrastructure as code. It is commonly used to install
and configure software on multiple servers efficiently.
Ansible Playbook to Install Docker on Ubuntu

Step 1: Create an Ansible Playbook (install_docker.yml)


---
- name: Install Docker on Ubuntu
hosts: all
become: yes
tasks:
- name: Update APT package index
apt:
update_cache: yes

- name: Install dependencies


apt:
name:
- ca-certificates
- curl
- gnupg
state: present

- name: Add Docker GPG Key


shell: |
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee
/etc/apt/keyrings/docker.asc > /dev/null
sudo chmod a+r /etc/apt/keyrings/docker.asc

- name: Add Docker Repository


shell: |
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee
/etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update

- name: Install Docker Engine


apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
state: present

- name: Enable and Start Docker Service


systemd:
name: docker
enabled: yes
state: started

- name: Add user to Docker group


user:
name: "{{ ansible_user }}"
groups: docker
append: yes
Step 2: Run the Playbook Ensure Ansible is installed, then execute:
ansible-playbook -i inventory.ini install_docker.yml
(Replace inventory.ini with your server's details.)

6. Real-World Use Cases for Ansible-based Docker Installation


✅ Consistency – Ensures Docker is installed uniformly on multiple servers. ✅ Automation – Reduces
manual installation efforts. ✅ Scalability – Quickly installs Docker across many machines. ✅
Infrastructure as Code (IaC) – Maintains a version-controlled, repeatable setup.
Common Scenarios:
 Cloud Deployments – Installing Docker on AWS, Azure, or GCP instances.
 CI/CD Pipelines – Automating server setup before deploying containerized applications.
 Microservices Management – Preparing environments for Kubernetes or Docker Swarm
clusters.

2. Docker Images & Containers


Working with Docker Images
1. What is a Docker Image?
A Docker image is a lightweight, standalone, and executable package that contains everything
needed to run an application, including:
 Application code
 Runtime (e.g., Python, Node.js, Go)
 Dependencies and libraries
 Environment configurations
 Minimal OS files
Key Features of Docker Images:
1. Read-Only & Immutable: Once built, images do not change.
2. Layered Structure: Each image consists of multiple layers, reducing duplication and
optimizing storage.
3. Portable & Reproducible: Runs on any system with Docker installed.

2. Managing Docker Images


2.1 Listing Available Images
To see all images stored locally:
docker images
Example output:
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 1318b700e415 2 weeks ago 72.9MB
python 3.9 8caa311cb592 3 weeks ago 882MB

2.2 Pulling Images from Docker Hub


Docker images can be downloaded from Docker Hub using:
docker pull <image-name>:<tag>
Example 1: Pulling Ubuntu Latest Image
docker pull ubuntu
Example 2: Pulling a Specific Version
docker pull ubuntu:20.04

2.3 Removing Images


To remove an image:
docker rmi <image-name>:<tag>
Force Removing an Image
docker rmi -f <image-id>
Removing All Unused Images
docker image prune -a

3. Creating Custom Docker Images


3.1 Creating a Dockerfile
A Dockerfile is a script containing instructions to build a custom image.
Example: Creating a Flask Web App Image
# Use an official Python runtime as base image
FROM python:3.9

# Set the working directory inside the container


WORKDIR /app

# Copy application files


COPY app.py requirements.txt /app/

# Install dependencies
RUN pip install -r requirements.txt

# Expose the application port


EXPOSE 5000

# Define the command to run the application


CMD ["python", "app.py"]
3.2 Building the Image
docker build -t myflaskapp .
3.3 Running the Container
docker run -p 5000:5000 myflaskapp

4. Optimizing Image Sizes with Multi-Stage Builds


Multi-stage builds help reduce image size by discarding unnecessary dependencies.
Example: Building a Go Application with Multi-Stage Builds

# Stage 1: Build Stage


FROM golang:1.18 as builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Stage 2: Production Stage (Smaller Image)
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]
Benefits of Multi-Stage Builds:
✅ Efficiency – Reduces build time. ✅ Smaller Image Size. ✅ Enhanced Security. ✅ Faster Deployment.

5. Creating a Private Docker Registry


A private registry is useful for hosting proprietary images securely.
5.1 Running a Private Registry
To start a private registry on port 5000:
docker run -d -p 5000:5000 --restart always --name registry registry:2
5.2 Tagging an Image for a Private Registry
docker tag ubuntu localhost:5000/myubuntu
5.3 Pushing an Image to the Private Registry
docker push localhost:5000/myubuntu
5.4 Pulling an Image from the Private Registry
docker pull localhost:5000/myubuntu

6. Useful Docker Image Commands


Command Description
docker build -t <image-name> . Builds a Docker image from a Dockerfile
docker images Lists all available images
docker history <image-name> Shows image layer history
docker inspect <image-name> Displays metadata about an image
docker load -i <image.tar> Loads an image from a tar file
docker save -o <image.tar> <image-name> Saves an image as a tar file
docker tag <source> <target> Tags an image for repository use
docker push <image-name> Pushes an image to a registry
docker rmi <image-name> Removes an image
docker prune -a Deletes all unused images

7. Example Commands with Outputs


7.1 Viewing Image History
docker history ubuntu
Example Output:
IMAGE CREATED CREATED BY SIZE
1318b700e415 2 weeks ago /bin/sh -c #(nop) CMD ["sh"] 72.9MB
7.2 Inspecting an Image
docker inspect ubuntu
 Provides details such as size, layers, and configuration.
7.3 Saving and Loading an Image
docker save -o ubuntu.tar ubuntu
docker load -i ubuntu.tar
7.4 Tagging an Image
docker tag ubuntu myrepo/ubuntu:v1
7.5 Pushing an Image to Docker Hub
docker push myrepo/ubuntu:v1

Docker Containers - Basics


What is a Docker Container?
A Docker container is a lightweight, standalone, and executable package that includes:
 The application code
 Runtime (if needed)
 System tools and libraries
 Dependencies
Containers run the same way in any environment, making them perfect for developing, testing, and
deploying applications.

Running a Container (docker run)


The docker run command is used to create and start a new container.
1. Running a Normal Container
docker run ubuntu echo "Hello from Ubuntu Container"
Explanation:
 This pulls the Ubuntu image (if not already available).
 Runs the echo command inside the container.
 After printing "Hello from Ubuntu Container", the container stops.
Output:
Hello from Ubuntu Container

2. Running a Container with Port Binding


Port binding allows exposing container services to the host machine.
docker run -d -p 8080:80 nginx
Explanation:
 -d → Runs the container in detached mode.
 -p 8080:80 → Maps port 80 of the container to port 8080 of the host.
 nginx → Uses the Nginx web server image.

Verify it’s running:


docker ps
Check the service in the browser:
http://localhost:8080

3. Running a Container in Attached vs Detached Mode


 Attached Mode (Default):
 docker run ubuntu bash
o Runs interactively, and you can see output live.
o Press CTRL+C to stop the container.
 Detached Mode (-d flag):
docker run -d ubuntu sleep 1000
o Runs in the background.
o You can re-attach later using:
o docker attach <container_id>

4. Naming a Container (--name flag)


You can assign a custom name to a container:
docker run --name my_ubuntu_container ubuntu
Check its name:
docker ps -a

Listing and Managing Containers


1. List Running Containers (docker ps)
docker ps
Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
7f3d4a2b6c3d nginx "nginx -g…" 10 minutes ago Up 10 mins my_nginx
2. List All Containers (Including Stopped) (docker ps -a)
docker ps -a
3. Stop a Running Container (docker stop)
docker stop <container_id>
4. Remove a Container (docker rm)
docker rm <container_id>
 Only removes stopped containers.
5. Remove All Stopped Containers
docker rm $(docker ps -aq)
6. Force Remove a Running Container (docker rm -f)
docker rm -f <container_id>

Executing Commands Inside Containers


By default, a primary process runs in a container (e.g., Nginx or Python). However, additional
processes can be executed inside a running container using docker exec.
Running an Interactive Shell (docker exec)
docker exec -it my_nginx bash
Explanation:
 -i → Enables interactive mode.
 -t → Opens a terminal session.

Overriding CMD While Running a Container


By default, Docker runs the CMD defined in the image, but you can override it:
docker run ubuntu echo "This is a custom command"
 This replaces the default CMD with echo "This is a custom command".

Restart Policies in Docker


Restart policies help containers restart automatically after crashes.
1. No Restart (--restart=no)
docker run --restart=no ubuntu
2. Restart on Failure (--restart=on-failure)
docker run --restart=on-failure ubuntu
 Restarts the container only if it exits with a non-zero status.
3. Always Restart (--restart=always)
docker run --restart=always ubuntu
 Restarts the container even after a manual stop.
4. Restart Unless Stopped (--restart=unless-stopped)
docker run --restart=unless-stopped ubuntu
 Restarts automatically unless stopped manually.

Viewing Logs (docker logs)


To check container logs:
docker logs <container_id>

Copying Files Between Host & Container (docker cp)


To copy files from host to container:
docker cp myfile.txt <container_id>:/app/
To copy files from container to host:
docker cp <container_id>:/app/myfile.txt .

Committing Changes to a New Image (docker commit)


To save changes made inside a running container as a new image:
docker commit <container_id> my_custom_image

Checking Resource Usage (docker stats)


Monitor resource usage (CPU, memory, network) of containers:
docker stats
Example Output:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT NET I/O BLOCK I/O
7f3d4a2b6c3d my_nginx 0.03% 15.5MiB / 1GiB 1.2MB / 500kB 0B / 0B

Automatically Removing Containers on Exit (--rm)


If you want a container to be deleted automatically after execution:
docker run --rm ubuntu echo "Temporary container"
This container will not be saved after it stops.

Container Logs and Shell Access


1. Checking Container Logs (docker logs)
docker logs <container_id>
Shows logs generated by a running container.
2. Attaching to a Running Container (docker attach)
docker attach <container_id>
Lets you see the live output of a container.

3. Accessing the Shell of a Running Container


docker exec -it <container_id> /bin/bash
Gives an interactive terminal inside the container.
EXTRA NOTE:

Monitoring Disk Usage


1. Check Disk Space Usage (df -h)
df -h
Output:
Filesystem Size Used Avail Use% Mounted on
udev 3.8G 0 3.8G 0% /dev
tmpfs 776M 74M 702M 10% /run
/dev/sda1 100G 60G 35G 64% /
tmpfs 3.8G 12M 3.8G 1% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 776M 12K 776M 1% /run/user/1000

2. Check Docker Disk Usage (docker system df)


docker system df
Shows how much disk space Docker is using.
Output:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 10 3 5.6GB 4.2GB (75%)
Containers 5 2 800MB 500MB (62%)
Local Volumes 8 6 3.1GB 1.2GB (39%)
Build Cache 15 0 7.5GB 7.5GB (100%)
3. Get Detailed Disk Usage (docker system df -v)
docker system df -v
Provides a more detailed breakdown.
Output:
Images space usage:
REPOSITORY TAG IMAGE ID SIZE CREATED CONTAINERS
nginx latest 5a3221f0137b 133MB 2 weeks ago 1
ubuntu 20.04 3f76fe9b07bc 72MB 1 month ago 0

Containers space usage:


CONTAINER ID IMAGE SIZE CREATED STATUS
f1a2b3c4d5e6 nginx 50MB 3 days ago Running
g6h7i8j9k0l1 ubuntu 750MB 2 weeks ago Exited

Local Volumes space usage:


VOLUME NAME SIZE
nginx_data 2.1GB
app_cache 980MB

netstat -ntlp Command in Docker & Linux


The netstat -ntlp command is used to list all active network connections and the
processes that are listening on ports. It is commonly used to check which ports are in
use, especially when working with Docker containers and network debugging.
Breaking Down the Command
netstat -ntlp
Option Meaning
-n Show numeric addresses (IP & port numbers instead of names)
-t Show TCP connections only (ignore UDP)
-l Show listening ports (ignores closed connections)
-p Show the process ID (PID) and name of the service using the port

Example: Checking Listening Ports on a System


Command:
netstat -ntlp
🔹 Output:
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program
name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 999/sshd
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 1234/mysqld
tcp6 0 0 :::80 :::* LISTEN 4567/nginx

3. Docker Networking
3.1 Docker Networking Basics
How Docker Manages Networking?
Docker provides a flexible networking model that allows containers to communicate with each other,
the host system, and the internet. By default, Docker creates different types of networks for various
use cases.

Types of Docker Networks


Docker provides the following built-in network types:
1. Bridge Network (Default)
o Created automatically when Docker is installed.
o Used when no specific network is assigned.
o Containers in the same bridge network can communicate via container ip.
o Cannot communicate with other bridge networks by default.
o Example:
docker network ls
NETWORK ID NAME DRIVER SCOPE
abc123def456 bridge bridge local
2. Host Network
o Removes network isolation and directly connects the container to the host’s network
stack.
o No separate IP is assigned to the container.
o Used for performance-sensitive applications.
o Example:
docker run --network host nginx
3. None Network
o Completely disables networking.
o Used when a container doesn’t need external communication.
o Example:
docker run --network none alpine
4. Overlay Network (Used in Swarm Mode)
o Allows communication between containers across multiple Docker hosts.
o Useful for distributed applications.
o Example:
docker network create -d overlay my-overlay
5. Macvlan Network
o Assigns a unique MAC address to each container, making it appear as a physical
device on the network.
o Used for low-level networking or legacy applications.
o Example:
docker network create -d macvlan --subnet=192.168.1.0/24 my-macvlan

Network Isolation in Docker


Each Docker container is isolated from other containers and the host unless explicitly configured. This
isolation helps in security and prevents unintended communication.

How Isolation Works?


 Each container gets its own network namespace, meaning it has its own IP, network
interfaces, and routing tables.
 Containers cannot access other containers’ networks unless connected to the same network.
 By default, containers on the bridge network can communicate only via container names or
exposed ports.

Testing Network Isolation


1. Creating Two Separate Containers Without a Shared Network
docker run -dit --name container1 ubuntu
docker run -dit --name container2 ubuntu
 Running ping container2 inside container1 will fail because they are not on the same
network.
2. Connecting Containers to the Same Bridge Network
docker network create my_bridge
docker run -dit --network my_bridge --name container1 ubuntu
docker run -dit --network my_bridge --name container2 ubuntu
 Running ping container2 inside container1 will succeed since they share the same network.

Container-to-Container Communication
Containers can communicate with each other using different networking approaches.

1. Communicating on the Same Bridge Network


 If two containers are on the same bridge network, they can talk to each other using
container names.
 Example:
docker network create my_bridge
docker run -dit --network my_bridge --name app_container ubuntu
docker run -dit --network my_bridge --name db_container ubuntu

Inside app_container, we can ping db_container:


ping db_container

2. Communicating Using Exposed Ports


 If containers are on different networks, they need to communicate using exposed ports.
 Example:
docker run -d --name myweb -p 8080:80 nginx
o The container runs a web server, and it is accessible on port 8080 of the host.

3. Using Docker Compose for Simplified Networking


Docker Compose automatically assigns containers to the same network and lets them communicate
using their service names. Example docker-compose.yml:
version: "3"
services:
web:
image: nginx
ports:
- "8080:80"
database:
image: mysql
environment:
MYSQL_ROOT_PASSWORD: root
 The web service can communicate with the database using database as the
hostname.

3.2 Types of Docker Networks


Docker provides various network modes that define how containers communicate with each other
and external systems. The main types of networks are:
1. Bridge Network (Default Network)
 A bridge network is the default network for Docker containers.
 Containers within the same bridge network can communicate with each other while being
isolated from the host and other networks.
 Uses NAT (Network Address Translation) for external communication.
 Containers in a user-defined bridge network can use container names for communication.
Example:
docker network create --driver bridge my_bridge
docker run -d --name web1 --network my_bridge nginx
docker run -d --name web2 --network my_bridge nginx
docker exec -it web1 ping web2

How Networking Works in Bridge Network


A bridge network is created by Docker by default using bridge driver. It allows containers to
communicate with each other within the same network while providing NAT-based isolation from the
host. Each bridge network has a CIDR range (Subnet). Within a bridge network, multiple containers
exist with separate ips and a Gateway interface with a Primary IP.

Containers IP vs. Gateway IP

 Each container gets an IP within the bridge network’s subnet.

 The bridge network has itself also a gateway IP to route traffic between containers. This ip is
also from the same subnet

Role of CIDR Block (Subnet) in Networking

The CIDR block (e.g., 192.168.1.0/24) defines the range of IPs available for the bridge network. The
container ip and bridge ip both come from this range

Checking IPs

 Machine IP: Run ifconfig or ip a


Output:
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.100 netmask 255.255.255.0 broadcast 192.168.1.255
inet6 fe80::1a2b:3c4d:5e6f:7g8h prefixlen 64 scopeid 0x20<link>
ether 00:1a:2b:3c:4d:5e txqueuelen 1000 (Ethernet)
RX packets 123456 bytes 987654321 (987.6 MB)
TX packets 654321 bytes 123456789 (123.4 MB)

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536


inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 10000 bytes 800000 (800 KB)
TX packets 10000 bytes 800000 (800 KB)

Explanation:
eth0: Primary network interface with IP 192.168.1.100. Generally the ip of interface of
Gateway
lo: Loopback interface (127.0.0.1).
RX/TX packets show data received/sent.

 Docker Network Details: docker network inspect bridge => It shows all the network
information, all the ips included and all the containers in the network.

 Container IP: docker container inspect <container-id> => In this we can see detail of specific
container, Hence also ip of that specific container and the network it belongs to.

User-defined Bridge Network vs. Default Bridge Network

 User-defined bridge networks allow automatic DNS-based container name resolution. So


instead of using ip of container, one container can directly connect to other container using
it’s name. It’s creation is shown in example section below.
 The default bridge network requires manual linking. (Legacy approach- Not used now)

Example:

Here’s a step-by-step example of how a Docker bridge network works, including commands and
expected outputs.

Step 1: Check Default Bridge Network


By default, Docker containers run in a bridge network unless specified otherwise.

Command:
docker network ls
Expected Output:
NETWORK ID NAME DRIVER SCOPE
abcdef123456 bridge bridge local
ghijkl789012 host host local
mnopqr345678 none null local
The bridge network is the default network for containers.

Step 2: Run a Container in the Default Bridge Network


Start two Nginx containers in the default bridge network.
Command:
docker run -d --name web1 nginx
docker run -d --name web2 nginx

Step 3: Inspect the Bridge Network


Find details of the default bridge network.
Command:
docker network inspect bridge
Expected Output (Truncated for Simplicity):
{
"Name": "bridge",
"Driver": "bridge",
"IPAM": {
"Config": [
{
"Subnet": "192.168.1.0/24",
"Gateway": "192.168.1.1"
}
]
},
"Containers": {
"container_id_1": {
"Name": "web1",
"IPv4Address": "192.168.1.2/24"
},
"container_id_2": {
"Name": "web2",
"IPv4Address": "192.168.1.3/24"
}
}
}
This shows that:
 The bridge network assigns IPs (192.168.1.2 and 192.168.1.3).
 The gateway for routing is 192.168.1.1.

Step 4: Check Container IPs


Command:
docker container inspect web1 | grep "IPAddress"
Expected Output:
"IPAddress": "192.168.1.2"

Step 5: Test Communication Between Containers


Since they are in the default bridge network, they cannot communicate by container name but can
use IP addresses.
Command (from web1 to web2 using IP):
docker exec -it web1 ping -c 3 192.168.1.3
Expected Output:
PING 192.168.1.3 (192.168.1.3): 56 data bytes
64 bytes from 192.168.1.3: icmp_seq=1 ttl=64 time=0.1 ms
64 bytes from 192.168.1.3: icmp_seq=2 ttl=64 time=0.1 ms
This confirms that web1 can communicate with web2 over the bridge network using IP.

Step 6: Create a User-Defined Bridge Network


A custom bridge network allows containers to communicate by name.
Command:
docker network create --driver bridge my_bridge
docker run -d --name web3 --network my_bridge nginx
docker run -d --name web4 --network my_bridge nginx

Step 7: Test Communication Using Container Names


Since they are in a user-defined bridge network, they can resolve each other’s names.
Command:
docker exec -it web3 ping -c 3 web4(We can directly ping using name of container in User-
Defined bridge)
Expected Output:
PING web4 (192.168.2.3): 56 data bytes
64 bytes from web4: icmp_seq=1 ttl=64 time=0.1 ms
64 bytes from web4: icmp_seq=2 ttl=64 time=0.1 ms
Now, web3 can reach web4 using its name instead of just its IP.

Key Differences Between Default and User-Defined Bridge Networks


Feature Default Bridge Network User-Defined Bridge Network
Container Name Resolution ❌ No ✅ Yes
Feature Default Bridge Network User-Defined Bridge Network
Custom IP Ranges ❌ No ✅ Yes
Security & Isolation 🔴 Limited 🟢 Better

2. Host Network
 Removes the network isolation of the container, making it use the host’s network stack
directly.
 The container does not get its own IP; it shares the host’s IP.
 Useful for performance optimization but eliminates container networking isolation.
Example:
docker run -d --name web_host --network host nginx
curl http://localhost

How Networking Works in Host Network

In host networking, the container directly uses the host machine’s network stack, bypassing Docker’s
bridge. So any container running in this network doesn’t need port binding. The host ip and port
become the container ip and port.

Use Case

Used when a container needs direct access to the host network, such as an antivirus container that
needs to monitor all traffic.

Checking IPs

 Machine IP: ifconfig

 Docker Network Details: docker network inspect host

 Container IP: Since it shares the host network, the container does not get a separate IP.

Example:

Here’s a step-by-step example of how a Docker host network works, including commands and
expected outputs.

Step 1: Check Available Networks


Docker provides a host network mode by default.
Command:
docker network ls
Expected Output:
NETWORK ID NAME DRIVER SCOPE
abcdef123456 bridge bridge local
ghijkl789012 host host local
mnopqr345678 none null local
 The host network exists by default and does not create a separate network for containers.

Step 2: Run a Container in the Host Network


Start an Nginx container using the host network.
Command:
docker run -d --name web_host --network host nginx
Here, the container directly shares the host’s networking stack.

Step 3: Inspect the Host Network


Since host networking does not create an isolated network, inspecting it does not show container-
specific IPs.
Command:
docker network inspect host
Expected Output (Truncated):
{
"Name": "host",
"Driver": "host",
"Containers": {}
}
 Unlike bridge networks, the host network does not list any containers.
 This is because containers using the host network share the host's IP and network stack
directly.

Step 4: Check Container IP


Since host mode shares the host’s network, the container does not have a separate IP.
Command:
docker container inspect web_host | grep "IPAddress"
Expected Output:
"IPAddress": ""
 The IP address is empty because it uses the host's IP.

Step 5: Test Access to the Container


On Host Machine
Since the container is running an Nginx server on port 80, we can access it using the host’s IP.
Command:
curl http://localhost
Expected Output:
<!DOCTYPE html>
<html>
<head><title>Welcome to nginx!</title></head>
<body>
<h1>Success! Nginx is running.</h1>
</body>
</html>
 The container is directly accessible on the host machine’s network.

Step 6: Compare with Bridge Network


If we had used the bridge network, we would have needed to expose ports manually using -p (e.g., -p
8080:80).
Bridge Mode Example:
docker run -d --name web_bridge -p 8080:80 nginx
Now, curl http://localhost:8080 would work, but in host mode, ports are directly accessible without
mapping.

Step 7: Use Cases for Host Network


Why Use Host Network?
 When low latency and direct network access are needed.
 Example Use Case: Running a network monitoring or antivirus container that needs full
network visibility.
Example: Running a Network Monitoring Tool
docker run -d --name sniffer --network host nicolaka/netshoot tcpdump -i eth0
This captures network traffic directly on the host interface.

Key Differences: Host Network vs. Bridge Network


Feature Host Network Bridge Network
Container Gets Separate IP? ❌ No (Uses Host's IP) ✅ Yes
Port Mapping Needed? ❌ No ✅ Yes (-p)
Performance 🟢 Fast (Direct Access) 🔴 Slight Overhead (NAT)
Use Case Network-heavy apps Standard container isolation

3. None Network
 Disables all networking for a container.
 The container only has a loopback interface.
 Used for highly restricted, isolated workloads.
Example:
docker run -d --name isolated_container --network none ubuntu sleep 1000
docker exec -it isolated_container ping google.com # Should fail
How It Works

A container with none network mode is fully isolated and does not have any network interfaces
except for the loopback interface.

Use Case

Useful for containers that should not have any network access, such as security-sensitive
applications.

Example:

Here’s a step-by-step example of how the Docker None network works, including commands,
outputs, and explanations.

Step 1: Check Available Networks


The none network is a built-in Docker network that provides full isolation—the container has no
network access.
Command:
docker network ls
Expected Output:
NETWORK ID NAME DRIVER SCOPE
abcdef123456 bridge bridge local
ghijkl789012 host host local
mnopqr345678 none null local
 The none network exists by default.

Step 2: Run a Container in the None Network


Start an Ubuntu container using the none network.
Command:
docker run -d --name isolated_container --network none ubuntu sleep 1000
 The container is running but has no network connectivity.
 It cannot access the internet or communicate with other containers.

Step 3: Inspect the None Network


Since none networking fully isolates the container, inspecting it does not show any connected
containers.
Command:
docker network inspect none
Expected Output:
{
"Name": "none",
"Driver": "null",
"Containers": {}
}
 No containers are listed because no communication is allowed.

Step 4: Check the Container's IP


Since the container is completely isolated, it does not get an IP address.
Command:
docker container inspect isolated_container | grep "IPAddress"
Expected Output:
"IPAddress": ""
 Unlike bridge or host networks, there is no IP address assigned.

Step 5: Verify No Network Access


We can confirm that the container has no networking capabilities.
Command:
docker exec -it isolated_container ping -c 3 google.com
Expected Output:
ping: google.com: Name or service not known
 The container cannot access the internet.

Step 6: Use Cases for None Network


Why Use None Network?
 When you need complete network isolation.
 For security-sensitive workloads where networking is not required.
 Running offline batch processing or data transformation tasks.
Example: Running an Offline Application
docker run -d --name secure_container --network none my_offline_app
 The application operates in isolation, preventing unauthorized network access.

4. Overlay Network
 Enables communication between containers across multiple Docker hosts in a Swarm cluster.
 Used in Docker Swarm or Kubernetes deployments.
 Provides secure, encrypted communication.
Example:
docker network create --driver overlay my_overlay

5. Macvlan Network
 Assigns each container a unique MAC address, making it appear as a physical device on the
network.
 Allows direct communication with other devices in the network.
Example:
docker network create -d macvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 my_macvlan
docker run -d --name mac_container --network my_macvlan nginx

6. IPvlan Network
 Assigns IP addresses directly from the physical network, similar to Macvlan but with lower
overhead.
 Provides better performance by reducing network translation layers.
Example:
docker network create -d ipvlan --subnet=192.168.1.0/24 --gateway=192.168.1.1 -o parent=eth0 my_ipvlan
docker run -d --name ipvlan_container --network my_ipvlan nginx

Key Differences Between Networks


Bridge Host None Overlay Macvlan
Feature IPvlan Network
Network Network Network Network Network
✅ Yes
Container Gets ❌ No (Uses ❌ No (No ✅ Yes (Multi-
✅ Yes (Unique ✅ Yes (Direct IP)
Separate IP? Host's IP) Networking) host)
MAC)
Can ✅ Yes
✅ Yes (if in the
Communicate (Shares ✅ Yes (Multi-
same ❌ No ✅ Yes ✅ Yes
with Other host host)
network)
Containers? network)
Internet Access? ✅ Yes ✅ Yes ❌ No ✅ Yes ✅ Yes ✅ Yes
Performance-
Standard Direct Host Swarm Physical
Use Case Full Isolation Optimized
Networking Access Networking Network
Networking
By understanding these network types and configurations, you can optimize Docker networking for
various use cases, from isolated workloads to highly interconnected microservices architectures.

3.3 Managing Docker Networks


Docker allows users to create, manage, and remove networks to control how containers
communicate.

Creating Networks
To create a new Docker network, use the docker network create command. This allows the creation
of custom bridge networks, overlay networks, and more.
Example: Creating a User-Defined Bridge Network
docker network create my_custom_bridge

Connecting Containers to a Network


A running container can be connected to an existing network using the docker network connect
command.
Example:
docker network connect my_custom_bridge my_container
Alternatively, specify the network when running a container:
docker run -d --name my_app --network my_custom_bridge nginx

Inspecting Networks
To get detailed information about a network, use docker network inspect.
Example:
docker network inspect my_custom_bridge (See what containers are part of this network,
what’s ip block of this network)

Removing Networks
Unused networks can be removed using docker network rm.
Example:
docker network rm my_custom_bridge

EXTRA NOTES:
-p vs -P Port Binding
Docker provides two options for exposing container ports to the host:
 -p <host_port>:<container_port> (explicit mapping): Maps a specific host port to a
container port.
 -P (automatic mapping): Randomly assigns available host ports to the container’s
exposed ports.
Example: Manual Port Mapping with -p
docker run -d -p 8080:80 nginx
To access the Nginx server, navigate to:
http://localhost:8080
This maps port 80 inside the container to port 8080 on the host.
Example: Random Port Mapping with -P
Step 1: Run a Container with -P
docker run -d --name web_random -P nginx
 The -P flag assigns a random available host port for each exposed port inside
the container.
 Since Nginx exposes port 80 by default, Docker will map it to a random host
port.

Step 2: Check Mapped Ports


docker ps
Expected Output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abc123456789 nginx "nginx -g …" 2 minutes ago Up 2 minutes 0.0.0.0:49153->80/tcp web_random
This means port 80 inside the container is mapped to port 49153 on the
host.

Step 3: Access the Container


curl http://localhost:49153

Step 4: Compare -P vs. -p


Feature -P (Random) -p (Manual)
Port Mapping Randomly assigns available host ports User-defined (e.g., -p 8080:80)
When to Use? When you don’t care about the specific port When a fixed port is needed
Example docker run -P nginx docker run -p 8080:80 nginx

Step 5: Check Assigned Ports via docker port


docker port web_random
Expected Output:
80/tcp -> 0.0.0.0:49153
This confirms that port 80 inside the container is mapped to 49153 on the
host.

3.4 Advanced Networking

Multi-Host Networking with Overlay Networks

Why Do We Need Multi-Host Networking?


By default, Docker containers communicate within the same host using bridge networks. However, in
distributed environments like Kubernetes or Docker Swarm, containers running on different hosts
need to communicate securely. Overlay networks provide a solution by creating a virtual network
across multiple hosts.

How Overlay Networks Work


 Overlay networks use VXLAN encapsulation to enable multi-host networking.
 They require Docker Swarm mode or manual setup with an external KV store (e.g., Consul,
etcd).
Example: Creating an Overlay Network
1. Initialize Docker Swarm:
docker swarm init
2. Create an Overlay Network:
docker network create -d overlay my_overlay_network
3. Deploy Services in Overlay Network:
docker service create --name web --network my_overlay_network -p 8080:80 nginx
4. Check the Network:
docker network ls
5. Inspect the Overlay Network:
docker network inspect my_overlay_network
Expected Output (Excerpt):
{
"Driver": "overlay",
"Scope": "swarm",
"Containers": {
"web": {
"IPv4Address": "10.0.0.2/24"
}
}
}
This means the web container is now part of the overlay network and can communicate any
container across nodes. Inspecting this network shows all containers which are part of it

DNS Resolution Inside Containers

Why DNS Resolution Matters?


When multiple containers communicate in a user-defined network, Docker provides automatic DNS
resolution, meaning containers can refer to each other using names instead of IPs.
Example: DNS Resolution in Docker
1. Create a User-Defined Network:
docker network create my_bridge
2. Run Containers in This Network:
docker run -d --name app --network my_bridge nginx
docker run -d --name db --network my_bridge mysql
3. Test Name Resolution:
docker exec -it app ping db

Expected Output:
PING db (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.064 ms
This shows that the container app can resolve db using the internal DNS.

Load Balancing in Docker Networks

Why Load Balancing is Important?


In microservices and distributed architectures, traffic must be evenly distributed among multiple
instances of a service. Docker Swarm provides built-in load balancing using its internal DNS and
routing mesh.
Example: Docker Swarm Load Balancing
1. Deploy Multiple Instances of a Service:
docker service create --name web --replicas 3 --network my_overlay_network -p 8080:80 nginx
2. Inspect Running Tasks:
docker service ps web
Expected Output:
ID NAME IMAGE NODE STATUS
xyz123 web.1 nginx node1 Running
abc456 web.2 nginx node2 Running
pqr789 web.3 nginx node3 Running
3. Access Load-Balanced Service:
curl http://localhost:8080 (Keep rerunning, This will hit different replicas in different runs)
This request will be automatically balanced across all web replicas.
By implementing overlay networks, DNS-based communication, and built-in load balancing, Docker
enables scalable, resilient container networking across distributed environments.

4. Docker Storage & Volumes


Docker provides multiple storage options for handling persistent and temporary data in containers.
Since containers are ephemeral by design, without proper storage, any data inside them is lost when
they stop or restart. Docker offers Volumes, Bind Mounts, and tmpfs to address different storage
needs. But before diving into volumes, Let’s look into Dockers own storage system

4.1 Understanding Docker Storage Drivers


Storage drivers are the core mechanism that allows Docker to manage and store container data
efficiently. They integrate all the layers of a Docker image, manage file system changes, and provide
Copy-on-Write (CoW) functionality to optimize storage use.

1. Task and Importance of Storage Drivers


What Does a Storage Driver Do?
 It assembles the layers of a Docker image into a unified file system for the running
container.
 It manages file system changes inside a container.
 It provides Copy-on-Write (CoW) to optimize space and prevent data duplication.
 It determines how data is stored persistently or temporarily.

Why Are Storage Drivers Important?


✔ Efficient Storage Usage – Prevents duplicate storage of unchanged files.
✔ Faster Container Startup – Allows reusing common layers across multiple containers.
✔ Isolation & Layered Structure – Each container runs in an isolated file system.
✔ Snapshot and Rollback Support – Allows reverting changes quickly.

2. How Storage Drivers Assemble Image Layers into a Container


When you pull a Docker image, it is made up of multiple read-only layers stored by Docker. Each layer
represents changes made to the image at different stages.

How It Works Internally


1. Docker Image Layers
o An image consists of multiple read-only layers stacked together.
o Each layer is created from the Dockerfile during the build process.
o Example:
FROM ubuntu
RUN apt-get install nginx
COPY index.html /var/www/html/
 Ubuntu Base Image (Layer 1)
 Installed Packages (Layer 2)
 Copied Files (Layer 3)
2. Creating a Writable Container Layer
o When you run a container, Docker adds a thin, writable layer on top of the read-only
layers.
o All file changes in the container occur in this writable layer.
o The writable layer disappears when the container is removed.
3. Union File System
o Docker storage drivers merge all the layers into a single unified file system.
o This allows the container to see it as a single directory structure.

3. Copy-on-Write (CoW) Strategy


Docker uses Copy-on-Write (CoW) to optimize how files are stored and modified.

How CoW Works:


 Instead of creating duplicate files for each container, Docker shares common files across
multiple containers.
 If a container modifies a file from a lower read-only layer, Docker:
1. Copies the file from the read-only layer to the writable layer.
2. The container now operates on the copied file, leaving the original intact.
3. Other containers using the same base layers remain unaffected.

Example of CoW in Action


1. Run an Ubuntu Container:
docker run -it ubuntu bash
2. Check the File System Layers:
ls /var/lib/docker/overlay2
This shows the underlying image and container layers.
3. Modify a File Inside the Container:
echo "Hello, Docker" > /etc/hello.txt
4. Check File Changes in Storage Layer:
ls /var/lib/docker/overlay2/<container-id>/diff/etc/
o The modified file now exists in the container’s writable layer.
o The original image file remains unchanged.

4. Checking Storage Driver in Docker


You can check which storage driver is currently being used with:
docker info | grep "Storage Driver"
Example Output:
Storage Driver: overlay2
This means OverlayFS (overlay2) is being used.

5. Common Storage Drivers and Their Use Cases


(A) OverlayFS (overlay2) [Default]
✔ Best for modern Linux kernels (>=4.x)
✔ Uses Copy-on-Write for efficiency
✔ Fast performance and low overhead
✔ Preferred choice for most production setups
Example:
docker run -d --storage-driver overlay2 nginx

(B) AUFS (Advanced Multi-Layered File System)


✔ Used in older Linux distributions.
✔ Supports layered storage.
✔ Deprecated in newer Docker versions.
Example:
docker run --storage-driver aufs -d nginx
(C) Btrfs (B-Tree File System)
✔ Built-in snapshot support.
✔ Works well with high-performance storage solutions.
✔ Requires Btrfs filesystem on the host.
Example:
docker run --storage-driver btrfs -d nginx
(D) ZFS (Zettabyte File System)
✔ Advanced filesystem with deduplication.
✔ Best for enterprise storage.
✔ Requires ZFS support on the host.
Example:
docker run --storage-driver zfs -d nginx
(E) Device Mapper
✔ Uses block-level storage.
✔ Best for RedHat-based systems.
✔ Requires manual configuration.
Example:
docker run --storage-driver devicemapper -d nginx

6. Block vs Object Storage


Storage plays a crucial role in managing data efficiently. Two of the most common types of
storage used in cloud and containerized environments are Block Storage and Object Storage.
Let’s break them down in detail.

1. What is Block Storage?


Block storage is a low-level, high-performance storage system where data is split into fixed-
size blocks and stored across a storage system. Each block has a unique address, but unlike
files, block storage does not include metadata about the stored data.

How Block Storage Works


 Data is broken into blocks (e.g., 4KB, 8KB chunks).
 Each block is assigned a unique ID.
 The blocks are stored in a distributed manner across storage devices.
 When a request is made, the system assembles the required blocks to provide the
complete data.
Example of Block Storage
Imagine a database storing customer records:
 Each customer record is divided into small blocks and stored across different drives.
 When querying a record, the system fetches and assembles the blocks.

Features of Block Storage


✅ Fast & Efficient – Best for high-speed transactions like databases.
✅ Low Latency – Direct access to blocks ensures fast read/write.
✅ Used for Persistent Data – Commonly used for OS disks, databases, and VM storage.
✅ Supports Mounting – Block storage volumes can be attached to servers like local disks.
Examples of Block Storage Services
 AWS Elastic Block Store (EBS)
 Google Persistent Disk (PD)
 Azure Managed Disks
 SAN (Storage Area Networks)

2. What is Object Storage?


Object storage manages data as objects instead of blocks or files. Each object consists of:
 Data (the actual file or content)
 Metadata (key-value pairs describing the object)
 Unique Identifier (object ID for retrieval)
Object storage is commonly used for large-scale unstructured data, such as media files,
backups, and logs.

How Object Storage Works


 Data is stored in objects inside a flat storage system (no hierarchical file system).
 Objects are retrieved via APIs (HTTP, S3 protocol) instead of file paths.
 Objects are stored redundantly across multiple locations for durability.
Example of Object Storage
Imagine storing images in a cloud storage system:
 Each image is stored as an object with metadata (e.g., "file_name: image1.jpg",
"size: 5MB", "created_at: 2024-03-26").
 When requested, the object is retrieved using an API call (GET request) instead
of using file paths.

Features of Object Storage


✅ Scalable – Can store petabytes of data across multiple data centers.
✅ Durable & Redundant – Replicates data across multiple locations.
✅ Cost-Effective for Archival – Great for backups, logs, and media content.
✅ Accessed via APIs – HTTP-based access instead of mounting as a disk.
Examples of Object Storage Services
 AWS S3 (Simple Storage Service)
 Google Cloud Storage (GCS)
 Azure Blob Storage
 Ceph, MinIO (self-hosted object storage)

3. Key Differences: Block Storage vs. Object Storage


Feature Block Storage Object Storage 📦
Stores data in small blocks with unique Stores entire files as objects with
Data Structure
addresses metadata
Access Method Directly mounted on OS as a virtual disk Accessed via API (HTTP, S3 protocol)
Performance Low latency, high speed Higher latency (not real-time)
Scales up to limited sizes (e.g., 16TB per EBS
Scalability Virtually unlimited scalability
volume)
Typically single-location storage (unless
Durability Highly redundant across data centers
replicated)
Databases, Virtual Machines, Operating
Best For Backup, Media Files, Logs, Big Data
System Disks
Example AWS S3, Google Cloud Storage, Azure
AWS EBS, Azure Managed Disks, Google PD
Services Blob

4. When to Use Block Storage vs. Object Storage?


✅ Use Block Storage for:
 Databases (MySQL, PostgreSQL)
 Virtual Machine Disks (VMs, Kubernetes persistent storage)
 High-performance applications (low latency required)
✅ Use Object Storage for:
 Storing backups & logs
 Storing media files (videos, images, PDFs, etc.)
 Big data analytics (Hadoop, AI/ML models)
 Cloud-based static website hosting

5. Combining Block & Object Storage in Docker


 Docker Containers Use Block Storage for Persistent Volumes
o Example: Mounting an EBS Volume to a container
docker run -d --name my_app -v /mnt/ebs:/app/data nginx

 Object Storage is Used for Backups & Media Storage


o Example: Uploading logs to S3
aws s3 cp /var/logs/myapp.log s3://mybucket/logs/

7. Check Current Storage Driver


docker info | grep Storage
Expected Output
Storage Driver: overlay2

8. Logging Drivers in Docker


Docker provides logging drivers to control how and where container logs are stored. By default,
Docker uses the json-file logging driver, but other options allow for better integration with
centralized logging systems.
Types of Logging Drivers
Logging Driver Description
json-file (Default) Stores logs as JSON files on the host system.
local Stores logs in an efficient binary format to reduce disk space usage.
syslog Sends logs to the system's syslog daemon.
journald Sends logs to systemd-journald.
fluentd Integrates with Fluentd for centralized logging.
gelf Sends logs to Graylog Extended Log Format (GELF)-compatible servers.
awslogs Sends logs to AWS CloudWatch.
splunk Sends logs to Splunk.
etwlogs Logs to Event Tracing for Windows (ETW).
none Disables logging.
Example: Configuring a Logging Driver
Run a container with Fluentd logging:
docker run -d --log-driver=fluentd --log-opt fluentd-address=localhost:24224 nginx

Checking Logs of a Container


docker logs my_container

9. Device Mapper Storage Driver


Device Mapper is a Docker storage driver that manages storage at the block level rather than
at the file system level. It is an older driver but still used in some environments.

How Device Mapper Works


 It uses thin provisioning to allocate storage dynamically.
 Each Docker image and container gets a separate snapshot layer.
 It creates virtual block devices mapped to physical storage.
Example: Check Storage Driver
Run the following command to check the current storage driver:
docker info | grep "Storage Driver"
Output (if Device Mapper is used):
Storage Driver: devicemapper

Disadvantages of Device Mapper (So not used anymore)


❌ Slow performance compared to newer drivers like OverlayFS.
❌ High disk space usage due to snapshot layers. (But Overlay uses COW)
❌ Deprecated for production environments in favor of Overlay2.

9. Changing the Storage Driver (Impact & Considerations)


Steps to Change Storage Driver
1️ Stop Docker Service
sudo systemctl stop docker
2️ Edit daemon.json
Modify the storage driver in /etc/docker/daemon.json:
{
"storage-driver": "overlay2"
}
3️ Delete Old Data (⚠️Destroys All Containers & Images!)
sudo rm -rf /var/lib/docker
4️ Restart Docker
sudo systemctl start docker
5️ Verify the New Storage Driver
docker info | grep "Storage Driver"

Impact of Changing the Storage Driver


⚠️All existing containers & images will be lost since /var/lib/docker is deleted.
⚠️Ensure you migrate important volumes before switching.
⚠️New storage driver improves performance but requires re-downloading images.

10. Why Write Data in Volumes Instead of the Storage Driver?


Issue 1: Persistence Problem in Container Writable Layer
Container writable layers are ephemeral—data is lost when the container is
removed.
✅ Solution: Use Docker Volumes (-v my_volume:/data) for persistent storage.
Example: Data Lost in Writable Layer
docker run -d --name temp_container nginx
docker exec -it temp_container sh
echo "Hello" > /usr/share/nginx/html/index.html
exit
docker stop temp_container
docker rm temp_container
docker run -d --name new_container nginx
💥 The file is lost because it was inside the container’s writable layer.
Example: Persisting Data with Volumes
docker run -d --name persistent_container -v my_volume:/usr/share/nginx/html nginx
docker exec -it persistent_container sh
echo "Hello" > /usr/share/nginx/html/index.html
exit
docker stop persistent_container
docker rm persistent_container
docker run -d --name new_persistent_container -v my_volume:/usr/share/nginx/html nginx
🎉 The file persists because it was stored in a volume.

Issue 2: Performance Bottlenecks in Writable Layer


 File writes to the container layer are slow due to Copy-on-Write (CoW).
 Using volumes improves I/O performance because data is written directly to
disk.
Example: Performance Difference
✅ Fast Volume Storage
docker run -d --name fast_container -v /myhostdata:/data busybox
time docker exec fast_container sh -c "dd if=/dev/zero of=/data/test bs=1M count=100"

🚫 Slow Writable Layer Storage


docker run -d --name slow_container busybox
time docker exec slow_container sh -c "dd if=/dev/zero of=/test bs=1M count=100"
📊 Result: Writing to a volume (/data) is significantly faster than writing to the container
layer (/test).

4.2 Volumes (Recommended for Persistent Storage)


Above we saw why we need volumes for persisting the data. There are 2 ways to persist data of
containers. 1. Docker Volume 2. Bind Mount

1. Docker Volume
Why use Docker Volumes?
 Managed by Docker (safe, portable).
 Persists
 Works across multiple containers.
 Best for databases, logs, and application data.

Example: Create & Use a Volume


docker volume create my_volume
docker run -d --name my_container -v my_volume:/app/data nginx

 my_volume (Host Side): A Docker-managed volume stored in


/var/lib/docker/volumes/my_volume/_data on the host.
 /app/data (Container Side): The mount point inside the container where the volume
is attached.

Check Volumes
docker volume ls
Expected Output
DRIVER VOLUME NAME
local my_volume

Inspect Volume
docker volume inspect my_volume
Expected Output
[
{
"Name": "my_volume",
"Mountpoint": "/var/lib/docker/volumes/my_volume/_data",
"Driver": "local",
"CreatedAt": "2025-03-26T10:00:00Z"
}
]
Note: As Volumes are managed by docker, hence they are in Docker Area of Host File system,
Unlike Bind mounts which can be at any location in host file system.

2. Bind Mounts (Direct Mapping to Host Filesystem)


Why use Bind Mounts?
 Directly maps a host directory to a container.
 Useful for development (editing files inside/outside the container).
 Less portable, as it depends on the host filesystem.
 Not managed by docker. It is not docker volume but simple memory location in host file
system

Example: Bind Mount a Directory


docker run -d --name my_bind_container -v /home/user/data:/app/data nginx
 Host Path: /home/user/data → This is the directory on the host machine.
 Container Path: /app/data → This is where the host directory is mounted
inside the container.

Check Mounted Data


docker inspect my_bind_container | grep Mounts -A 5
Expected Output
"Mounts": [
{
"Type": "bind",
"Source": "/home/user/data",
"Destination": "/app/data"
}
]

3. tmpfs (In-Memory Storage, Lost on Restart)


Why use tmpfs?
 Fastest storage (stored in RAM).
 Data is automatically erased when the container stops.
 Ideal for caching, temporary files, sensitive data.

Example: Use tmpfs in a Container


docker run -d --name my_tmpfs_container --tmpfs /app/tmpfs nginx
 Container Path: /app/tmpfs → This is the location inside the container where the tmpfs mount is created.
 Host Path: There is no host path. tmpfs storage exists only in memory (RAM) and is not backed by the host
filesystem.

Check tmpfs Mount


docker inspect my_tmpfs_container | grep Mounts -A 5
Expected Output
"Mounts": [
{
"Type": "tmpfs",
"Destination": "/app/tmpfs"
}
]

Difference Between Volumes, Bind Mounts, and Tmpfs


Storage Managed by
Persistent Location Use Case
Type Docker?
Persistent storage for
Volumes ✅ Yes /var/lib/docker/volumes/ ✅ Yes
databases, logs, app data
Storage Managed by
Persistent Location Use Case
Type Docker?
Bind Sharing host files with
✅ Yes Any directory on the host ❌ No
Mounts containers, development
❌ No Temporary storage, caching,
tmpfs Stored in RAM ❌ No
(Temporary) sensitive data

4.3 Types of Docker Volumes


1. Bind Mounts (Mounting Host Directories)
 Mounts a specific host directory into a container.
 Example:
 docker run -d -v /host/path:/container/path nginx
 Use Case: Development (modify code without rebuilding the container).

2. Named Volumes (Managed by Docker)


 Created & managed by Docker.
 Example:
 docker run -d -v my_named_volume:/app/data nginx
 Use Case: Databases, persistent storage.

3. Anonymous Volumes (Temporary Volumes)


 Docker creates a random volume name.
 Example:
 docker run -d -v /app/data nginx
 Use Case: Temporary storage (deleted when the container is removed).

4.4 Managing Volumes


1. Creating a Volume
docker volume create my_volume
Output
my_volume

2. Attaching a Volume to a Container


docker run -d -v my_volume:/app/data nginx
Verify Volume Inside Container
docker exec -it my_container ls /app/data

3. Listing Volumes
docker volume ls
Output
DRIVER VOLUME NAME
local my_volume

4. Inspecting Volumes
docker volume inspect my_volume
Output
[
{
"Name": "my_volume",
"Mountpoint": "/var/lib/docker/volumes/my_volume/_data"
}
]

5. Removing Volumes
docker volume rm my_volume
Output
my_volume

6. Automatically removing the volume on deletion of container

By default, Docker does not remove volumes when a container is deleted, even if the container is
removed using docker rm. This is to prevent data loss. However, you can automatically remove the
associated volume when a container is removed using anonymous volumes and the --rm or --
volumes flag.

6.1. Using --rm for Temporary Containers while starting container(Does Not Work for Named
Volumes)
docker run --rm -v /app/data nginx
🔹 The container and its anonymous volume will be removed as soon as it stops.
❗ Limitation: This does not work with named volumes.

6.2. Using rm -v while removing container (Only for Anonymous Volumes)


docker run -d --name temp_container -v /app/data nginx
docker rm -v temp_container
🔹 This removes the container and any anonymous volumes attached to it.
❗ Named volumes will not be deleted using this method.

6.3. Automatically Removing Named Volumes (--mount + --rm)


To remove both the container and the named volume, you must use a different approach,
because --rm does not work with named volumes.
docker volume create my_volume
docker run --rm --mount source=my_volume,target=/app/data nginx
🔹 This method ensures that when the container stops, its mount is released, but the
volume still exists.
❗ Named volumes must be manually deleted using docker volume rm my_volume

6.4. Automatically Removing Named Volumes on Container Deletion (docker rm -v)


If you use a named volume in a container:
docker run -d --name my_container -v my_volume:/app/data nginx
Then remove the container along with its named volume:
docker rm -v my_container
🔹 This will remove both the container and the attached named volume.
6.5. Using Docker Compose to Remove Volumes Automatically
If you are using Docker Compose, you can remove volumes automatically with:
docker-compose down -v
🔹 This will remove containers, networks, and volumes defined in docker-compose.yml.

5. Dockerfile Instructions & Image Optimization


A Dockerfile is a script containing a set of instructions to automate the creation of Docker images.
Properly structuring and optimizing a Dockerfile can reduce image size, improve performance, and
speed up builds.

5.1 Essential Dockerfile Instructions

FROM – Base Image


Every Dockerfile starts with a FROM instruction, which defines the base image.
FROM ubuntu:20.04
🔹 This sets the image to use Ubuntu 20.04 as the base.
🔹 If version not mentioned, takes latest version which makes docker file unexpected

RUN – Executes Commands at Build Time


Used to install software, update packages, or configure the system inside the image.
RUN apt update && apt install -y nginx
🔹 Runs at build time, adding layers to the image.

CMD – Default Command at Runtime


Defines the default command executed when a container runs.
CMD ["nginx", "-g", "daemon off;"]
🔹 Can be overridden when running the container.

ENTRYPOINT – More Strict Default Command


Sets the main command that cannot be easily overridden.
ENTRYPOINT ["nginx"]
🔹 If overridden, it replaces only the arguments, not the command.

🛠 Difference Between CMD & ENTRYPOINT


CMD ["echo", "Hello"]
ENTRYPOINT ["echo", "Hello"]
docker run myimage World
 CMD Output → World
 ENTRYPOINT Output → Hello World (CMD is replaced, but ENTRYPOINT appends)

5.2 Copying Files and Setting Working Directory

COPY – Copy Files from Host to Image


COPY myfile.txt /app/myfile.txt
🔹 Copies myfile.txt from the host system to /app/ inside the container.
ADD – Like COPY, but Also Supports Archives & URLs
ADD archive.tar.gz /app/
🔹 Extracts archive.tar.gz inside /app/.
🚨 Best Practice: Prefer COPY unless you need archive extraction.

WORKDIR – Sets Default Working Directory


WORKDIR /app
🔹 Instead of RUN cd /app, it sets /app as the default directory.

5.3 Configuring Environment Variables & Metadata

ENV – Set Environment Variables


ENV APP_ENV=production
🔹 Used for configuring applications.

ARG – Build-Time Variables


ARG VERSION=1.0
RUN echo "Building version $VERSION"
🔹 Unlike ENV, ARG cannot be accessed at runtime.

LABEL – Metadata for Images


LABEL maintainer="Pranay Mohan" version="1.0"
🔹 Adds metadata (not functional, but useful for organization).

5.4 Exposing Ports & Storage Management


EXPOSE – Informative Port Exposure
EXPOSE 80
🔹 This does not publish the port; it’s just documentation.
🔹 To expose it:
docker run -p 8080:80 myimage

VOLUME – Persistent Storage


VOLUME /app/data
🔹 Mounts /app/data as a persistent volume in default docker volume.
🚨 Why Use Volumes?
1. Data Persistence (prevents data loss when a container stops)
2. Better Performance (separates storage from container layers)

5.5 Health Checking & User Management

HEALTHCHECK – Container Health Monitoring


HEALTHCHECK --interval=30s --timeout=5s \
CMD curl -f http://localhost || exit 1
🔹 Checks every 30s; if curl fails, Docker marks it unhealthy.
USER – Run as a Non-Root User
RUN useradd -m myuser
USER myuser
🔹 Enhances security by running containers as a non-root user.

5.6 Optimizing Docker Images


ONBUILD – Trigger Actions in Derived Images
ONBUILD COPY . /app
🔹 Executes only when another Dockerfile extends this image.

Tagging Docker Images


docker build -t myapp:v1 .
docker tag myapp:v1 myrepo/myapp:v1
🔹 Helps version control.

Docker Commit
docker commit my_container my_new_image
🔹 Saves live container changes to an image (not best practice for reproducibility).

Prune vs. Prune -a


docker system prune # Removes unused containers & networks
docker system prune -a # Removes unused images too

Flattening Docker Images


docker export my_container | docker import - my_flat_image
🔹 Removes intermediate layers, reducing image size.

5.7 Using Multi-Stage Builds (Best Practice)


Why Multi-Stage Builds?
 Reduces image size by removing build dependencies
 Keeps final image clean & minimal
 Speeds up deployment

Example:
# Stage 1: Build
FROM golang:1.20 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# Stage 2: Runtime
FROM alpine:latest
COPY --from=builder /app/myapp /usr/local/bin/myapp
ENTRYPOINT ["myapp"]
🔹 This results in a smaller image by keeping only the built binary.

🛠 Best Practices for Optimizing Dockerfiles


✔ Minimize layers (RUN apt update && apt install -y nginx && rm -rf /var/lib/apt/lists/*)
✔ Use .dockerignore to exclude unnecessary files
✔ Prefer COPY over ADD unless archive extraction is needed
✔ Use multi-stage builds to reduce final image size
✔ Run as a non-root user for better security
✔ Leverage VOLUME instead of writing to the container filesystem

6. Docker Compose
6.1 Introduction to Docker Compose
Docker Compose is a tool for defining and running multi-container(different apps) Docker
applications in one machine. It uses a YAML file to configure the application's services, networks, and
volumes, making it easier to manage and deploy complex environments.

🔹 Why Use Docker Compose?


1️ Managing Multi-Container Applications
Imagine a web application that consists of:
 A frontend (React, Angular, Vue)
 A backend (Node.js, Python, Java, etc.)
 A database (MySQL, PostgreSQL, MongoDB)
Manually running each container with docker run is tedious. Docker Compose automates this
process.
💡 Example Without Compose (Manually Running Containers)
# Run a MySQL container
docker run -d --name mysql-db -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 mysql

# Run the backend container


docker run -d --name backend-app --link mysql-db -p 5000:5000 my-backend-image

# Run the frontend container


docker run -d --name frontend-app --link backend-app -p 3000:3000 my-frontend-image

⚠ Problems with this approach


✔ Too many commands
✔ Hard to manage dependencies
✔ Difficult to share with teams

2️ Simplifying Multi-Container Setup with Compose


With Docker Compose, all of this can be done using one file and a single command.
💡 Example Using Compose (docker-compose.yml)
version: "3.8"

services:
db:
image: mysql:latest
container_name: mysql-db
environment:
MYSQL_ROOT_PASSWORD: root
ports:
- "3306:3306"

backend:
image: my-backend-image
container_name: backend-app
depends_on:
- db
ports:
- "5000:5000"

frontend:
image: my-frontend-image
container_name: frontend-app
depends_on:
- backend
ports:
- "3000:3000"

✅ Benefits of Using Compose


✔ One Command to Start Everything (docker-compose up -d)
✔ Easier Networking (Services can talk to each other by name)
✔ Dependency Management (Ensures correct startup order)
✔ Easier to Maintain and Share

🔹 Installing Docker Compose


1️ Check if Docker Compose is Installed
docker-compose --version
🔹 If it’s installed, you will see an output like:
Docker Compose version v2.17.3

2️ Installing Docker Compose (Linux, macOS, Windows)


📌 Linux Installation
1. Download and install Docker Compose:
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-
compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
2. Give execution permissions:
sudo chmod +x /usr/local/bin/docker-compose
3. Verify installation:
docker-compose --version
📌 Windows Installation
 Docker Compose comes pre-installed with Docker Desktop.
 Open PowerShell and verify:
docker-compose --version
🔹 If not installed, download from Docker Compose Releases.
📌 macOS Installation
 If using Docker Desktop, it comes pre-installed.
 Otherwise, install via Homebrew:
brew install docker-compose

🔹 Running a Docker Compose File


1️Start Services
docker-compose up -d
🔹 -d runs in detached mode (background).
2️ Check Running Containers
docker ps
3️ Stop Services
docker-compose down
4️ Restart Services
docker-compose restart

6.2 Writing a Docker Compose File


Docker Compose simplifies the management of multi-container applications by allowing you to
define everything in a single docker-compose.yml file.

🔹 Understanding docker-compose.yml
A docker-compose.yml file is a configuration file written in YAML format that defines:
✔️Services (containers)
✔️Networks
✔️Volumes
✔️Environment variables
✔️Restart policies
✔️Dependencies between services

🔸 Basic Structure of docker-compose.yml


version: "3.8" # Defines the Docker Compose version
services:
service_name: # Define a service (container)
image: image_name # The Docker image to use
build: . # Build from a Dockerfile in the current directory
ports:
- "host_port:container_port" # Port mapping
environment:
- VARIABLE_NAME=value # Define environment variables
volumes:
- volume_name:/container/path # Attach a volume
networks:
- network_name # Attach the container to a network
volumes:
volume_name: # Define a named volume
networks:
network_name: # Define a custom network
🔹 Configuring Services in Docker Compose
Each service represents a container in your application. Let’s go deeper into configuring
services.
Example: A Web App with Database

version: "3.8"

services:
web:
image: nginx:latest
ports:
- "8080:80"
depends_on:
- db # Web service depends on the database
restart: always
networks:
- my_network

db:
image: postgres:latest
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- db_data:/var/lib/postgresql/data
networks:
- my_network

volumes:
db_data:

networks:
my_network:
✅ What Happens Here?
 depends_on: Ensures db starts before web, but it does NOT wait for the DB to be
ready.
 restart: always: Ensures the container restarts automatically if it crashes.
 Networking: Both containers communicate via my_network (instead of exposing
ports to the host (By default, Bridge network).
 Volume db_data stores the database’s persistent data.

🔹 depends_on (Service Dependencies)


depends_on helps order service startup but does NOT guarantee a service is ready before
another starts.

Example:
services:
app:
image: my-app
depends_on:
- db # Ensures db service starts before app

db:
image: mysql:latest

⚠ Limitation: depends_on does not wait for the database to be fully initialized. To ensure
readiness, use a health check.
Solution: Using healthcheck for Readiness
services:
app:
image: my-app
depends_on:
db:
condition: service_healthy # Waits for db health check to pass
db:
image: mysql:latest
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
retries: 5
start_period: 30s
✅ Now, app will wait until db is actually ready!

🔹 Restart Policies (restart:)


The restart option defines how a container should restart if it stops or crashes.
Policy Behavior
no Default, container never restarts
always Always restarts, even if stopped manually
unless-stopped Restarts unless explicitly stopped
on-failure Restarts only if the container exits with an error
Example:
restart: always
✅ Best Practice: Use unless-stopped in development to prevent manual stops from being
undone.

🔹 Using Environment Variables in Docker Compose


You can define environment variables in two ways:
1. Directly in docker-compose.yml
2. Using an .env file

1️ Direct Definition in docker-compose.yml


services:
app:
image: my-app
environment:
- APP_ENV=production
- DB_HOST=db
- DB_USER=root
- DB_PASSWORD=secret
2️ Using an .env File (Recommended)
Create a .env file:
APP_ENV=production
DB_HOST=db
DB_USER=root
DB_PASSWORD=secret
Then, reference it in docker-compose.yml:
services:
app:
image: my-app
env_file:
- .env
✅ Why Use .env?
✔️Keeps secrets out of docker-compose.yml
✔️Allows different environments (dev, prod, staging)

🔹 Attaching Volumes
Volumes persist data even when a container is removed.
1️ Named Volumes (Preferred)
Docker manages these volumes.
services:
db:
image: postgres:latest
volumes:
- db_data:/var/lib/postgresql/data

volumes:
db_data: # Declare the named volume
🟢 Data remains even after docker-compose down.

2️ Bind Mounts (Host Path)


Mounts a host directory to a container path.
services:
app:
image: my-app
volumes:
- ./data:/app/data
🟡 Use when you need access to host files (e.g., local development).

3️ Anonymous Volumes (Temporary)


services:
app:
image: my-app
volumes:
- /app/tmp
🛑 Data is lost when the container is removed.

🔹 Attaching Networks
By default, Docker Compose creates a default network for all services to communicate.
1️ Default Bridge Network
networks:
my_network:
driver: bridge

services:
app:
image: my-app
networks:
- my_network
db:
image: postgres
networks:
- my_network
✔️Containers in the same network can talk using service names.
✔️app can reach db using db:5432.

2️ Custom Overlay Network (For Multi-Host Swarm Mode)


networks:
my_overlay:
driver: overlay

services:
backend:
image: my-backend
networks:
- my_overlay
✔️Used in Swarm Mode to connect services across multiple hosts.

🔹 Running & Managing a Docker Compose Setup


Start Containers
docker-compose up -d
🚀 Starts all services in detached mode.

Stop Containers
docker-compose down
🚀 Stops and removes all services.

Check Running Containers


docker-compose ps

View Logs
docker-compose logs -f
Rebuild After Code Changes
docker-compose up -d --build

6.3 Docker Compose Commands


Docker Compose provides a set of commands to manage multi-container applications efficiently.
Here’s a complete guide to the most important commands with explanations, examples, and
expected outputs.

🔹 1. Starting and Stopping Containers

🚀 docker-compose up -d (Start Services in Detached Mode)

This command starts all services defined in docker-compose.yml.


docker-compose up -d
Options:
 -d → Runs containers in the background (detached mode).
 --build → Rebuilds the images before starting.

Example Output:
Creating network my_app_default ... done
Creating volume my_app_data ... done
Creating my_app_db ... done
Creating my_app_web ... done
✅ Use case: Start the whole multi-container application in the background.

🛑 docker-compose down (Stop and Remove Everything)

Stops and removes all containers, networks, and volumes.


docker-compose down
Options:
 --volumes → Removes all named volumes.
 --remove-orphans → Removes any containers not defined in docker-compose.yml.

Example Output:
Stopping my_app_web ... done
Stopping my_app_db ... done
Removing my_app_web ... done
Removing my_app_db ... done
Removing network my_app_default
✅ Use case: Clean up the environment after development or testing.

🔹 2. Checking Logs
📜 docker-compose logs (View Container Logs)
Fetches logs for all containers.
docker-compose logs
Options:
 -f → Follows logs in real time (like tail -f).
 --tail=50 → Shows the last 50 log lines.
Example Output:
web | Starting Nginx...
db | Database initialized.
✅ Use case: Debugging application behavior.

🔹 3. Validating and Troubleshooting


✅ docker-compose config (Validate docker-compose.yml)

Checks the syntax and structure of docker-compose.yml.


docker-compose config
Expected Output:
version: "3.8"
services:
web:
image: nginx
ports:
- "8080:80"
✅ Use case: Ensure there are no syntax errors before running docker-compose up.

🔹 4. Managing Services
🚀 docker-compose restart (Restart Containers)

Restarts all containers in the stack.


docker-compose restart
✅ Use case: Apply configuration changes without stopping everything.

🔄 docker-compose stop (Stop Containers Without Removing Them)

Stops running containers but does not remove them.


docker-compose stop
✅ Use case: Temporarily stop containers while keeping data intact.

docker-compose start (Start Stopped Containers)

Starts containers that were stopped with docker-compose stop.


docker-compose start
✅ Use case: Resume work without recreating containers.

🔥 docker-compose rm (Remove Stopped Containers)

Deletes stopped containers but not volumes.


docker-compose rm
Options:
 -f → Force removal.
 -v → Remove associated volumes.
✅ Use case: Clean up unused containers after stopping them.

🔹 5. Managing Volumes and Networks


docker-compose volume ls (List Volumes)

Shows all volumes created by Docker Compose.


docker volume ls
✅ Use case: Check persistent storage.

🌐 docker-compose network ls (List Networks)

Displays all networks used by Docker Compose.


docker network ls
✅ Use case: Inspect how services communicate.

🔹 6. Checking Running Containers

📌 docker-compose ps (List Running Containers)


Shows running services.
docker-compose ps

Example Output:
Name Command State Ports
-------------------------------------------------------------
my_app_web "nginx -g daemon off;" Up 80/tcp
my_app_db "docker-entrypoint.sh" Up 5432/tcp
✅ Use case: Verify which containers are running.

🔹 7. Updating Services
🔄 docker-compose pull (Pull New Image Versions)

Fetches the latest images from Docker Hub.


docker-compose pull
✅ Use case: Keep containers updated with new images.

🔄 docker-compose build (Build Images from Dockerfile)

Builds new images if a Dockerfile is present.


docker-compose build
✅ Use case: Apply changes to the application code.

🚀 docker-compose up --force-recreate (Recreate Containers)

Forces recreation of containers without reusing existing ones.


docker-compose up --force-recreate
✅ Use case: Reset containers with fresh configurations.

🔹 8. Running Commands in a Container


💻 docker-compose exec (Run Commands Inside a Container)

Similar to docker exec, but works with Compose services.


docker-compose exec web ls /app
✅ Use case: Debug inside a running container.

💻 docker-compose run (Run a One-Time Command in a New Container)

Runs a service's command in a new temporary container.


docker-compose run web sh
✅ Use case: Testing or debugging without affecting running containers.

🔹 Summary of Commands
Command Description
docker-compose up -d Start all services in detached mode
docker-compose down Stop and remove containers, networks, and volumes
docker-compose logs -f View real-time logs
docker-compose ps List running services
docker-compose stop Stop containers without removing them
docker-compose restart Restart all containers
docker-compose start Start previously stopped containers
docker-compose rm -f Remove stopped containers
docker-compose exec service_name command Run commands inside a running container
docker-compose run service_name command Run a command in a new temporary container
docker-compose pull Pull latest images from the registry
docker-compose build Build images from a Dockerfile
docker-compose up --force-recreate Recreate containers without reusing old ones
docker-compose volume ls List all Docker volumes
docker-compose network ls List all Docker networks
docker-compose config Validate docker-compose.yml file

7. Docker Swarm (Orchestration)


7.0 Orchestration in Docker
Before we dive into Docker Swarm or Kubernetes, let's first understand why container orchestration
is needed, its importance, the challenges it solves, and the various tools available in the market.

🔹 Why Container Orchestration?


When dealing with multiple containers, managing them manually can become complex.
Container orchestration solves this by automating deployment, scaling, networking, and
availability.
⚠️What Happens Without Orchestration?
Imagine you have a microservices-based application with:
 User Service
 Product Service
 Payment Service
 Database Service
If you run these services as standalone Docker containers, you will face:
1. Manual Scaling: If traffic increases, you must manually start more containers.
2. Manual Networking: You need to define and manage connections between services.
3. Service Recovery: If a container crashes, you must restart it manually.
4. Load Balancing: You need to distribute traffic among containers yourself.
5. Resource Management: You must ensure optimal CPU & memory utilization.
Solution? ➝ Use a Container Orchestration Tool that automates everything.

🔹 Importance of Container Orchestration


Container orchestration is critical for modern cloud-native applications.
✅ Benefits:
Feature Description
Automated Scaling Adds or removes containers based on traffic.
Self-Healing Restart failed containers automatically.
Load Balancing Distributes traffic between multiple instances.
Service Discovery Containers find each other easily without manual IP management.
Rolling Updates Update applications without downtime.
Multi-Host Management Run and coordinate containers across multiple machines.

Example Use Case


🚀 E-commerce Website:
 During a sale, traffic spikes from 10,000 users to 100,000 users.
 A container orchestrator automatically scales up instances of services (cart,
payments, etc.).
 Once the sale is over, it scales down to save costs.

🔹 Challenges in Container Orchestration


Even with orchestration tools, there are challenges.
❌ Major Challenges:
1. Complex Setup: Managing and configuring orchestration tools requires expertise.
2. Security Issues: Containers communicate over the network, leading to security
concerns.
3. Storage Management: Persisting data across container restarts is difficult.
4. Networking Complexity: Inter-container and inter-host communication needs proper
networking.
5. Monitoring & Logging: Keeping track of logs and metrics across multiple containers is
tricky.
6. Cross-Cloud Compatibility: Running an orchestrator across different cloud providers
needs extra effort.

Example Challenge
If a database container crashes, orchestration tools restart it. But if persistent data storage
isn’t set up properly, data may be lost.

🔹 Popular Container Orchestration Tools


Several tools are available to manage and orchestrate containers. The most widely used are:
1️ Kubernetes (K8s) – Industry Standard
🔹 Open-source orchestration tool by Google.
🔹 Features:
 Self-healing containers.
 Automated rollouts & rollbacks.
 Horizontal scaling.
 Network policies & security.
 Works on-premise & cloud (AWS, Azure, GCP).

Example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
✅ Best for: Large-scale production deployments.

2️ Docker Swarm – Built-in Orchestration


🔹 Lightweight & easier than Kubernetes, managed by Docker.
🔹 Features:
 Simple cluster setup.
 Native Docker CLI integration.
 Auto-scaling & load balancing.
Example:
docker swarm init
docker service create --replicas 3 -p 80:80 nginx
✅ Best for: Small & medium-scale applications.

3️ Amazon ECS (Elastic Container Service)


🔹 AWS-managed orchestration for Docker containers.
🔹 Features:
 Deep AWS integration.
 No need to manage control plane.
 Works with Fargate for serverless containers.
✅ Best for: AWS-only workloads.

4️ Nomad (By HashiCorp)


🔹 Lightweight orchestration tool.
🔹 Features:
 Supports Docker & non-Docker workloads.
 Less complex than Kubernetes.
 Integrates with HashiCorp Vault for security.
✅ Best for: Simple orchestrations & hybrid workloads.

🔹 Comparison of Orchestration Tools


Feature Kubernetes Docker Swarm Amazon ECS Nomad
Complexity High Low Medium Low
Scalability Very High Medium High Medium
Self-Healing Yes Yes Yes No
Networking Advanced Basic AWS-native Basic
Cloud Agnostic? Yes Yes No (AWS only) Yes

7.1 Introduction to Docker Swarm

🔹 What is Docker Swarm?


Docker Swarm is a native clustering and orchestration tool for Docker that allows multiple Docker
hosts (nodes) to work together as a single virtual system. Swarm simplifies container management by
handling scaling, networking, load balancing, and self-healing.

✅ Features of Docker Swarm


Feature Description
Easy Setup Swarm is built into Docker, requiring minimal configuration.
Scaling Quickly scale up or down the number of running containers (services).
Self-Healing If a container crashes, Swarm replaces it automatically.
Containers can find and communicate with each other without IP
Service Discovery
management.
Load Balancing Built-in load balancing distributes traffic among running containers.
Multi-Host Networking Supports overlay networks for communication across multiple nodes.

🔹 Swarm vs Standalone Docker


In standalone Docker, you run and manage containers manually on a single machine. However, when
working with multiple containers across multiple machines, Swarm helps automate and optimize
deployment.
⚖️Comparison: Docker Standalone vs Docker Swarm
Feature Standalone Docker Docker Swarm
Cluster Support No Yes (Multiple nodes)
High Availability No Yes (Self-healing)
Scaling Manual Automatic
Service Discovery Manual Automatic
Load Balancing Needs Nginx/HAProxy Built-in
Multi-Host Networking No Yes
Ease of Use Simple Slightly complex

🔹 Example: Running a Standalone Docker Container


Without Swarm, you manually start a container on a single machine:
docker run -d --name my_web -p 80:80 nginx
 Runs an Nginx web server.
 Only runs on one machine (no clustering).
 If it fails, it won't restart automatically.
🚀 Now, let's see how Swarm improves this!

🔹 Example: Setting Up Docker Swarm


Let's convert our standalone setup into a Swarm cluster.
Step 1: Initialize Swarm Mode
docker swarm init
 This command initializes the current machine as a Swarm manager node.
 It provides a join token for adding worker nodes.

Expected Output:
Swarm initialized: current node (abcd1234) is now a manager.

To add a worker to this swarm, run:


docker swarm join --token SWMTKN-1-xxxxx <manager-IP>:2377

Step 2: Add Worker Nodes to the Swarm


On other machines, run:
docker swarm join --token SWMTKN-1-xxxxx <manager-IP>:2377
 This command joins a new machine as a worker node in the cluster.
 Workers cannot manage the cluster, but they can run containers.
✅ Now, we have multiple Docker nodes working as a single Swarm!

Step 3: Deploy a Service in Swarm


In Swarm mode, you deploy services instead of individual containers.
docker service create --name web_service -p 80:80 --replicas 3 nginx
 Creates 3 replicas of an Nginx container across available Swarm nodes.
 Swarm automatically balances containers across nodes.
 If a container fails, Swarm automatically replaces it.

Step 4: Check Running Services


docker service ls
Expected Output:
ID NAME MODE REPLICAS IMAGE
abcd1234 web_service replicated 3/3 nginx:latest
 Shows that 3 replicas of nginx are running.

Step 5: Verify Load Balancing


Check which containers are running on which nodes:
docker service ps web_service

Expected Output:
ID NAME NODE STATUS
xyz123 web_service.1 worker-1 Running
abc456 web_service.2 worker-2 Running
def789 web_service.3 worker-3 Running
 Swarm distributes containers across multiple nodes for high availability.

Step 6: Scaling Services


Easily scale up services:
docker service scale web_service=5
 Adds 2 more instances of the web service, ensuring better performance.

Step 7: Removing the Swarm


To disable Swarm mode:
docker swarm leave --force
 Removes the machine from the Swarm cluster.

🔹 Why Use Docker Swarm Instead of Standalone Docker?


Challenge Without Swarm With Swarm
Scaling Must manually start new containers Swarm auto-scales services
Container Failures Must restart crashed containers Swarm auto-restarts failed containers
Multi-Host Support Limited to single machine Runs across multiple hosts
Service Discovery Needs manual networking setup Automatic service discovery

7.2 Swarm Cluster Management


🔹 Introduction
To properly understand and manage Docker Swarm Clusters, we need to first set up a cluster
environment. A Swarm Cluster consists of multiple nodes, where some act as managers (handling
orchestration) and others as workers (running containers).

🔹 Setting Up a Swarm Cluster on AWS EC2


Step 1: Launch 3 EC2 Instances
 Create three EC2 instances (Amazon Linux 2 or Ubuntu).
 Install Docker on all instances:
sudo yum update -y # For Amazon Linux
sudo yum install docker -y
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
Logout and log back in to apply user changes.
 Verify Docker installation:
docker --version
✅ Now, we have 3 EC2 instances with Docker installed.

🔹 Understanding Swarm Terminologies


Before proceeding, let's clarify some key terms in Docker Swarm.
Term Description
Node A machine (VM or physical server) running Docker in the Swarm.
Manager Node Controls and manages the Swarm, schedules tasks, and manages worker nodes.
Worker Node Runs containers based on instructions from the manager.
Service A task definition that tells Swarm what containers to run.
Task A running instance of a container as part of a service.
Overlay Network A network that allows communication between nodes in a Swarm.
Ingress Network Built-in Swarm network for load balancing and external access.

🔹 Step 2: Initialize the Swarm on the Manager Node


1️ Choose the Manager Node
 Login to the instance you want to be the Swarm Manager.
 Find its private IP address:
ifconfig # For Linux/macOS
ip a # Alternative method
 Initialize the Swarm with:
docker swarm init --advertise-addr <manager_private_ip>

Expected Output:
Swarm initialized: current node (abcd1234) is now a manager.

To add a worker to this swarm, run:


docker swarm join --token SWMTKN-1-xxxxx <manager-private-ip>:2377
 --advertise-addr ensures that other nodes communicate with the manager via the
correct IP.
✅ Now, our Swarm cluster is created with the first Manager node!

🔹 Step 3: Join Worker Nodes to the Swarm


On each Worker Node, execute the docker swarm join command from the manager's output:
docker swarm join --token SWMTKN-1-xxxxx <manager-private-ip>:2377
Expected Output:
This node joined a swarm as a worker.
✅ The worker is now part of the Swarm cluster.

🔹 Step 4: Verify Nodes in Swarm


To list all nodes in the Swarm from the manager node, run:
docker node ls
Expected Output:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
abcd1234 manager-1 Ready Active Leader
efgh5678 worker-1 Ready Active
ijkl9012 worker-2 Ready Active
 Manager node is the Leader.
 Worker nodes are Active but don’t have a Manager Status.
✅ Now, we have a 3-node Swarm cluster running! 🎉

🔹 Step 5: Adding and Removing Nodes


Adding More Worker Nodes
 Simply run the docker swarm join command on any new machine.
 To get the join command again, run this on the manager:
docker swarm join-token worker
Adding More Manager Nodes
 If needed, additional manager nodes can be added:
docker swarm join-token manager
 To promote a worker to manager:
docker node promote worker-1

Removing a Node from the Swarm


Option 1: Remove from Manager
On the manager node, remove a worker:
docker node rm worker-1
Expected Output:
worker-1 removed from swarm.

Option 2: Leave Swarm from Node


On the worker node, leave the Swarm:
docker swarm leave
Expected Output:
Node left the swarm.
✅ The node is no longer part of the cluster.

🔹 Step 6: Demoting a Manager


If you want to demote a manager back to a worker, run:
docker node demote manager-2
Expected Output:
Manager node manager-2 demoted in the swarm.
✅ This node is now a worker.

🔹 Step 7: Removing the Entire Swarm


To completely remove the Swarm:
1. On all worker nodes, run:
docker swarm leave
2. On the manager node, run:
docker swarm leave --force
Expected Output:
Swarm mode disabled.
✅ Swarm is now fully removed.
7.3 Swarm Services & Tasks
🔹 Introduction to Swarm Services & Tasks
Docker Swarm is a container orchestration tool that manages the deployment, scaling, and
failover of containers across a cluster of machines. In a Swarm cluster, the smallest unit of
scheduling is a task, which represents a single instance of a container running on a node.
A service in Swarm defines the desired state of running tasks. If a task or container fails,
Swarm automatically restarts it to maintain the desired state.

🔹 Understanding Swarm Services & Tasks


1️ What is a Service?
A service in Swarm is a declarative way to manage containers. When you create a service,
Swarm decides where to place tasks based on available nodes and constraints.

2️ What is a Task?
 1 task = 1 container running on a Swarm node.
 If a service is set to 5 replicas, Swarm creates 5 tasks distributed across nodes.
 If a task fails, Swarm automatically replaces it on an available node.

📝 Example: Creating a Service


# Create a service with 3 replicas of Nginx
$ docker service create --name my_nginx --replicas 3 -p 8080:80 nginx
✅ This command will:
 Deploy 3 tasks (containers) across Swarm nodes.
 Expose port 80 on container and map it to port 8080 on host.
 If any container fails, Swarm replaces it on an available node.

📝 Verifying the Service & Tasks


# List all services
$ docker service ls

# List tasks running under the service


$ docker service ps my_nginx
Expected Output:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
abcd1234 my_nginx.1 nginx worker-1 Running Running
xyz98765 my_nginx.2 nginx worker-2 Running Running
lmno6789 my_nginx.3 nginx worker-3 Running Running

🔹 Swarm vs. ECS (Amazon Elastic Container Service)


Feature Docker Swarm Amazon ECS
Service Manages container replicas Manages container replicas
Runs a single container per Runs one or multiple
Task
task containers per task
Multi-container ❌ No ✅ Yes
Feature Docker Swarm Amazon ECS
tasks
Uses AWS VPC and Task
Networking Uses Overlay networks
Networking
Manual & Auto-scaling via Auto-scaling via ECS Task
Scaling
docker service update Definitions

Comparison Example:
 In Swarm, to run 2 different containers, you need 2 separate services.
 In ECS, a single task definition can run multiple containers together.

🔹 Difference Between Services, Tasks, and Containers


Component Description
Service Defines how tasks should be deployed across nodes.
Task A single running container instance within the Swarm cluster.
Container The actual runtime of a Docker image within a task.

🔹 Handling Failures in Swarm


1️ What happens if a container stops on a node?
Swarm automatically starts a new task on an available node to maintain service availability.
$ docker stop <container_id>
✅ The task will restart container on another node.(check using docker service ps nginx)

2️ What if we stop the Docker agent on one node?


$ systemctl stop docker
✅ Swarm will detect the failure and redistribute tasks to other nodes.

🔹 Removing a Docker Service


To completely remove a running service:
$ docker service rm my_nginx
✅ This will stop all running tasks and delete the service.

🔹 Scaling Services
Swarm supports two types of scaling:
1. Replicated Scaling: Defines a fixed number of replicas. Uses –replicas=5
2. Global Scaling: Ensures exactly one task runs per node. Eaxh time we add a node, this service
is added to that node. This type of scaling is done to run antivirus containers on all machines.
Example: docker service create – name antivirus –mode global -dt ubuntu

# Scale replicas from 3 to 5


$ docker service scale my_nginx=5
✅ Now, 5 tasks will be running instead of 3.

🔄 scale vs. update --replicas


Command Use Case
docker service scale Quick scaling up or down. Can scale 2 or more
Command Use Case
<service>=<replicas> services at once(docker service scale a=4 b=5)
docker service update -- More control over updates, can be used with rolling
replicas=<count> updates.

🔹 Draining a Node
When maintaining a Swarm node, you can drain it so tasks are rescheduled to other nodes.
$ docker node update --availability drain worker-1
✅ This removes tasks from worker-1.
To reactivate the node:
$ docker node update --availability active worker-1

Use case: We want to update something on a node. Then we can drain that node and update
it and then later make it active again so that tasks can be assigned to it by orchestrator

🔹 Inspecting Swarm Services & Nodes


To get detailed information on a service:
$ docker service inspect my_nginx --pretty

To inspect a node:
$ docker node inspect worker-1 --pretty
✅ Provides a human-readable summary.

🔹 Publishing Ports in Swarm


To expose a service externally:
$ docker service create --name web -p 8080:80 nginx
✅ This binds port 8080 on the host to port 80 in the container.

🔹 Mounting a Volume in Swarm


$ docker service create --name my_service -v my_volume:/app/data nginx

Or

$ docker service create --name my_service –mount type=volume source=my_volume,target=/app/data nginx


✅ This ensures persistent storage across nodes.
To verify volume:
$ docker volume ls => my volume created

🔹 Deploying Multi-Service Applications


Docker Swarm does not support multi-container tasks. This means one service in
Swarm can only run one container per task. However, real-world applications often
require multiple services (e.g., a web application with a database).
To deploy multiple services together, we use Docker Stack, which allows us to define
multiple services in a docker-compose.yml file and deploy them in Swarm Mode.

Why Use Docker Stack?


 Simplifies deployment of multi-container applications.
 Manages multiple services together instead of deploying services manually.
 Ensures proper networking and scaling within a Swarm cluster.
 Supports service discovery and automatic failover.

Example: Deploying a Multi-Service Application Using Docker Stack


We will deploy a simple web application consisting of:
 An NGINX web server (frontend service).
 A MySQL database (db service).

Step 1: Create the docker-compose.yml File


Create a new directory and navigate into it:
mkdir my_stack && cd my_stack

Create a docker-compose.yml file:


version: "3.8"

services:
frontend:
image: nginx:latest
ports:
- "8080:80"
networks:
- app_network
deploy:
replicas: 2
restart_policy:
condition: any

db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: mydatabase
volumes:
- db_data:/var/lib/mysql
networks:
- app_network
deploy:
replicas: 1
restart_policy:
condition: on-failure

networks:
app_network:

volumes:
db_data:
Explanation:
 frontend (NGINX web server)
o Runs on port 8080 (maps to container’s port 80).
o Uses a custom network (app_network) to communicate with the database.
o Runs two replicas for load balancing.
 db (MySQL database)
o Uses environment variables to set the database name and password.
o Uses a Docker volume (db_data) to persist database data.
o Runs only one replica (databases should not have multiple replicas unless
explicitly configured).
 networks: Creates a custom network for inter-container communication.
 volumes: Ensures MySQL data is persisted.

Step 2: Initialize a Docker Swarm (If Not Already Done)


To deploy a stack, you must have Docker Swarm mode enabled.
Check if Swarm is enabled:
docker info | grep Swarm
If Swarm is inactive, initialize it:
docker swarm init --advertise-addr <MANAGER_IP>
Replace <MANAGER_IP> with your manager node’s IP address.

Step 3: Deploy the Stack


Run the following command in the same directory where the docker-
compose.yml file is located:
docker stack deploy -c docker-compose.yml my_stack
This deploys the stack named my_stack.

Step 4: Verify the Deployment


Check the running services:
docker stack services my_stack
Expected Output:
ID NAME MODE REPLICAS IMAGE
abc123 my_stack_frontend replicated 2/2 nginx:latest
def456 my_stack_db replicated 1/1 mysql:5.7

 frontend service has 2 replicas running.


 db service has 1 replica running.

Check the running containers (tasks):


docker stack ps my_stack

Step 5: Test the Deployment


 Open http://<MANAGER_IP>:8080 in a browser. You should see the NGINX
default page.
 To connect to MySQL inside the running container:
 docker exec -it $(docker ps -q -f name=my_stack_db) mysql -uroot -
prootpassword

Step 6: Scaling the Services


If you need to scale services dynamically:
docker service scale my_stack_frontend=3
This increases the frontend service replicas to 3.

Step 7: Updating the Stack


To update a service (e.g., changing the image version), modify docker-
compose.yml and apply:
docker stack deploy -c docker-compose.yml my_stack
Docker Swarm will perform a rolling update.

Step 8: Removing the Stack


To stop and remove all services in the stack:
docker stack rm my_stack

🔹 Troubleshooting Service Deployment Failures


1️ Service Stuck in PENDING State
Possible reasons:
 No nodes available to run the task.
 Resource constraints (CPU, Memory) or other constraints say label .
 Network issues preventing overlay creation.
 Port conflicts.
✅ To debug:
$ docker service ps my_service

🔹 Controlling Service Placement


Why Control Service Placement?
In a Docker Swarm cluster, service placement ensures that containers run on
specific nodes based on predefined conditions. This is useful for:
 Running database services on high-memory nodes.
 Ensuring geo-distributed deployments (e.g., some services run in us-
east, others in us-west).
 Placing GPU workloads on nodes with GPUs.
 Distributing workloads based on resource availability.
Docker Swarm allows service placement control using constraints and
preferences.

1. Assigning Labels to Nodes


Docker Swarm uses node labels to categorize nodes. You can assign custom
labels to define node roles.

Check Existing Node Labels


To list labels assigned to all nodes:
docker node inspect --format '{{ .Spec.Labels }}' <NODE_NAME>

Example output:
{"region":"us-east","storage":"ssd"}
This means the node is labeled as:
 region=us-east
 storage=ssd

Add a Label to a Node


To add a label to a node, use:
docker node update --label-add region=us-east <NODE_NAME>

Example:
docker node update --label-add storage=ssd worker-1
This assigns the label storage=ssd to the node named worker-1.

Remove a Label from a Node


To remove a label:
docker node update --label-rm region <NODE_NAME>
Example:
docker node update --label-rm storage worker-1

2. Creating a Service with a Node Constraint


Once labels are assigned to nodes, we can restrict service placement using
constraints.

Run a Service Only on Nodes with a Specific Label


docker service create --name my_service --constraint 'node.labels.region == us-east' nginx
✅ This ensures that the my_service container runs only on nodes labeled
region=us-east.

Run a Service on Nodes with Multiple Labels


If we need multiple constraints, use:
docker service create --name my_service \
--constraint 'node.labels.region == us-east' \
--constraint 'node.labels.storage == ssd' \
nginx
✅ This ensures the service only runs on nodes labeled region=us-east and
storage=ssd.

Check Which Nodes a Service is Running On


To verify where a service is deployed:
docker service ps my_service
Example output:
ID NAME NODE DESIRED STATE CURRENT STATE
xyz123 my_service.1 worker-1 Running Running 5m ago
abc456 my_service.2 worker-2 Running Running 5m ago
✅ This shows the my_service replicas are running on worker-1 and worker-2.

3. Checking a Service’s Placement Constraints


To check which constraints were set on a running service:
docker service inspect my_service --format '{{ .Spec.TaskTemplate.Placement.Constraints }}'

Example output:
[region == us-east storage == ssd]
✅ This confirms that the service was restricted to nodes with these labels.

4. Controlling Placement with Preferences


Instead of forcing placement on certain nodes, preferences allow Swarm to prioritize
placement without strict enforcement.
Example: Prefer High-Memory Nodes
docker service create --name my_service \
--placement-pref 'spread=node.labels.memory' \
nginx
✅ This distributes containers evenly among nodes with the memory label.

5. Advanced Placement Control


Deploy a Global Service on All Nodes (Ignoring Constraints)
A global service runs one replica per node, ignoring placement constraints:
docker service create --name monitoring --mode global prom/node-exporter
✅ This runs a Node Exporter container on every node in the Swarm.

Limit Service to Specific Node Types


To only deploy on manager nodes:
docker service create --name manager_service --constraint 'node.role == manager' nginx
✅ This ensures the service runs only on manager nodes.

7.4 Networking in Docker Swarm (Overlay Networks)


In Docker Swarm, networking enables containers running on different hosts (nodes) to
communicate seamlessly. Unlike standalone Docker, where containers communicate via a
single host network, Swarm uses an overlay network to span multiple nodes.
Overlay networking allows: ✅ Communication between containers on different hosts.
✅ Automatic service discovery.
✅ Built-in load balancing.
✅ Secure encrypted communication.

1. Understanding the Overlay Network in Swarm


What is the Overlay Driver?
The overlay driver enables multi-host networking by creating a virtual network that spans
multiple Swarm nodes. It connects containers running on different physical machines.

How Does the Overlay Network Work?


1. When a service is created, Swarm automatically creates an overlay network if one
does not exist.
2. Each node participating in the network gets a virtual bridge connected to the overlay.
3. VXLAN (Virtual Extensible LAN) encapsulates packets, allowing containers across
different hosts to communicate as if they were on the same physical network.
4. Service discovery automatically assigns virtual IPs to services, so they can be
accessed by name.
2. Default Overlay Network in Swarm
Swarm provides a default overlay network named ingress. This is automatically created when
Swarm initializes.

Check the Default Overlay Network


docker network ls
Example output:
NETWORK ID NAME DRIVER SCOPE
0fb3b2e3c2f3 bridge bridge local
c2b5c6d1c4d5 host host local
35c1e2f1b8f8 none null local
8f79b2e3d2d4 ingress overlay swarm
✅ The ingress network is an overlay network used for publishing ports.

3. Creating a Custom Overlay Network


Instead of using the default ingress network, we can define custom overlay networks.

Create a Custom Overlay Network


docker network create --driver overlay my_overlay_network
✅ This creates a Swarm-wide network that spans all nodes.

Verify the Network


docker network ls
Example output:
NETWORK ID NAME DRIVER SCOPE
0fb3b2e3c2f3 bridge bridge local
c2b5c6d1c4d5 host host local
35c1e2f1b8f8 none null local
8f79b2e3d2d4 ingress overlay swarm
ae12bc34d56f my_overlay_network overlay swarm
✅ my_overlay_network is an overlay network across all Swarm nodes.

4. Deploying Services on the Overlay Network


Once the overlay network is created, services can be attached to it.

Deploy a Service on the Custom Overlay Network


docker service create --name my_service --network my_overlay_network nginx
✅ This ensures that my_service containers can communicate over my_overlay_network.

List Services in the Network


docker network inspect my_overlay_network
✅ This shows all containers connected to the network.

5. Securing Overlay Networks


By default, overlay networks are unencrypted, meaning that traffic flows in plain text. To
secure communication, Swarm supports encryption.
Enable Network Encryption
docker network create --driver overlay --opt encrypted secure_overlay_network
✅ This encrypts all communication between containers across hosts.

6. Testing Overlay Network Communication


Step 1: Create an Overlay Network
docker network create --driver overlay my_test_network

Step 2: Deploy Two Services on Different Nodes


docker service create --name web --network my_test_network nginx
docker service create --name app --network my_test_network alpine sleep 10000

Step 3: Enter the App Container and Ping the Web Container
Find a running container from the app service:
docker ps

Example output:
CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES
ab12cd34ef56 alpine "sleep 10000" 1 minute ago Up 1 minute app.1.xxxx

Enter the container:


docker exec -it ab12cd34ef56 sh

Ping the web service:


ping web
✅ If networking is working, the output will be:
PING web (10.0.0.2): 56 data bytes
64 bytes from 10.0.0.2: seq=0 ttl=64 time=0.045 ms

7. Verifying Encryption
To check if encryption is working, capture network packets and ensure traffic is encrypted.
On One of the Swarm Nodes, Run:
sudo tcpdump -i eth0 port 4789
🔹 Port 4789 is used for VXLAN encapsulation. If encrypted, no plain text data will be visible.

8. Publishing Ports on an Overlay Network


If a service needs to be accessible externally (e.g., Nginx on port 80), use -p.
docker service create --name web --network my_overlay_network -p 8080:80 nginx
✅ Now, http://<ANY_NODE_IP>:8080 will serve the Nginx page.

9. Removing an Overlay Network


If the network is no longer needed, remove it:
docker network rm my_overlay_network

7.5 Swarm High Availability & Fault Tolerance

Ensuring high availability and fault tolerance in a Docker Swarm cluster is critical for preventing
disruptions and maintaining service uptime. In this section, we'll cover key topics like quorum, split-
brain problems, manager node high availability, and disaster recovery strategies.
1. Quorum & Split-Brain Problem

What is Quorum?
Quorum is the minimum number of manager nodes required for the cluster to function properly.
✅ Swarm uses Raft consensus algorithm to maintain consistency across manager nodes.
✅ A quorum is required for leader elections and state changes.
✅ If quorum is lost, the cluster cannot accept new updates, even if some nodes are running.

Split-Brain Problem
If two or more partitions of a cluster believe they are the leader due to a network failure, it's called a
split-brain problem.
🔹 This can lead to data inconsistency and conflicting changes.
🔹 Swarm prevents split-brain by requiring a majority (quorum) of managers to make decisions.
🔹 If quorum is lost, Swarm stops making decisions until the quorum is restored.

2. Fault Tolerance in Swarm Based on Cluster Size


Swarm's fault tolerance depends on the number of manager nodes in the cluster.
Cluster Size (Total Managers) Quorum Needed Max Fault Tolerance (Nodes That Can Fail)
1 1 0
3 2 1
5 3 2
7 4 3
🔹 The best practice is to use an odd number of managers to ensure proper quorum.

3. Why Do We Need High Availability for Manager Nodes?


The manager node in Swarm is responsible for: ✅ Maintaining the state of the cluster.
✅ Handling service deployments.
✅ Running the Raft consensus algorithm for leader elections.
🚨 If a manager node fails and the cluster does not have quorum: ❌ No leader election can take place.
❌ No updates to services can be made.
✅ Solution: Have at least 3 or 5 manager nodes to maintain fault tolerance.

4. How to Achieve High Availability in Swarm


1. Odd Number of Manager Nodes
Swarm requires an odd number of manager nodes (e.g., 3, 5, or 7) to ensure quorum is maintained.
2. Raft Implementation (Maintaining Quorum)
 Raft consensus ensures only one leader at a time.
 At least (n-1)/2 managers must be online to avoid losing quorum.

5. Creating Additional Manager Nodes


To increase fault tolerance, convert worker nodes into manager nodes.
Step 1: Get Swarm Join Command for Managers
On the current leader manager, run:
docker swarm join-token manager
Example output:
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-xyz 192.168.1.10:2377

Step 2: Add a New Manager Node


On the node you want to promote to a manager, run:
docker swarm join --token SWMTKN-1-xyz 192.168.1.10:2377

Step 3: Verify All Manager Nodes


On any manager node, check the list of nodes:
docker node ls
Example output:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
8f3c8d6c7e89 manager-1 Ready Active Leader
9c5d1e3f8a6b manager-2 Ready Active Reachable
3e8b4d9c2d8f manager-3 Ready Active Reachable
✅ Leader is the active manager. Other managers are reachable.
Step 4: Handling Manager Node Failure
🚨 If the leader manager goes down, a new leader will be automatically elected.
✅ No manual intervention needed if quorum exists.

6. Manager-Only Nodes (Using Draining)


A manager-only node does not run services but only handles Swarm management.
Why Use Manager-Only Nodes?
 Prevents manager overload from running both services & leader elections.
 Ensures manager nodes focus on orchestration and Raft consensus.
Drain a Manager Node to Prevent Workload
docker node update --availability drain manager-1
✅ This ensures only worker nodes run services.

7. Locking a Swarm Cluster


Swarm allows locking the cluster to protect against unauthorized manager restarts.
Step 1: Enable Auto-Locking
On the manager node, enable auto-lock:
docker swarm update --autolock=true
✅ This ensures the cluster requires a passkey when restarting a manager.

Step 2: Retrieve Unlock Key


After enabling auto-lock, retrieve the key:
docker swarm unlock-key
Example output:
SWM: Unlock key: YJ83c92E4mv8rfdg56FH8Jv3
✅ Store this key safely.
Step 3: Unlock the Swarm on Restart
If the cluster restarts, you must unlock it:
docker swarm unlock
Then, enter the unlock key.

8. Recovering from Losing Quorum


If too many manager nodes fail, Swarm loses quorum, and no changes can be made.
Step 1: Force a New Leader Election
On one of the remaining manager nodes, run:
docker swarm --force-new-cluster
✅ This forces a new Raft state.
Step 2: Check Node Status
docker node ls
Example output:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
8f3c8d6c7e89 manager-1 Ready Active Leader
✅ The cluster is recovered.
Step 3: Restore Lost Managers
Re-add failed managers:
docker swarm join --token <manager-token> <manager-ip>:2377

9. Role of Raft State Store


What is Raft State Store?
Swarm stores the cluster state using the Raft algorithm. This includes: ✅ List of services running in
Swarm.
✅ State of each node (leader, follower, worker, etc.).
✅ Configuration of networks, volumes, and deployments.
Even if the Swarm leader changes, the cluster state remains intact.
Where is Raft Data Stored?
Raft data is stored in:
/var/lib/docker/swarm/raft/
✅ This ensures data persists even if a manager fails or restarts.

8. Troubleshooting & Debugging Docker


8.1 Logs & Debugging in Docker Swarm
Logging and debugging are crucial in maintaining a healthy Docker Swarm cluster. This section
explores:
✅ Checking logs of containers and services
✅ Debugging service deployment failures
✅ Monitoring resource usage of running containers

1. Inspecting Logs with docker logs


Logs are essential for debugging container issues. Docker provides the docker logs command
to view logs from running or stopped containers.
Basic Usage
docker logs <container_id>
Example
Let's say we have an nginx service running in Swarm.
1️ Find the container ID:
docker ps
Example output:
CONTAINER ID IMAGE COMMAND STATUS NAMES
1a2b3c4d5e6f nginx "nginx -g 'daemon off;'" Up 10 mins nginx-container
2️ View logs of this container:
docker logs 1a2b3c4d5e6f
Example output:
2025/03/29 12:34:56 [notice] 1#1: start worker process 8
2025/03/29 12:34:56 [notice] 1#1: start worker process 9

Follow Live Logs (-f)


To stream logs live, use:
docker logs -f <container_id>
🔹 Useful when debugging a service in real-time.

2. Debugging Service Deployment Issues


If a service fails to start in Swarm, debugging is necessary.
1. Checking Service Status
Use:
docker service ps <service_name>
Example:
docker service ps my_web_service
Output:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
3e4a2b1c2d8e my_web.1 nginx:latest node1 Running Running 5s ago
f1a2b3c4d5e6 my_web.2 nginx:latest node2 Shutdown Failed 3s ago
❌ One instance failed!
2. Checking Logs of a Failed Task
docker logs <container_id>
🔹 This will show why the service failed.
3. Checking Service Details
docker service inspect my_web_service --pretty
🔹 Shows environment variables, constraints, placement, and networking.
4. Checking Node Issues
docker node ls
If a node is down, move workloads using:
docker node update --availability drain node2

3. Viewing Container Resource Usage (docker stats)


To monitor CPU, memory, network, and disk usage for containers:
docker stats
Example output:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT NET I/O BLOCK I/O
1a2b3c4d5e6f nginx-container 3.14% 20MiB / 512MiB 10MB / 2MB 0B / 0B
🔹 Use case: If a container is using too much memory, check logs for memory leaks.

8.2 Docker System Commands


1. Checking Disk Usage (docker system df)
To see how much disk space Docker is using:
docker system df
Example output:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 10 5 2.1GB 1.5GB (71%)
Containers 8 4 500MB 250MB (50%)
Volumes 15 10 3.2GB 1.2GB (37%)
Build Cache 5 2 1.1GB 600MB (54%)
🔹 If disk usage is high, prune unused resources.

2. Cleaning Up Unused Resources (docker system prune)


To remove all unused images, containers, volumes, and networks, run:
docker system prune
✅ Prompts confirmation before deleting.
To force cleanup without confirmation
docker system prune -f
To remove unused volumes too
docker system prune --volumes
🚨 Warning: This will delete unused volumes, losing stored data.

9. Security Best Practices in Docker


Docker security is crucial to prevent unauthorized access, privilege escalation, and container escape
attacks. This section covers:
✅ Running Containers as Non-Root Users
✅ Securing the Docker Daemon
✅ Restricting Container Capabilities
✅ Using seccomp and AppArmor Profiles

1. Running Containers as Non-Root Users


By default, containers run as the root user inside the container, which can be a security risk. If a
container gets compromised, the attacker gets root access inside the container, which increases the
attack surface.
Solution: Run Containers as a Non-Root User
Modify your Dockerfile to use a non-root user:
FROM nginx:latest
RUN addgroup --system mygroup && adduser --system --ingroup mygroup myuser
USER myuser
CMD ["nginx", "-g", "daemon off;"]
Running a Non-Root User in Docker Run
If the Dockerfile is not modified, override the user when running the container:
docker run -d --user 1001 nginx
🔹 Check running user inside the container:
docker exec -it <container_id> whoami
Expected Output:
myuser
🚀 Benefits:
 Prevents privilege escalation in case of an attack.
 Restricts system-wide access if the container is compromised.

2. Securing the Docker Daemon


The Docker daemon (dockerd) runs as root and listens for API requests. If misconfigured, it can
expose the system to unauthorized access.
2.1 Use TLS to Secure the API Socket
By default, the Docker daemon listens on unix:///var/run/docker.sock, but if exposed on TCP
(tcp://0.0.0.0:2375), it must be secured with TLS.

Check if Docker API is Open


netstat -tulnp | grep dockerd
🚨 If it shows tcp://0.0.0.0:2375, it's a security risk!

Enable TLS for Secure Communication


Edit /etc/docker/daemon.json:
{
"tls": true,
"tlscert": "/etc/docker/cert.pem",
"tlskey": "/etc/docker/key.pem"
}
Restart Docker:
systemctl restart docker

2.2 Disable Docker API for Unauthorized Users


Limit API access to specific users:
usermod -aG docker myuser
Check if a user is in the Docker group:
groups myuser

3. Restricting Container Capabilities


Linux provides capabilities to restrict the actions containers can perform. Containers run with many
capabilities by default, which increases security risks.
3.1 Dropping Unnecessary Capabilities
Run a container with restricted capabilities:
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
 --cap-drop=ALL → Drops all capabilities.
 --cap-add=NET_BIND_SERVICE → Allows binding to ports below 1024.
🔹 List all capabilities:
capsh --print

🔹 Check capabilities inside a running container:


docker exec -it <container_id> capsh --print
🚀 Benefits:
 Prevents privilege escalation.
 Reduces the attack surface in case of container compromise.

4. Using seccomp and AppArmor Profiles


4.1 seccomp (Secure Computing Mode)
seccomp is a Linux security feature that restricts system calls available to containers.

🔹 Docker uses a default seccomp profile, but it can be customized.


Check the Default seccomp Profile
docker info | grep -i seccomp
Output:
Security Options:
seccomp

Run a Container with seccomp Restrictions


docker run --security-opt seccomp=default.json nginx

🔹 Example seccomp profile (default.json)


{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["chmod", "chown"],
"action": "SCMP_ACT_ALLOW"
}
]
}
🚀 Benefits of seccomp:
 Prevents syscall-based attacks.
 Blocks unnecessary system calls.

4.2 AppArmor Profiles


AppArmor is a Linux security module that restricts container actions.

Check AppArmor Status


apparmor_status

Run a Container with an AppArmor Profile


docker run --security-opt apparmor=docker-default nginx

Custom AppArmor Profile


Create /etc/apparmor.d/my-profile:
profile my-profile flags=(attach_disconnected) {
capability,
network inet stream,
file,
}

Apply the profile:


apparmor_parser -r /etc/apparmor.d/my-profile
🚀 Benefits of AppArmor:
 Restricts file system access.
 Prevents unauthorized network access.

10. AWS ECS (Elastic Container Service)


Amazon Elastic Container Service (ECS) is a fully managed container orchestration service provided
by AWS. It allows you to run and manage Docker containers on a cluster of EC2 instances or in a
serverless manner using Fargate.

10.1 Introduction to ECS


ECS vs Docker Swarm
Feature AWS ECS Docker Swarm
Hosting Fully managed by AWS Self-managed
Scalability Auto Scales via ASG/Fargate Manual Scaling
Load Balancing Integrated with ALB/NLB Requires external setup
Security IAM for fine-grained access Basic security
Networking VPC-native with private IPs Requires overlay networks
Pricing Fargate pay-per-use EC2 costs
Storage EFS, S3, Local volumes Local Volumes
Service Discovery AWS Cloud Map Internal DNS
🚀 Why ECS?
 No need to manage control planes like in Kubernetes.
 Integrates well with AWS services (IAM, CloudWatch, ALB, etc.).
 Supports both EC2 & Serverless (Fargate).
 Built-in security via IAM roles & VPC networking.

10.2 Managing ECS Tasks & Services


1️ Creating an ECS Cluster
An ECS Cluster is a logical grouping of EC2 instances or Fargate tasks.
Using AWS Console
1. Go to AWS ECS → Click Create Cluster.
2. Choose EC2 Linux + Networking or Fargate.
3. Configure the cluster name → my-ecs-cluster.
4. Select the instance type (for EC2 mode) → t3.micro.
5. Enable CloudWatch Logs for monitoring.
6. Click Create Cluster.

🚀 Terraform Code for Cluster


resource "aws_ecs_cluster" "ecs_cluster" {
name = "my-ecs-cluster"
}
terraform init
terraform apply -auto-approve
✔️Output:
Apply complete! Resources: 1 added.

2️ Registering a Task Definition


A Task Definition describes a container’s configuration (Docker image, CPU, memory, IAM role,
environment variables, etc.).
Using AWS Console
1. Go to ECS → Click Task Definitions.
2. Click Create New Task Definition.
3. Choose Fargate or EC2.
4. Configure container:
o Image: nginx
o CPU: 256
o Memory: 512
o Port Mapping: 80:80
5. Click Create Task Definition.

🚀 Terraform Code for Task Definition


resource "aws_ecs_task_definition" "nginx_task" {
family = "nginx-task"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = "256"
memory = "512"
execution_role_arn = aws_iam_role.ecs_task_execution_role.arn

container_definitions = jsonencode([
{
name = "nginx"
image = "nginx"
cpu = 256
memory = 512
essential = true
portMappings = [
{
containerPort = 80
hostPort = 80
}
]
}
])
}
terraform apply -auto-approve
✔️Output:
Apply complete! Resources: 1 added.

3️ Running a Service in ECS


A Service ensures that a specified number of tasks are always running.
Using AWS Console
1. Go to ECS → Click Create Service.
2. Select:
o Launch Type: Fargate
o Task Definition: nginx-task
o Cluster: my-ecs-cluster
o Desired Task Count: 2
3. Configure networking:
o Select a VPC and subnets.
o Attach a security group allowing port 80.
4. Click Create Service.

🚀 Terraform Code for ECS Service


resource "aws_ecs_service" "nginx_service" {
name = "nginx-service"
cluster = aws_ecs_cluster.ecs_cluster.id
task_definition = aws_ecs_task_definition.nginx_task.arn
launch_type = "FARGATE"
desired_count = 2

network_configuration {
subnets = aws_subnet.public[*].id
security_groups = [aws_security_group.ecs_sg.id]
assign_public_ip = true
}
}
terraform apply -auto-approve
✔️Output:
Apply complete! Resources: 1 added.

4️ Scaling ECS Services


Using AWS Console
 Navigate to the ECS Service.
 Click Update Service → Change Desired Count to 3.

🚀 Terraform Code for Scaling


resource "aws_appautoscaling_target" "ecs_target" {
max_capacity =5
min_capacity =2
resource_id = "service/my-ecs-cluster/nginx-service"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}

10.3 ECS Launch Types


1️ EC2 Mode (Self-Managed)
 Runs containers on EC2 instances (similar to Kubernetes worker nodes).
 Requires manual instance provisioning & scaling.
Terraform Example for EC2 Cluster
resource "aws_launch_configuration" "ecs_instance" {
name = "ecs-instance"
image_id = "ami-12345678"
instance_type = "t3.micro"
user_data = <<-EOF
#!/bin/bash
echo "ECS_CLUSTER=my-ecs-cluster" >> /etc/ecs/ecs.config
EOF
}

2️ Fargate Mode (Serverless)


 Fully managed, no EC2 provisioning.
 AWS automatically scales resources.
 Best for microservices & event-driven applications.

Comparison: Fargate vs EC2


Feature EC2 Mode Fargate Mode
Infrastructure Requires EC2 instances Serverless
Auto Scaling Manual via ASG Fully managed
Cost Pay for EC2 instances Pay per-task usage
Management Overhead High Low
🚀 Which One to Use?
 Use Fargate for auto-scaling, serverless, & microservices.
 Use EC2 Mode for cost control & flexibility.

NOTE: USE ALB FOR LOAD BALANCING ECS

11. Real-World Docker Deployment Strategies


A. Deploying Multi-Service Applications in Production
Deploying multi-service applications in production using Docker involves several best
practices and tools to ensure scalability, reliability, and ease of management. Let’s break
down the process with detailed steps, examples, and explanations of how this works in real-
world production environments.

1. Overview of Multi-Service Applications


A multi-service application is one where different functionalities or components of the
application are broken down into separate services, each running in its container. For
example:
 A web application (e.g., a frontend React app).
 A backend API (e.g., a Django or Node.js API server).
 A database (e.g., PostgreSQL or MySQL).
Each service communicates with others, and together they form the complete
application.

2. Using Docker Compose for Multi-Service Applications


The most common way to deploy multi-service applications in Docker is by using
Docker Compose, which allows you to define and run multi-container Docker
applications with a single YAML file.

Example: Docker Compose for Multi-Service App


Consider a simple application with:
 A web service running an Nginx server.
 A backend service running a Node.js application.
 A database service running MySQL.
Here’s how you would define it in a docker-compose.yml file:
version: '3.7'

services:
web:
image: nginx:latest
container_name: web_container
ports:
- "80:80"
networks:
- app_network
depends_on:
- backend

backend:
image: node:14
container_name: backend_container
build: ./backend
networks:
- app_network
environment:
DB_HOST: db
DB_PORT: 3306
depends_on:
- db

db:
image: mysql:5.7
container_name: db_container
environment:
MYSQL_ROOT_PASSWORD: rootpassword
MYSQL_DATABASE: appdb
networks:
- app_network
volumes:
- db_data:/var/lib/mysql

networks:
app_network:
driver: bridge
volumes:
db_data:
driver: local

Explanation of the YAML Structure


 services: Defines the containers to be used (web, backend, db).
 web: This service uses the Nginx image, maps port 80 from the container to
the host, and depends on the backend service.
 backend: This service builds from a local directory (./backend) containing a
Node.js app, and connects to the database (db).
 db: Uses the MySQL image, initializes the database with a root password, and
stores data persistently in a named volume db_data.
 networks: Defines the network (app_network) where all services
communicate.
 volumes: Creates a persistent storage volume for MySQL data.

3. Scaling Multi-Service Applications


When deploying multi-service applications in production, scaling is often required to
handle varying loads. Docker Swarm or Kubernetes can be used to scale services
horizontally.

Scaling in Docker Swarm


In Docker Swarm, you can scale services based on the number of replicas. For
example:
docker service scale backend=3
This command will scale the backend service to 3 replicas across the nodes in the
Swarm cluster. Swarm automatically handles load balancing between replicas.

Scaling in Kubernetes
In Kubernetes, you would use a Deployment to scale the backend service:
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend-deployment
spec:
replicas: 3
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: backend_image
ports:
- containerPort: 8080

4. Service Discovery & Load Balancing


In multi-service architectures, each service needs to discover and communicate with
other services. This is often handled by a service discovery mechanism.
 In Docker Swarm, Docker automatically sets up service discovery via DNS. For
example, if the backend service needs to connect to the database, it can use db
as the hostname (since that's the name of the service in Docker Compose).
 In Kubernetes, service discovery is done through Kubernetes Services, where
each service is given a stable DNS name within the cluster.
For example, in Docker Swarm, a service called backend can reach the database service
by using db:3306 as the connection string.
5. Persistent Data with Volumes
When deploying multi-service applications, data persistence is crucial, especially for
services like databases. Docker volumes are used to persist data outside of
containers. In the above Docker Compose example, we used a named volume
(db_data) to persist MySQL data.
volumes:
db_data:
driver: local
In production, you might use cloud-based storage or other persistent storage
solutions to ensure data is retained across container restarts.

6. Deploying Multi-Service Applications with Docker Stack


Docker Swarm allows you to deploy multi-service applications using docker stack.
This is similar to Docker Compose but is used in a Swarm mode.

Steps to Deploy Using Docker Stack:


1. Prepare the Compose File: The docker-compose.yml file can be directly used
to deploy the stack in Swarm.
2. Deploy the Stack:
docker stack deploy -c docker-compose.yml my_stack

This command will deploy all services defined in the docker-compose.yml to the
Swarm cluster.
3. Verify Deployment:
docker stack services my_stack
This command will list the services deployed in the stack and their current status.
7. Continuous Integration and Continuous Deployment (CI/CD)
To maintain consistent deployments and enable automated testing and release,
integrating Docker with a CI/CD pipeline is crucial. Popular tools like Jenkins, GitLab
CI, and CircleCI can be used to automate building and deploying multi-service
applications.

Example: Docker CI/CD Pipeline (GitLab CI)


stages:
- build
- deploy

build:
stage: build
script:
- docker build -t my-app .

deploy:
stage: deploy
script:
- docker-compose up -d
This pipeline:
 Builds the Docker image.
 Deploys the application using docker-compose up -d.

8. Monitoring & Logging in Multi-Service Applications


To ensure the application runs smoothly, monitoring and logging are essential in
production.
 Prometheus & Grafana can be used for monitoring metrics like CPU usage,
memory usage, and network activity for each container in the multi-service
application.
 ELK Stack (Elasticsearch, Logstash, and Kibana) or EFK Stack (Elasticsearch,
Fluentd, and Kibana) can be used for centralized logging.

For example, in Docker Compose, you can integrate Fluentd as a logging driver:
services:
web:
image: nginx
logging:
driver: fluentd
options:
fluentd-address: localhost:24224

B. Managing Zero Downtime Deployments


Zero downtime deployment ensures that an application remains available without disruption
while updating or deploying a new version. This is critical for production environments where
downtime can lead to financial losses or degraded user experience.

1️ Understanding Zero Downtime Deployment


In traditional deployments, restarting a service or updating an application could
cause temporary downtime.
 Downtime Problem: If you update a running container, all requests will fail until the
new container is available.
 Solution: Use rolling updates, blue-green deployments, and load balancing
techniques.
Approaches to Achieve Zero Downtime
✅ Rolling Updates: Gradually replace old containers with new ones.
✅ Blue-Green Deployment: Deploy new version alongside the old one and switch
traffic when ready.
✅ Canary Deployment: Release the new version to a subset of users before full
rollout.

2️ Hands-On: Rolling Updates Using Docker Swarm


Docker Swarm provides built-in rolling updates, making it easier to achieve zero
downtime.
Step 1: Set Up Docker Swarm
🚀 Initialize Docker Swarm (On the manager node):
docker swarm init --advertise-addr <manager-ip>
💡 Check if Swarm is Active:
docker info | grep "Swarm"
If it’s active, proceed. If not, join worker nodes to the Swarm.

Step 2: Deploy a Web Service in Swarm


Let’s deploy a simple Nginx web server in Swarm mode.
📌 Create a Docker Service with 3 Replicas
docker service create --name web-service --replicas 3 -p 80:80 nginx:latest
📌 Verify Service Deployment
docker service ls
docker service ps web-service
🔍 You should see 3 running Nginx containers distributed across nodes.
📌 Access the Web Service Find the public IP of a Swarm node and access it in
your browser:
http://<node-ip>

Step 3: Perform a Rolling Update


Suppose we need to update our web server to a new version (nginx:alpine).
✅ Update the Service with Zero Downtime
docker service update --image nginx:alpine --update-delay 10s --update-parallelism 1 web-service
💡 Explanation:
 --image nginx:alpine → The new image to deploy.
 --update-delay 10s → A 10-second delay between updating each container.
 --update-parallelism 1 → Updates 1 container at a time, ensuring availability.
🔍 Check the Rolling Update Progress
docker service ps web-service
🔍 Confirm Version Update
docker inspect web-service | grep Image

3️ Hands-On: Blue-Green Deployment


Blue-Green Deployment runs two environments (blue = current version, green = new
version) and switches traffic between them.

Step 1: Deploy the Blue (Current) Version


docker service create --name web-blue --replicas 3 -p 80:80 nginx:1.21
Step 2: Deploy the Green (New) Version
docker service create --name web-green --replicas 3 -p 8080:80 nginx:1.23
📌 Now, the blue version is running on port 80, and the green version is running on
port 8080.
Step 3: Switch Traffic to the New Version
✅ Use a reverse proxy like Traefik or NGINX to switch traffic dynamically. OR
✅ Remove the blue service and re-map port 80 to the green version:
docker service rm web-blue
docker service update --publish-add 80:80 web-green

4️ Monitoring & Verifying Deployment


📌 Check Running Services
docker service ls
📌 Check Logs for Any Errors
docker service logs web-service
📌 Check Resource Usage
docker stats

5️ Rollback in Case of Issues


If the new version has bugs, we can roll back to the previous version.
docker service update --rollback web-service
🚀 The previous stable version will be restored without downtime.

C. Monitoring & Logging with Prometheus & Grafana


Monitoring and logging are crucial for understanding system performance,
troubleshooting issues, and ensuring stability in production. In this guide, we’ll set up
Prometheus (for monitoring) and Grafana (for visualization) to monitor Docker
containers.

1️ Understanding Prometheus & Grafana


✅ Prometheus: An open-source monitoring tool that scrapes metrics from
services and stores them in a time-series database.
✅ Grafana: A visualization tool that fetches data from Prometheus and
displays it using interactive dashboards.
📌 Why Use Prometheus & Grafana?
 Real-time monitoring of containerized applications.
 Custom alerts for CPU, memory, network, etc.
 Historical data analysis for performance tuning.

2️ Setting Up Prometheus & Grafana with Docker Compose


We’ll use Docker Compose to simplify deployment.

Step 1: Create a Docker Network


docker network create monitoring
This ensures all monitoring services communicate within the same
network.

Step 2: Create the prometheus.yml Configuration File


Create a directory for Prometheus:
mkdir -p ~/monitoring/prometheus
cd ~/monitoring/prometheus
Create the prometheus.yml config file:
nano prometheus.yml

Paste the following:


global:
scrape_interval: 5s # Scrape metrics every 5 seconds

scrape_configs:
- job_name: 'docker'
static_configs:
- targets: ['host.docker.internal:9323']
📌 This tells Prometheus to scrape Docker metrics from
host.docker.internal:9323 (Docker's built-in metric endpoint).

Step 3: Create the Docker Compose File


Go back to the main directory:
cd ~/monitoring
nano docker-compose.yml
Paste the following:
version: '3'

services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
volumes:
-
./prometheus/prometheus.yml:/etc/prometheus/prometheus.y
ml
ports:
- "9090:9090"
networks:
- monitoring

grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
networks:
- monitoring
depends_on:
- prometheus

networks:
monitoring:
driver: bridge
📌 Explanation:
 Prometheus runs on port 9090 and scrapes data.
 Grafana runs on port 3000 and fetches metrics from Prometheus.
 Both services share a network (monitoring) for communication.

Step 4: Start the Monitoring Stack


Run the following command:
docker-compose up -d
📌 This will start Prometheus & Grafana in detached mode (-d).

Step 5: Verify Prometheus is Running


Check the running containers:
docker ps
Output:
CONTAINER ID IMAGE STATUS PORTS
b4f5a8c23f02 prom/prometheus Up 5 minutes 0.0.0.0:9090->9090/tcp
e3a5f6d21a9b grafana/grafana Up 5 minutes 0.0.0.0:3000->3000/tcp
Check if Prometheus is collecting metrics:
curl http://localhost:9090/metrics
📌 You should see a list of Prometheus metrics.

3️ Access Grafana & Configure Prometheus as a Data Source


Step 1: Open Grafana
Go to http://localhost:3000 in your browser.
Step 2: Login to Grafana
 Username: admin
 Password: admin (default, change after first login)
Step 3: Add Prometheus as a Data Source
1. Click on Settings → Data Sources → Add Data Source.
2. Select Prometheus.
3. Set the URL to http://prometheus:9090 (since both services are in the
same network).
4. Click Save & Test.
📌 Now Grafana is ready to fetch metrics from Prometheus!

4️ Visualizing Metrics in Grafana


Step 1: Import a Prebuilt Dashboard
1. Go to Dashboards → Import.
2. Enter Dashboard ID: 1860 (popular Docker monitoring dashboard).
3. Select Prometheus as the data source.
4. Click Import.
✅ You should now see CPU, memory, network, and container metrics in
Grafana! 🎉

5️ Logging Docker Container Metrics


Docker has a built-in logging driver that supports CloudWatch, Fluentd, Loki,
and more.
Step 1: Enable Docker Logs Collection

Run a container with logging enabled:


docker run -d --name test-container --log-driver=json-file nginx
To check logs:
docker logs test-container
📌 To integrate logs with Grafana Loki:
1. Install Loki (docker run -d --name=loki grafana/loki).
2. Configure Promtail (docker-compose.yml).
3. Add Loki as a data source in Grafana.

6️ Stopping & Removing Monitoring Stack


To stop the monitoring setup:
docker-compose down
To remove all data:
docker volume prune -f

D. Performance testing Hands-on


🔹 Why Performance Testing?
Performance testing helps analyze:
✅ Latency (Response Time)
✅ Throughput (Requests per second)
✅ Resource Utilization (CPU, Memory, Disk, Network)
✅ Scalability & Load Handling
Tools Used for Performance Testing in Docker
1. Apache Bench (ab) – Load Testing
2. JMeter – Advanced Performance Testing
3. Siege – Stress Testing
4. Prometheus + Grafana – Resource Monitoring

1️Load Testing with Apache Bench (ab)


Step 1: Run a Test Web Service in Docker
We'll use Nginx as our test application.
docker run -d --name test-nginx -p 8080:80 nginx
✅ Now, Nginx is running on http://localhost:8080.

Step 2: Install ab (Apache Bench)


For Linux/macOS:
sudo apt install apache2-utils # Ubuntu
brew install apache2-utils # macOS

Step 3: Run a Load Test


ab -n 1000 -c 50 http://localhost:8080/
📌 Explanation:
 -n 1000: Total 1000 requests
 -c 50: 50 concurrent requests
✅ Expected Output:
Server Software: nginx
Server Hostname: localhost
Server Port: 8080
Requests per second: 200 [#/sec] (mean)
Time per request: 5 ms [ms] (mean)
Transfer rate: 20 Mbps received
📌 Key Metrics:
 Requests per second – Determines max request handling capacity.
 Time per request – Lower is better.

2️ Stress Testing with Siege


Siege is useful for overloading services to check failure points.
Step 1: Install Siege
For Linux/macOS:
sudo apt install siege # Ubuntu
brew install siege # macOS

Step 2: Run a Stress Test


siege -c 100 -t 30s http://localhost:8080/
📌 Explanation:
 -c 100 → 100 concurrent users
 -t 30s → Test for 30 seconds
✅ Expected Output:
Transactions: 5000 hits
Availability: 99.9 %
Elapsed time: 30.12 secs
Response time: 0.02 secs
Transaction rate: 165 requests/sec
📌 Key Metrics:
 Transaction Rate – How fast requests are handled.
 Availability – If it drops below 99%, the server may be failing under load.

3️ Advanced Load Testing with JMeter


JMeter provides a GUI-based load & stress testing tool.
Step 1: Run JMeter in Docker
docker run -d --name jmeter -p 60000:60000 -v ~/jmeter:/tmp/apache-jmeter -it justb4/jmeter
📌 Access JMeter GUI in your browser and configure a test plan.

4️ Monitoring Performance with Prometheus & Grafana


Step 1: Run Prometheus & Grafana
If not set up, follow the guide in the previous response:
docker-compose up -d

Step 2: Install cAdvisor for Container Metrics


docker run -d --name=cadvisor -p 8081:8080 \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:ro \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
google/cadvisor
✅ Now, cAdvisor is available at http://localhost:8081.

Step 3: Configure Grafana Dashboard


 Data Source: Add Prometheus (http://prometheus:9090).
 Dashboard: Use Docker & cAdvisor Dashboard (ID: 193).
✅ Now you can visualize CPU, memory, network, and disk usage!

5️ Analyzing Bottlenecks
📌 Look for:
✅ CPU Spikes → High CPU usage means container may need more resources.
✅ High Memory Usage → Containers may be leaking memory.
✅ Slow Response Times → If response time increases under load, optimize code/config.
✅ Container Restarts → If containers restart under load, scale replicas or debug.

6️ Scaling Services Based on Load


If performance degrades under load, scale services.
Step 1: Scale Containers in Docker Compose
docker-compose up --scale test-nginx=3 -d
📌 Now, 3 Nginx containers are running behind load balancing.
E. Different type of possibilities for getting the server down and how to
troubleshoot them.
Different Types of Server Downtime & Troubleshooting in Docker

🔹 Why Do Servers Go Down?

A Docker-based server can go down due to several reasons, including:


✅ Hardware Failures (Disk, CPU, Memory)
✅ Network Issues (DNS, Firewall, Connectivity)
✅ Container Issues (Crash, Exit, High Load)
✅ Storage Issues (Full Disk, Volume Errors)
✅ Configuration Issues (Wrong Environment Variables, Incorrect Service Bindings)
✅ Security Attacks (DDoS, Unauthorized Access)

1️⃣ Checking if the Server is Down

Check Server Health

📌 Ping the server

ping <server-ip>

✅ If no response, the server might be down or network-related issues exist.

📌 Try SSH into the server

ssh user@server-ip

✅ If SSH fails, it might be a system failure or firewall issue.

2️⃣ Docker-Specific Downtime Reasons & Troubleshooting

📌 Issue 1: Docker Service is Down

If Docker itself is not running, all containers will be down.

Check if Docker is Running

systemctl status docker

✅ Solution: If Docker is stopped, restart it:

sudo systemctl restart docker

📌 Issue 2: Container Crashes or Exits Unexpectedly

Containers might stop due to code errors, memory limits, or misconfigurations.

Check Running Containers

docker ps -a
✅ If a container has exited, check logs:

docker logs <container_id>

✅ Solution: Restart the container:

docker restart <container_id>

✅ Check if a container is repeatedly crashing:

docker inspect <container_id> | grep -i "oom"

If you see "oom_killed": true, the container is running out of memory.

📌 Solution:

 Increase Memory Limits in Docker Compose:

services:

my_service:

mem_limit: 512m

 Use a lightweight base image like alpine.

📌 Issue 3: Port Conflict

A container might fail to start if the assigned port is already in use.

Check Port Usage

sudo netstat -tulnp | grep <port>

✅ Solution:

 Change the container's port mapping:

docker run -d -p 8081:80 nginx

 Stop the conflicting service:

sudo systemctl stop apache2

📌 Issue 4: Storage Issues (Full Disk or Corrupt Volumes)

If the disk is full, containers might crash or refuse to start.

Check Disk Usage

df -h

📌 If /var/lib/docker is full:

du -sh /var/lib/docker/*

✅ Solution:
 Prune Unused Resources:

docker system prune -a

 Move Docker Storage to Another Disk:

sudo nano /etc/docker/daemon.json

Add:

"data-root": "/mnt/docker-data"

Then restart Docker:

sudo systemctl restart docker

📌 Issue 5: Network Issues

If the container can't access external networks, check Docker networking.

Check Container Network

docker network ls

✅ If bridge is missing, restart Docker:

sudo systemctl restart docker

✅ If DNS inside a container fails:

docker run --rm busybox nslookup google.com

If it fails, restart the DNS resolver:

sudo systemctl restart systemd-resolved

📌 Issue 6: High CPU or Memory Usage

A container might be consuming too many resources.

Check Resource Usage

docker stats

✅ Solution:

 Limit CPU & Memory Usage

services:

my_service:

mem_limit: "512m"
cpu_shares: 512

 Scale the service:

docker-compose up --scale my_service=3 -d

📌 Issue 7: Container Cannot Access Database

If a database service is down, dependent applications might fail.

Check if Database Container is Running

docker ps | grep mysql

✅ Solution: Restart the database container:

docker restart mysql_container

✅ Check logs:

docker logs mysql_container

📌 Issue 8: Corrupted Docker Overlay Network

Sometimes, Docker networking fails due to corruption.

✅ Solution: Remove and recreate the network.

docker network rm my_network

docker network create my_network

Then restart affected services.

📌 Issue 9: Docker Swarm Node Failure

In a Swarm cluster, if a node goes down, services might fail.

Check Swarm Node Status

docker node ls

✅ If a node is down, remove it:

docker node rm <node-id>

Then add a new node:

docker swarm join --token <token> <manager-ip>:2377

📌 Issue 10: Docker Daemon Fails to Start

Check Docker Daemon Logs


sudo journalctl -u docker --no-pager | tail -50

📌 Possible Fixes:

 Restart Docker:

sudo systemctl restart docker

 If configuration is invalid, check /etc/docker/daemon.json for syntax errors.

✅ Summary of Fixes

Issue Troubleshooting Solution

Docker Down systemctl status docker Restart with systemctl restart docker

Container Crashes docker logs <container_id> Restart, fix config, increase memory

Port Conflict `netstat -tulnp grep `

Full Disk df -h docker system prune -a or move storage

Network Issue docker network ls Restart Docker or recreate network

High CPU docker stats Set CPU limits or scale services

DB Unreachable `docker ps grep mysql`

Overlay Network Corrupt docker network inspect Remove & recreate network

Swarm Node Down docker node ls Remove & rejoin node

Docker Daemon Fails journalctl -u docker Restart, check config

🚀 With these steps, you can troubleshoot and recover from most server downtime issues in
Docker!

Configuration Issues in Docker: Troubleshooting & Fixes

Configuration mistakes can cause Docker containers to fail at startup, crash unexpectedly, or behave
incorrectly. These can stem from:
✅ Incorrect environment variables
✅ Missing or incorrect volume mounts
✅ Wrong network configuration
✅ Errors in docker-compose.yml or Dockerfile
✅ Incorrect permissions

1️⃣ Checking for Configuration Issues in Containers

Step 1: Inspect Running Containers

docker ps
If your container is not running, check all containers:

docker ps -a

📌 If a container exited with an error, check logs:

docker logs <container_id>

✅ Look for errors like:

 Invalid configuration value

 Missing environment variable

 Permission denied

📌 Issue 1: Incorrect Environment Variables

Some applications fail if required environment variables are missing.

Check Environment Variables in a Running Container

docker inspect <container_id> | jq '.[0].Config.Env'

✅ Solution:

 Set missing variables when running a container:

docker run -e DB_HOST=db.example.com -e DB_USER=root myapp

 Define them in docker-compose.yml:

services:

myapp:

environment:

- DB_HOST=db.example.com

- DB_USER=root

 Check if variables are defined in .env file:

cat .env

📌 Issue 2: Incorrect Volume Mounts

Containers may fail if the mounted volume does not exist or lacks permissions.

Check Mounted Volumes

docker inspect <container_id> | jq '.[0].Mounts'

If the Source path is missing, the container might be failing.

✅ Solution:
 Verify if the host directory exists:

ls -l /data

 Ensure correct permissions:

sudo chown -R 1000:1000 /data

 Fix the docker-compose.yml volume definition:

services:

myapp:

volumes:

- /data:/app/data

 Use --mount correctly when running a container:

docker run -v /data:/app/data myapp

📌 Issue 3: Network Misconfiguration

Containers may not communicate due to incorrect network settings.

Check Container Network

docker network inspect my_network

✅ Solution:

 If network is missing, recreate it:

docker network create my_network

 Ensure correct network in docker-compose.yml:

services:

db:

networks:

- my_network

app:

networks:

- my_network

networks:

my_network:

driver: bridge

 Attach a running container to a network:


docker network connect my_network my_container

📌 Issue 4: Errors in docker-compose.yml

A broken docker-compose.yml can prevent services from starting.

Validate the Configuration

docker-compose config

✅ Solution:

 If there are syntax errors, fix them.

 Indentation errors are common (YAML is indentation-sensitive).

 Example of incorrect indentation:

services:

app:

image: myapp

ports:

- 8080:80

✅ Correct indentation:

services:

app:

image: myapp

ports:

- 8080:80

📌 Issue 5: Incorrect Dockerfile Configuration

Containers may fail to build or run due to a misconfigured Dockerfile.

Common Issues

1️⃣ Using COPY instead of ADD for extracting tar files


❌ Incorrect:

COPY myapp.tar.gz /app/

✅ Correct:

ADD myapp.tar.gz /app/

2️⃣ Forgetting WORKDIR before CMD


❌ Incorrect:
CMD ["./app"]

✅ Correct:

WORKDIR /app

CMD ["./app"]

3️⃣ Hardcoded environment variables


❌ Incorrect:

ENV DB_HOST=localhost

✅ Correct (use ARG for flexibility):

ARG DB_HOST

ENV DB_HOST=${DB_HOST}

Check Build Logs

If the build fails, check logs:

docker build -t myapp .

✅ Solution:

 Fix syntax issues in Dockerfile.

 Use docker history to check image layers.

 Clean up old images:

docker image prune -a

📌 Issue 6: Insufficient Container Permissions

If a container lacks root privileges, it may fail to access files or execute commands.

Check the Container User

docker inspect <container_id> | jq '.[0].Config.User'

✅ Solution:

 Ensure correct user in Dockerfile:

USER 1000

 Run the container as root (if needed):

docker run --user root myapp

 Grant permissions to mounted directories:

sudo chmod -R 777 /data


📌 Issue 7: Configuring Health Checks Incorrectly

If a health check fails, Docker may continuously restart the container.

Check Health Status

docker inspect --format='{{json .State.Health.Status}}' <container_id>

✅ Solution:

 Define a proper health check in Dockerfile:

HEALTHCHECK --interval=10s --timeout=3s --retries=3 CMD curl -f http://localhost:80 || exit 1

 Check if the service inside the container is running:

docker exec -it <container_id> curl localhost:80

If it's not responding, fix your application or network settings.

✅ Summary of Fixes

Issue Troubleshooting Solution

Missing Env Vars `docker inspect <container_id> jq '.[0].Config.Env'`

Wrong Volume
`docker inspect <container_id> jq '.[0].Mounts'`
Mounts

Recreate network, attach


Network Issues docker network inspect
container

YAML Errors docker-compose config Fix indentation, syntax

Use correct instructions, fix


Dockerfile Errors docker build -t myapp .
WORKDIR

Low Permissions `docker inspect <container_id> jq '.[0].Config.User'`

docker inspect --
Health Check Fix HEALTHCHECK, ensure app
format='{{json .State.Health.Status}}'
Failures is running
<container_id>

📌 With these checks, you can fix most Docker configuration issues and ensure smooth container
operation! 🚀

You might also like