Guide

A container is an ordinary Linux process that the kernel isolates. It sees its own process tree, network interfaces, root filesystem and hostname. It may use only a fixed slice of CPU and memory. It shares the host's kernel with every other container on the machine.

That one fact explains most of what containers do. They start in milliseconds, images can be 20 MB, and a kernel bug in one container can reach the host.

Containers are the unit of deployment for most production work. Kubernetes schedules them, serverless platforms run them, and your CI pipeline builds, scans and signs them. Once you know the moving parts, odd cases like exit code 137 or a process that ignores SIGTERM stop being mysteries.

The concept pages

StepConceptWhat it answers
1Containers vs virtual machinesWhy is a container lighter than a VM, and what does it give up?
2Namespaces and cgroupsHow does a process see its own world and stay within limits?
3Image layers and digestsHow is an image stored, and why does a tag not pin anything?
4Writing good DockerfilesHow do you order steps so builds are fast and images are small?
5Container securityWhat do you lock down, and why is a container not a sandbox?
6Shrinking an imageHow do you take a 1.2 GB image to under 150 MB?

Local development with Compose

Docker Compose runs several containers from one compose.yaml: your app, a database, a cache. The containers reach each other by service name on a private network.

YAML
services:
  api:
    build: .
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 2s
      retries: 15

A plain depends_on waits for the database container to start, not to accept connections, so use the healthcheck condition. Compose is for development and CI. In production the same images run on Kubernetes or a managed runtime.

Common mistakes across the topic

  • Using the shell form of CMD. The app never receives SIGTERM, so it is killed after the grace period.
  • Deploying by a mutable tag such as latest. The bytes behind the tag can change under you.
  • Putting a secret in a RUN step. Even if a later step deletes it, the earlier layer still holds it.
  • Treating the container as a sandbox for untrusted code. It is a convenience boundary, not a strong one.

Key takeaways

  • A container is a normal process, isolated by namespaces and limited by cgroups, sharing the host kernel.
  • Images are stacks of content-addressed layers. Deleting a file in a later layer does not shrink the image.
  • Order Dockerfile steps from least to most often changed, and use multi-stage builds on slim or distroless bases.
  • Deploy by digest, and harden with minimal images, a non-root user, a read-only filesystem and dropped capabilities.

Further learning

Docker: Get started covers the basic commands. The next page is containers vs virtual machines, which explains why the shared kernel matters.