Docker

Docker

Build, Ship, and Run Containers Anywhere

devopsintermediate
13M+
Developers
use Docker daily
7M+
Applications
on Docker Hub
2013
Released
by Docker Inc.
100B+
Image Pulls
from Docker Hub

What is Docker?

Docker is a containerization platform that packages applications and their dependencies into lightweight, portable containers. Unlike virtual machines, containers share the host OS kernel, making them faster to start and more resource-efficient. Docker provides tools for building images, running containers, and orchestrating multi-container applications.

Think of Docker like shipping containers for software

Before shipping containers, loading cargo was slow and error-prone - different goods needed different handling. Shipping containers standardized everything. Docker does the same for software: your app runs the same way everywhere, regardless of the underlying infrastructure.

Key Features

Lightweight Containers

Share host OS kernel. Start in seconds, not minutes like VMs.

Consistent Environments

Works on my machine = works everywhere. Dev/prod parity.

Docker Hub Registry

Pull official images for any stack. Push your own images.

Docker Compose

Define multi-container apps in YAML. One command deployment.

When to Use

  • Consistent development environments across teams
  • Microservices architecture
  • CI/CD pipelines - build once, deploy anywhere
  • Local development matching production
  • Isolating application dependencies
  • Running multiple versions of software simultaneously

When Not to Use

  • GUI applications (containers are primarily for headless apps)
  • When you need full OS isolation (use VMs instead)
  • Extremely performance-sensitive workloads (small overhead exists)
  • Persistent data storage (use volumes or external storage)
  • Windows-only applications on Linux hosts (and vice versa)

Prerequisites

  • Basic command line knowledge
  • Understanding of Linux basics (helpful)
  • Sufficient disk space for images (~20GB recommended)

Installation

linux(apt)
curl -fsSL https://get.docker.com | sh

Official install script

linux(apt)
sudo apt install docker.io

Ubuntu/Debian package

macos(brew)
brew install --cask docker

Docker Desktop

windows(winget)
winget install Docker.DockerDesktop

Docker Desktop

Verify installation: docker --version && docker run hello-world

Quick Start Steps

1

Verify installation

Run the hello-world container to verify Docker works

docker run hello-world
2

Run your first container

Start an nginx web server container

docker run -d -p 8080:80 nginx
# Visit http://localhost:8080
3

Create a Dockerfile

Build your own image from a Node.js app

4

Build and run your image

Build the image and run it as a container

docker build -t my-app .
docker run -d -p 3000:3000 my-app
docker run <image>

Create and start a container from image

docker ps

List running containers

docker ps -a

List all containers (including stopped)

docker images

List local images

docker pull <image>

Download image from registry

docker build -t <name> .

Build image from Dockerfile

docker stop <container>

Stop a running container

docker rm <container>

Remove a container

docker rmi <image>

Remove an image

docker logs <container>

View container logs

docker exec -it <container> sh

Execute command in container

docker-compose up -d

Start services defined in compose file

Commands by Category

Pro Tips14

Optimize layer caching

performance

Order Dockerfile instructions from least to most frequently changing. Put COPY package*.json and RUN npm install before COPY . . This way, dependencies are cached unless package.json changes.

Use Alpine-based images

performance

Alpine Linux images are ~5MB vs ~100MB+ for Debian-based. Use node:20-alpine, python:3.11-alpine, etc. Only use full images if you need specific libraries.

FROM node:20-alpine
FROM node:20

Run as non-root user

security

Create and use a non-root user in your Dockerfile. Running as root in containers is a security risk if the container is compromised.

One process per container

best-practice

Each container should do one thing well. Don't run multiple services in one container. Use Docker Compose for multi-service applications.

Use specific image tags

best-practice

Always specify image versions in production. :latest can change unexpectedly. Pin to specific versions like node:20.10-alpine.

FROM node:20.10-alpine
FROM node:latest

Use multi-stage builds

performance

Multi-stage builds let you use build tools without including them in the final image. Dramatically reduces image size and attack surface.

Always add health checks

best-practice

HEALTHCHECK instructions tell orchestrators if your app is actually working, not just running. Essential for production reliability.

Use ENV for runtime config, ARG for build-time

gotcha

ARG values are only available during build. ENV values persist into the running container. Use ARG for build secrets that shouldn't be in the final image.

Combine RUN commands

performance

Each RUN creates a layer. Combine related commands with && to reduce layers and image size. Clean up in the same RUN that creates files.

RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
RUN apt-get update\nRUN apt-get install -y curl\nRUN rm -rf /var/lib/apt/lists/*

Prefer COPY over ADD

best-practice

COPY is transparent and predictable. ADD has extra features (tar extraction, URL fetching) that are rarely needed and can be confusing.

Use .dockerignore

performance

A .dockerignore file speeds up builds by excluding unnecessary files (node_modules, .git, docs). Similar to .gitignore syntax.

Prune unused resources

automation

Docker accumulates unused images, containers, and volumes. Run 'docker system prune' periodically. Use '-a' flag to remove all unused images.

Use named volumes over bind mounts in production

best-practice

Named volumes are managed by Docker and portable. Bind mounts depend on host filesystem paths. Use bind mounts for development, named volumes for production.

Scan images for vulnerabilities

security

Use 'docker scout' or Trivy to scan images for known vulnerabilities. Integrate into CI/CD pipelines. Keep base images updated.

Key Facts10

Containers share the host OS kernel, VMs have their own OS

This makes containers much lighter (~MB) than VMs (~GB), and they start in seconds instead of minutes.

Docker images are built from layers that are cached and reused

Each instruction in a Dockerfile creates a layer. Layers are cached and shared between images, saving disk space and build time.

Container filesystems are ephemeral by default

Changes made inside a container are lost when it stops. Use volumes for persistent data.

Default bridge network doesn't support automatic DNS

Containers on the default bridge must use IP addresses. Create a custom network for automatic DNS resolution by container name.

The container's main process runs as PID 1

PID 1 has special responsibilities (signal handling, reaping zombies). Use exec form CMD or an init system like tini.

Containers use copy-on-write for filesystem

Containers share read-only image layers. Writes go to a thin writable layer unique to each container.

Docker sends the entire build context to the daemon

Everything in your build directory (except .dockerignore patterns) is sent to Docker. Large contexts slow builds.

-p 8080:80 means host:container

The first port is on the host, the second is inside the container. -p 8080:80 forwards host port 8080 to container port 80.

ENV variables persist in the image and all derived containers

ENV sets environment variables that exist at runtime. ARG variables only exist during build.

Containers run as root by default

This is a security risk. Always add a USER instruction to run as non-root in production.

Interview & Exam Practice4

A colleague asks why you chose Docker containers over virtual machines for your microservices deployment.

What are the key differences and when would you choose each?

Your Docker build takes 10 minutes because it reinstalls npm dependencies every time, even when only application code changes.

How would you optimize the Dockerfile?

Your team deployed a PostgreSQL database in a Docker container. After a host reboot, all data was lost.

What went wrong and how should this be fixed?

A security audit flagged several issues with your Docker deployment: containers running as root, secrets in Dockerfiles, and unpatched base images.

What's the correct approach to address all these issues?

Related Tools

kubernetesdocker-composepodmancontainerdbuildah