Learn

Navigate through learn topics

Containers & Orchestration

Understanding Docker, Kubernetes and modern containerisation technologies

Last updated: 8/15/2025

Master the art of packaging, deploying and managing applications using containers - the building blocks of modern cloud infrastructure.

What are Containers?

The Core Concept

Portable packages for applications

A container is like a shipping container for software. Just as shipping containers can be moved between trucks, ships and trains without unpacking, software containers can run on any system that supports containers.

Real-world analogy: Think of containers like food trucks. Each truck (container) has everything it needs to operate - kitchen equipment, ingredients, power supply - and can set up shop anywhere there's a parking space (host system).

Containers vs Virtual Machines

Understanding the Difference

Lightweight isolation

Traditional VMs:
┌─────────────────────────────────────┐
│          Virtual Machine 1          │
│  ┌─────────────────────────────┐   │
│  │     Guest OS (10GB+)        │   │
│  │  ┌───────────────────────┐  │   │
│  │  │    Application        │  │   │
│  │  └───────────────────────┘  │   │
│  └─────────────────────────────┘   │
└─────────────────────────────────────┘

Containers:
┌─────────────────────────────────────┐
│         Container 1 (MB)           │
│  ┌───────────────────────┐         │
│  │    Application        │         │
│  │    + Dependencies     │         │
│  └───────────────────────┘         │
│         Shared OS Kernel            │
└─────────────────────────────────────┘

Key differences:

  • Size: Containers are MBs, VMs are GBs
  • Startup: Containers start in seconds, VMs in minutes
  • Resource usage: Containers share OS kernel, VMs need full OS
  • Isolation: VMs offer stronger isolation, containers are lighter

Docker Fundamentals

Docker Architecture

The container ecosystem

Core components:

  • Docker Engine: The runtime that creates and manages containers
  • Images: Read-only templates for creating containers
  • Containers: Running instances of images
  • Registry: Storage for Docker images (like Docker Hub)

Dockerfile

The recipe for building images

# Start from a base image
FROM node:18-alpine

# Set working directory
WORKDIR /app

# Copy dependency files
COPY package*.json ./

# Install dependencies
RUN npm ci --only=production

# Copy application code
COPY . .

# Expose port
EXPOSE 3000

# Define startup command
CMD ["node", "server.js"]

Essential Docker Commands

# Build an image
docker build -t myapp:1.0 .

# Run a container
docker run -d -p 3000:3000 myapp:1.0

# List running containers
docker ps

# View logs
docker logs container_id

# Stop a container
docker stop container_id

# Remove a container
docker rm container_id

Container Images

Image Layers

Building blocks of efficiency

Docker images are built in layers, each representing a change from the previous layer. This makes images efficient and cacheable.

FROM ubuntu:22.04        # Layer 1: Base OS
RUN apt-get update      # Layer 2: Update packages
RUN apt-get install -y  # Layer 3: Install dependencies
COPY app /app          # Layer 4: Add application
CMD ["./app"]          # Layer 5: Set command

Benefits:

  • Shared layers between images save space
  • Faster builds through layer caching
  • Easy to track changes

Multi-stage Builds

Optimising image size

# Build stage
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
CMD ["node", "dist/index.js"]

Result: Smaller production images without build tools

Container Registries

Docker Hub

The default public registry

The GitHub of Docker images - store, share and discover container images.

# Push to Docker Hub
docker tag myapp:1.0 username/myapp:1.0
docker push username/myapp:1.0

# Pull from Docker Hub
docker pull nginx:latest

Private Registries

Secure image storage

Options:

  • Amazon ECR: AWS's container registry
  • Google Container Registry: GCP's offering
  • Azure Container Registry: Microsoft's solution
  • GitHub Container Registry: Integrated with GitHub
  • Self-hosted: Run your own registry

Kubernetes (K8s)

What is Kubernetes?

Container orchestration at scale

Kubernetes is like a conductor for an orchestra of containers. It manages where containers run, ensures they stay healthy and coordinates communication between them.

Core benefits:

  • Automatic scaling
  • Self-healing
  • Load balancing
  • Rolling updates
  • Secret management

Kubernetes Architecture

┌─────────────────────────────────────────┐
│            Control Plane                │
│  ┌──────────┐  ┌──────────┐            │
│  │   API    │  │Scheduler │            │
│  │  Server  │  │          │            │
│  └──────────┘  └──────────┘            │
│  ┌──────────┐  ┌──────────┐            │
│  │Controller│  │   etcd   │            │
│  │ Manager  │  │(Database)│            │
│  └──────────┘  └──────────┘            │
└─────────────────────────────────────────┘
                    │
┌─────────────────────────────────────────┐
│              Worker Nodes               │
│  ┌─────────────────────────────┐       │
│  │     Node 1                  │       │
│  │  ┌──────┐  ┌──────┐        │       │
│  │  │ Pod  │  │ Pod  │        │       │
│  │  └──────┘  └──────┘        │       │
│  └─────────────────────────────┘       │
└─────────────────────────────────────────┘

Key Kubernetes Concepts

Pods

The smallest deployable unit

A Pod wraps one or more containers that share storage and network.

apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: myapp
    image: myapp:1.0
    ports:
    - containerPort: 3000

Deployments

Managing replica sets

Deployments ensure a specified number of pod replicas are running.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
        ports:
        - containerPort: 3000

Services

Networking and load balancing

Services provide stable network endpoints for pods.

apiVersion: v1
kind: Service
metadata:
  name: myapp-service
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 3000
  type: LoadBalancer

Container Orchestration Platforms

Managed Kubernetes

Amazon EKS (Elastic Kubernetes Service)

  • Fully managed control plane
  • Deep AWS integration
  • Auto-scaling with Fargate

