MFormations
Modern DevOps Engineering

Chapitre 2

02 — Containers & Docker

02 — Containers & Docker

Course: Containers & Docker

1. Container Fundamentals

1.1 What Are Containers?

Containers are lightweight, portable, isolated environments for running applications. They share the host OS kernel but have isolated filesystems, processes, and network stacks.

Containers vs VMs:

AspectContainerVM
KernelShares host kernelFull OS kernel
IsolationNamespaces + cgroupsHypervisor-level
StartupMillisecondsSeconds to minutes
SizeMBsGBs
DensityHighLower

1.2 OCI Standards

The Open Container Initiative (OCI) defines:

  • Image Spec: Standard format for container images
  • Runtime Spec: Standard behavior for container runtimes

OCI-compliant runtimes:

  • runc (default Docker runtime)
  • containerd (high-level container manager)
  • crun (faster, written in C)
  • Kata Containers (VM-level isolation via OCI)

2. Docker Images

2.1 Multi-Stage Builds

Multi-stage builds optimize image size by separating build and runtime environments.

# Build stage
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server .

# Runtime stage
FROM alpine:3.19
RUN apk add --no-cache ca-certificates tzdata
COPY --from=builder /app/server /server
EXPOSE 8080
USER nobody
ENTRYPOINT ["/server"]

2.2 Slim Images

Base ImageSizeUse Case
alpine~5MBMinimal, musl libc
distroless~10MBGoogle's minimal, no package manager
scratch0MBFully static binaries
ubuntu:22.04~77MBFull distro, compatibility
debian:slim~80MBBalanced

2.3 Dockerfile Best Practices

# 1. Use specific tags (not latest)
FROM node:20-alpine

# 2. Set working directory
WORKDIR /app

# 3. Copy package files first (leverage cache)
COPY package*.json ./
RUN npm ci --only=production

# 4. Copy rest of application
COPY . .

# 5. Use non-root user
USER node

# 6. Metadata
LABEL org.opencontainers.image.source="https://github.com/org/app"
LABEL org.opencontainers.image.description="Production app"

# 7. Healthcheck
HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1

EXPOSE 8080
CMD ["node", "server.js"]

Best practices checklist:

  • Pin base image versions
  • Minimize layers (combine RUN commands)
  • Use .dockerignore
  • Use COPY instead of ADD (unless extracting tar)
  • Set --no-cache for apt/apk
  • Drop capabilities in runtime
  • Scan images with docker scout

3. Docker Networking

3.1 Network Drivers

DriverIsolationUse Case
bridgePer-hostDefault, single-host containers
overlayMulti-hostSwarm services, multi-node
macvlanDirect MACLegacy apps needing physical IP
hostNoneMaximum performance, no isolation
noneFullFull isolation, manual config

3.2 Bridge Network

# Create custom bridge
docker network create --driver bridge --subnet 172.20.0.0/16 mynet

# Run containers on custom network
docker run --network mynet --name web nginx
docker run --network mynet --name api myapp

# DNS resolution by container name
ping api  # Works automatically

3.3 Overlay Network (Swarm)

# Create overlay network
docker network create --driver overlay --attachable my-overlay

# Services on overlay
docker service create --name web --network my-overlay nginx

4. Storage

4.1 Volume Types

TypePersistenceUse Case
Named volumePersistent (managed by Docker)Database data, config
Bind mountPersistent (host path)Development, config files
tmpfsIn-memorySecrets, temporary data
# Named volume
docker volume create mydata
docker run -v mydata:/data myapp

# Bind mount
docker run -v /host/path:/container/path myapp

# tmpfs
docker run --tmpfs /tmp:noexec,nosuid,size=64m myapp

5. Registries

5.1 Major Registries

RegistryProviderFeatures
Docker HubDocker IncPublic/private, automated builds
Amazon ECRAWSIAM integration, lifecycle policies
Google GCR/GARGCPVulnerability scanning, IAM
Azure ACRAzureAD auth, geo-replication
HarborCNCFOpen-source, vulnerability scanning, replication

5.2 Authentication

# Docker Hub
docker login

# ECR
aws ecr get-login-password --region us-east-1 | \
  docker login --username AWS --password-stdin <account>.dkr.ecr.us-east-1.amazonaws.com

# GCR
gcloud auth configure-docker

# ACR
az acr login --name myregistry

6. Docker Compose

6.1 Compose File Example

version: "3.9"

services:
  web:
    build:
      context: ./web
      dockerfile: Dockerfile.prod
    ports:
      - "80:8080"
    environment:
      - NODE_ENV=production
      - DB_HOST=db
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: "256M"

  api:
    image: myapi:latest
    expose:
      - "3000"
    environment:
      - REDIS_HOST=redis
    secrets:
      - api_key

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]

  redis:
    image: redis:7-alpine
    volumes:
      - redis-data:/data

volumes:
  pgdata:
  redis-data:

secrets:
  api_key:
    file: ./secrets/api_key.txt
  db_password:
    environment: DB_PASSWORD

7. Docker Security

7.1 Rootless Mode

Running Docker daemon without root privileges:

# Install rootless Docker
dockerd-rootless-setuptool.sh install

# Run container rootless
docker run --rm hello-world
export DOCKER_HOST=unix:///run/user/$UID/docker.sock

7.2 Dropping Capabilities

# Drop all capabilities, add only needed ones
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE myapp

# Privileged mode (avoid in production)
docker run --privileged myapp  # ❌

7.3 Seccomp

# Default Docker seccomp profile
docker run --security-opt seccomp=/path/to/custom.json myapp

# Disable seccomp (not recommended)
docker run --security-opt seccomp=unconfined myapp

7.4 AppArmor

# Load a profile
apparmor_parser -r -W /etc/apparmor.d/docker-myapp

# Use with container
docker run --security-opt apparmor=docker-myapp myapp

7.5 Image Scanning

# Trivy
trivy image myapp:latest

# Docker Scout
docker scout quickview myapp:latest
docker scout recommendations myapp:latest

# Snyk
snyk container test myapp:latest

8. Containerd & Nerdctl

8.1 Containerd

containerd is an industry-standard container runtime that manages the complete container lifecycle:

# Namespaces
ctr namespace ls

# Images
ctr images pull docker.io/library/nginx:alpine
ctr images ls

# Run container
ctr run --rm docker.io/library/nginx:alpine nginx

# Task management
ctr task ls

8.2 Nerdctl

nerdctl is a Docker-compatible CLI for containerd:

# Equivalent to docker commands
nerdctl run -d --name web -p 80:80 nginx:alpine
nerdctl compose up -d
nerdctl build -t myapp .
nerdctl pull --platform linux/amd64 myapp
nerdctl network create mynet
nerdctl volume create myvol

8.3 containerd vs dockerd

Featuredockerdcontainerd
Full Docker APIYesNo (CRI)
Image buildBuilt-inVia buildkit
ComposeNativeVia nerdctl
Swarm modeBuilt-inNot supported
Resource usageHigherLower
Used by KubernetesVia dockershim (deprecated)Native CRI

Summary

Docker revolutionized containerization by making it accessible. Modern container workflows use multi-stage builds for small images, Docker Compose for local development, and containerd/nerdctl for lightweight production runtimes. Security is paramount — rootless mode, dropped capabilities, seccomp, AppArmor, and regular image scanning are essential practices.