Google GKE (Google Kubernetes Engine)

  • Autopilot mode for hands-off management
  • Best-in-class Kubernetes experience
  • Integrated with Google Cloud services

Azure AKS (Azure Kubernetes Service)

  • Integrated with Azure Active Directory
  • Azure Policy for governance
  • Dev Spaces for development

Simpler Alternatives

Amazon ECS (Elastic Container Service)

  • AWS-native orchestration
  • Simpler than Kubernetes
  • Tight AWS integration

Docker Swarm

  • Built into Docker
  • Easier learning curve
  • Good for smaller deployments

Nomad

  • Lightweight and flexible
  • Supports non-container workloads
  • Simple architecture

Container Networking

Network Types

Bridge Network

  • Default network for containers
  • Containers can communicate on same host

Host Network

  • Container uses host's network directly
  • Better performance, less isolation

Overlay Network

  • Spans multiple Docker hosts
  • Used in Swarm and Kubernetes

Service Mesh

Advanced networking for microservices

Service meshes like Istio or Linkerd provide:

  • Traffic management
  • Security (mTLS)
  • Observability
  • Policy enforcement

Container Storage

Volume Types

Ephemeral Storage

  • Deleted when container stops
  • Good for temporary data

Persistent Volumes

  • Survives container restarts
  • Essential for databases
# Kubernetes Persistent Volume Claim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: database-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

Storage Solutions

  • CSI (Container Storage Interface): Standard for storage plugins
  • Rook: Cloud-native storage for Kubernetes
  • Longhorn: Distributed block storage
  • GlusterFS: Distributed file system

Security Best Practices

Image Security

Scan for vulnerabilities:

# Using Trivy
trivy image myapp:1.0

# Using Snyk
snyk container test myapp:1.0

Use minimal base images:

# Good: Alpine-based
FROM node:18-alpine

# Better: Distroless
FROM gcr.io/distroless/nodejs18

Runtime Security

Run as non-root:

USER node

Read-only filesystem:

securityContext:
  readOnlyRootFilesystem: true

Network policies:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: api-netpol
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend

Monitoring and Logging

Container Metrics

Prometheus + Grafana

  • Industry standard for metrics
  • Beautiful dashboards
  • Alerting capabilities

Key metrics to monitor:

  • CPU and memory usage
  • Network I/O
  • Disk usage
  • Application-specific metrics

Centralised Logging

ELK Stack (Elasticsearch, Logstash, Kibana)

  • Powerful log aggregation
  • Full-text search
  • Visualisation

Fluentd/Fluent Bit

  • Lightweight log forwarding
  • Multiple output plugins
  • Kubernetes-native

CI/CD with Containers

Build Pipeline

# GitHub Actions example
name: Build and Deploy
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    
    - name: Build Docker image
      run: docker build -t myapp:${{ github.sha }} .
    
    - name: Push to registry
      run: |
        docker tag myapp:${{ github.sha }} myregistry/myapp:latest
        docker push myregistry/myapp:latest
    
    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/myapp myapp=myregistry/myapp:latest

GitOps

ArgoCD or Flux

  • Declarative deployments
  • Git as source of truth
  • Automatic synchronisation

Development Workflow

Local Development

Docker Compose

version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
    environment:
      - NODE_ENV=development
  
  db:
    image: postgres:14
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Dev Tools

Skaffold

  • Continuous development for Kubernetes
  • Hot reload for containers

Tilt

  • Smart rebuilds and live updates
  • Great developer experience

Telepresence

  • Develop locally, test in cluster
  • Route cluster traffic to local machine

Common Patterns

Sidecar Pattern

Helper containers

spec:
  containers:
  - name: app
    image: myapp:1.0
  - name: logging-agent
    image: fluentd:latest

Init Containers

Setup before main container

spec:
  initContainers:
  - name: migration
    image: myapp:1.0
    command: ['npm', 'run', 'migrate']
  containers:
  - name: app
    image: myapp:1.0

Ambassador Pattern

Proxy for external services

Used for service discovery, load balancing and circuit breaking.

Troubleshooting

Common Issues

Container won't start:

# Check logs
docker logs container_id

# Inspect container
docker inspect container_id

# Debug interactively
docker run -it myapp:1.0 /bin/sh

Kubernetes pod issues:

# Describe pod
kubectl describe pod pod-name

# Get logs
kubectl logs pod-name

# Execute commands in pod
kubectl exec -it pod-name -- /bin/sh

Cost Optimisation

Right-sizing

  • Monitor actual resource usage
  • Set appropriate resource requests/limits
  • Use horizontal pod autoscaling

Spot Instances

  • Use spot/preemptible instances for non-critical workloads
  • Implement graceful shutdown handling

Image Optimisation

  • Use multi-stage builds
  • Choose minimal base images
  • Remove unnecessary files

Getting Started

Your First Container

Step 1: Install Docker

# macOS/Windows: Download Docker Desktop
# Linux: Install Docker Engine

Step 2: Create a simple app

// app.js
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello from Container!');
});

app.listen(3000, () => {
  console.log('Server running on port 3000');
});

Step 3: Create Dockerfile

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["node", "app.js"]

Step 4: Build and run

docker build -t myapp .
docker run -p 3000:3000 myapp

Summary

Containers have revolutionised how we build, ship and run applications. They provide consistency across environments, enable microservices architectures and form the foundation of modern cloud-native applications.

Key takeaways:

  • Containers package applications with dependencies
  • Docker makes container creation and management simple
  • Kubernetes orchestrates containers at scale
  • Proper security and monitoring are essential
  • Start simple, grow as needed

The container ecosystem continues to evolve, making it easier to build scalable, resilient applications that run anywhere!